声明一个C函数返回一个数组

我如何制作一个返回数组的函数? 我试过了

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);
}
Jaska asked 2020-06-27T16:37:07Z
5个解决方案
79 votes

有几点要指出。

首先,您不能像在这里那样分配数组对象:

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

数组类型的对象不可修改。

其次,C语言中的函数无法返回数组类型。 但是,它们可以返回指向数组的指针:

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;
}

语法有点混乱; 它读为

       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

对于C89,以上代码段中的HEIGHT必须是编译时常量整数表达式(宏,数字文字或由宏和/或数字文字组成的算术表达式)。 我不确定C99是否也适用。

根据您发布的代码片段,您要做的是获取一个已经分配的数组并初始化其内容。 请记住,在大多数情况下,数组类型的表达式将隐式转换为指向基本类型的指针。 IOW,如果将T的N个元素数组传递给函数,则函数实际接收的是指向T的指针:

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

对于二维数组,这有点难看:

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

这也依赖于在编译时已知M,这限制了函数的用途。 您想要的是一个可以处理任意大小的二维数组的函数。 我所知道的最好的方法是,不要将指针传递给数组,而是传递array [1]中第一个元素的地址,并将行数和列数作为单独的参数传递:

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

因此,您的rand_grid函数将如下所示:

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. 即使表达式&A[0][0]A产生相同的值(A的基地址),两个表达式的类型也不同。 第一个表达式的结果为指向char的简单指针(char *),第二个表达式的结果为指向char的二维数组的指针(char (*)[HEIGHT])。
John Bode answered 2020-06-27T16:38:07Z
15 votes

你不能 您可以将指针传递给数组作为参数并让函数对其进行修改,或者函数本身可以分配数据并返回指针。

在你的情况下

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);
}

编辑:正如caf所指出的,实际上可以返回带有数组的struct,但是当然,在他们的右脑中没有c程序员会这样做。

Michael Krelin - hacker answered 2020-06-27T16:38:37Z
11 votes

您不能返回除原始(值)类型之外的其他类型的堆栈分配变量(“ struct”),以及此类变量的structs。 对于其他类型,您需要使用malloc()从堆中分配内存,或将(固定大小的)数组包装到struct中。

如果您使用固定大小的数组,则可以将其建模为struct并使用struct-return:

#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;
}

这样做很好,并且不应比使用显式指针的替代方法花费更多:

void board_init(Board *b);

由于前者struct-return的情况可以(由编译器)重写为后者。 这称为返回值优化。

unwind answered 2020-06-27T16:39:11Z
1 votes

如果您确实想这样做,可以尝试使数组A静态化,这样,A的存储空间就不受函数范围的限制,您实际上可以返回数组(当然以指针的形式)。

但这不是完成您要实现的目标的好方法,而是将数组传递给函数rand_grid。 那就是地址传递的目的。

sud03r answered 2020-06-27T16:39:36Z
0 votes

我知道从函数返回数组的所有方法都有缺点和优点。

在结构中进行包装避免了分配和释放内存的开销,并且避免了记住释放。 使用malloc,calloc和realloc的任何解决方案都存在这些问题。 另一方面,包装在结构中需要知道最大可能的数组大小,并且肯定会浪费内存和大型数组的执行时间(例如,将文件加载到内存中以及将文件内容从一个函数传递到另一个函数 通过复制)。

Indinfer answered 2020-06-27T16:40:02Z
translate from https://stackoverflow.com:/questions/1453410/declaring-a-c-function-to-return-an-array