47 votos

Declarar una función en C para devolver una matriz

¿Cómo puedo hacer una función que devuelve un array? He intentado esto

const int WIDTH=11;
const int HEIGHT=11;

int main() {
  char A[WIDTH][HEIGHT];
  A=rand_grid(WIDTH,HEIGHT);
  return 0;
}

// Initializes a random board.
char[][] rand_grid(int i, int k) {
  char* A[i][k];
  for(j=0;j<i;++j) {
    for(l=0;l<k;++l) {
      A[j][l]=ran(10);
    }
  }
  return A;
}

// Returns a random number from the set {0,...,9}.
int ran(int i) {
  srand((unsigned int) time(0));
  return(rand()%10);
}

78voto

John Bode Puntos 33046

Varias cosas a destacar.

Primero de todo, no se puede asignar un objeto de matriz de como hacerlo aquí:

char A[WIDTH][HEIGHT];  
A=rand_grid(WIDTH,HEIGHT);

Los objetos de tipo de matriz no son modificables.

En segundo lugar, las funciones en C no se puede volver tipos de matriz. Pueden volver punteros a arrays, a pesar de que:

char (*foo(int width))[HEIGHT]
{
  /**
   * dynamically allocate memory for a widthxHEIGHT array of char
   */
  char (*newArr)[HEIGHT] = malloc(sizeof *newArr * width);
  /**
   * initialize array contents here
   */
  return newArr;
}

La sintaxis es un poco confuso; se lee como

       foo                                   -- foo
       foo(int width)                        -- is a function
                                             -- taking an int parameter
      *foo(int width)                        -- returning a pointer
     (*foo(int width))[HEIGHT]               -- to a HEIGHT-element array
char (*foo(int width))[HEIGHT]               -- of char

Para C89, ALTURA en el fragmento anterior debe ser una constante en tiempo de compilación integral de la expresión (una macro, un literal numérico, o una expresión aritmética que consiste en macros y/o literales numéricos). No estoy seguro de si eso es cierto también para C99.

Basado en el fragmento de código que has publicado, lo que quieres hacer es tomar una matriz ya has asignado e inicializar sus contenidos. Recuerde que en la mayoría de los contextos, una expresión de un tipo de matriz implícitamente se convierte en un puntero al tipo base. IOW, si pasa un N-elemento de la matriz de T a una función, lo que la función recibe realmente es un puntero a T:

void foo (T *p) {...}
...
T arr[N];
foo(arr);

Para matrices 2-d, es un poco más fea:

void foo (T (*p)[M]) {...}
...
T arr[N][M];
foo(arr);

Esto también se basa en los M ser conocido en tiempo de compilación, lo que limita la función de utilidad. Lo que desea es una función que se puede tratar con una 2-d de la matriz de tamaño arbitrario. La mejor manera que conozco para lograr esto es en lugar de pasar un puntero a la matriz, pase a la dirección del primer elemento de la matriz[1], y de paso el número de filas y columnas como parámetros independientes:

void foo(T *base, size_t rows, size_t cols) {...}
...
T arr[N][M];
foo (&arr[0][0], N, M);

Por lo que su rand_grid función sería algo como esto:

void rand_grid(char *base, size_t rows, size_t cols)
{
  size_t i, j;
  for (i = 0; i < rows; i++)
  {
    for (j = 0; j < cols; j++)
    {
      /**
       * Since base is a simple char *, we must index it
       * as though it points to a 1-d array.  This works if
       * base points to the first element of a 2-d array,
       * since multi-dimensional arrays are contiguous.  
       */
      base[i*cols+j] = initial_value();
    }
  }
}

int main(void)
{
  char A[WIDTH][HEIGHT];
  rand_grid(&A[0][0], WIDTH, HEIGHT);
  ...
}


  1. Aunque las expresiones &A[0][0] y A de rendimiento con el mismo valor (la dirección base de Una), los tipos de las dos expresiones son diferentes. La primera expresión se evalúa a un simple puntero a char (char *), mientras que el segundo evalúa a un puntero a un 2-d de la matriz de char (char (*)[HEIGHT]).

15voto

Usted no puede. Se puede pasar puntero a un array como parámetro, y tienen la función de modificar, o a la propia función se puede asignar a los datos y devolver un puntero.

en su caso

void rand_grid(char A[WIDTH][HEIGHT]) {
    A[0][0] = 'A'; // or whatever you intend to do
}

main() {
    char A[WIDTH][HEIGHT];
    rand_grid(A);
}

Edit: Como caf señaló que realmente se puede devolver el struct con una matriz en ella, pero, por supuesto, no c-programador en su sano juicio haría eso.

11voto

unwind Puntos 181987

Nunca se puede volver un asignado en la pila ("auto") variable de algo distinto de una primitiva (valor) tipo y structs de tales. Para los otros tipos, necesita asignar la memoria del montón, usando malloc(), o envuelva la (tamaño fijo) de la matriz en un struct.

Si usted está utilizando una matriz de tamaño fijo, se puede modelar como un struct y el uso struct-regreso:

#define WIDTH  11
#define HEIGHT 11

typedef struct {
  unsigned char cell[WIDTH * HEIGHT];
} Board;

Board board_new(void)
{
  Board b;
  size_t i;

  for(i = 0; i < sizeof b.cell / sizeof *b.cell; i++)
    b.cell[i] = rand() & 255;
  return b;
}

Esto está muy bien, y no debe ser más costosa que la alternativa de utilizar una explícita puntero:

void board_init(Board *b);

Desde el primer caso de la estructura de retorno puede ser reescrito (por el compilador) a la segunda. Esto se llama valor de retorno de la optimización.

1voto

sud03r Puntos 6093

Si usted realmente quiere hacer que usted puede intentar hacer la matriz estática, de esta manera el almacenamiento no está determinado por el alcance de la función y en realidad se puede devolver la matriz(en forma de puntero de curso).

Pero esto no es una buena manera de hacer lo que usted está tratando de lograr, en lugar de pasar el array a la función rand_grid . Eso es lo que pasa por la dirección que está destinado.

Iteramos.com

Iteramos es una comunidad de desarrolladores que busca expandir el conocimiento de la programación mas allá del inglés.
Tenemos una gran cantidad de contenido, y también puedes hacer tus propias preguntas o resolver las de los demás.

Powered by:

X