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

时间:2022-03-09 17:27:10

How can I make a function which returns an array? I tried this

如何创建返回数组的函数?我试着这

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

5 个解决方案

#1


79  

Several things to point out.

有几点需要指出。

First of all, you cannot assign an array object as you do here:

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

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

Objects of array type are not modifiable.

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

Secondly, functions in C cannot return array types. They can return pointers to arrays, though:

其次,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;
}

The syntax is a little confusing; it reads as

语法有点混乱;它读取

       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

For C89, HEIGHT in the above snippet must be a compile-time constant integral expression (either a macro, a numeric literal, or an arithmetic expression consisting of macros and/or numeric literals). I'm not sure if that's also true for C99.

对于C89,上面代码片段中的高度必须是编译时常量整型表达式(可以是宏、数值文字,也可以是由宏和/或数值文字组成的算术表达式)。我不确定C99是否也是这样。

Based on the snippet you've posted, what you want to do is to take an array you've already allocated and initialize its contents. Remember that in most contexts, an expression of an array type will implicitly be converted to a pointer to the base type. IOW, if you pass an N-element array of T to a function, what the function actually receives is a pointer to T:

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

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

For 2-d arrays, it's a little uglier:

对于二维数组,它有点丑:

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

This also relies on M being known at compile time, which limits the function's usefulness. What you'd like is a function that can deal with a 2-d array of arbitrary size. The best way I know of to accomplish this is instead of passing a pointer to the array, pass the address of the first element in the array[1], and pass the number of rows and columns as separate parameters:

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

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

So your rand_grid function would look something like this:

你的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. Even though the expressions &A[0][0] and A yield the same value (the base address of A), the types of the two expressions are different. The first expression evaluates to a simple pointer to char (char *), while the second evaluates to a pointer to a 2-d array of char (char (*)[HEIGHT]).
  2. 即使表达式&A[0][0]和A产生相同的值(A的基本地址),两个表达式的类型是不同的。第一个表达式计算为指向char (char *)的简单指针,而第二个表达式计算为指向char (char (*)[HEIGHT]的二维数组的指针。

#2


15  

You can't. You can either pass pointer to array as a parameter and have function modify it, or the function itself can allocate data and return pointer.

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

in your case

在你的情况中

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: As caf pointed out one can actually return the struct with an array in it, but of course no c-programmer in their right mind would do that.

编辑:正如caf指出的那样,一个人实际上可以返回带有数组的结构体,但在他们的头脑中当然没有一个c程序员会这么做。

#3


11  

You can never return a stack-allocated ("auto") variable of something other than a primitive (value) type, and structs of such. For other types, you need to allocate the memory from the heap, using malloc(), or wrap the (fixed-size) array into a struct.

除了原语(值)类型和此类类型的结构之外,您永远不能返回堆栈分配(“auto”)变量。对于其他类型,您需要使用malloc()从堆中分配内存,或者将(固定大小)数组包装到结构体中。

If you're using a fixed-size array, you can model it as a struct and use struct-return:

如果使用固定大小的数组,可以将其建模为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;
}

This is fine, and should not be more costly than the alternative, of using an explicit pointer:

使用显式指针是可以的,而且不应该比使用显式指针更昂贵:

void board_init(Board *b);

Since the former case of struct-return can be rewritten (by the compiler) to the latter. This is called return value optimization.

由于结构返回的前一种情况可以(由编译器)重写到后者。这称为返回值优化。

#4


1  

If you really want to do that you can try making the array A static, this way the storage for A is not determined by the scope of function and you can actually return the array(in form of pointer of course).

如果你真的想这样做,你可以试着让数组变成静态的,这样,A的存储不是由函数的作用域决定的,你可以返回数组(当然是指针的形式)。

But this is not a good way to do accomplish what you are trying to achieve, instead pass the array to function rand_grid . Thats what pass by address is meant for.

但是,这并不是实现目标的好方法,而是将数组传递给函数rand_grid。这就是“按地址传递”的含义。

#5


0  

All methods of which I am aware to return an array from a function have weaknesses and strengths.

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

Wrapping in a struc avoids the overhead of allocating and freeing memory, as well as avoids remembering to free. You have those problems on any solution that uses malloc, calloc, and realloc. On the other hand, wrapping in a struct requires knowing the maximum possible size of the array, and is decidedly wasteful of memory and execution time for large arrays (for example, loading a file into memory and passing the file contents around from function to function by copying).

在struc中进行包装,避免了分配和释放内存的开销,同时避免了对空闲内存的记忆。在使用malloc、calloc和realloc的任何解决方案上都存在这些问题。另一方面,封装结构需要知道数组的最大可能大小,对于大型数组来说,这无疑是浪费内存和执行时间(例如,将文件加载到内存中,并通过复制将文件内容从函数传递到函数)。

#1


79  

Several things to point out.

有几点需要指出。

First of all, you cannot assign an array object as you do here:

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

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

Objects of array type are not modifiable.

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

Secondly, functions in C cannot return array types. They can return pointers to arrays, though:

其次,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;
}

The syntax is a little confusing; it reads as

语法有点混乱;它读取

       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

For C89, HEIGHT in the above snippet must be a compile-time constant integral expression (either a macro, a numeric literal, or an arithmetic expression consisting of macros and/or numeric literals). I'm not sure if that's also true for C99.

对于C89,上面代码片段中的高度必须是编译时常量整型表达式(可以是宏、数值文字,也可以是由宏和/或数值文字组成的算术表达式)。我不确定C99是否也是这样。

Based on the snippet you've posted, what you want to do is to take an array you've already allocated and initialize its contents. Remember that in most contexts, an expression of an array type will implicitly be converted to a pointer to the base type. IOW, if you pass an N-element array of T to a function, what the function actually receives is a pointer to T:

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

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

For 2-d arrays, it's a little uglier:

对于二维数组,它有点丑:

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

This also relies on M being known at compile time, which limits the function's usefulness. What you'd like is a function that can deal with a 2-d array of arbitrary size. The best way I know of to accomplish this is instead of passing a pointer to the array, pass the address of the first element in the array[1], and pass the number of rows and columns as separate parameters:

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

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

So your rand_grid function would look something like this:

你的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. Even though the expressions &A[0][0] and A yield the same value (the base address of A), the types of the two expressions are different. The first expression evaluates to a simple pointer to char (char *), while the second evaluates to a pointer to a 2-d array of char (char (*)[HEIGHT]).
  2. 即使表达式&A[0][0]和A产生相同的值(A的基本地址),两个表达式的类型是不同的。第一个表达式计算为指向char (char *)的简单指针,而第二个表达式计算为指向char (char (*)[HEIGHT]的二维数组的指针。

#2


15  

You can't. You can either pass pointer to array as a parameter and have function modify it, or the function itself can allocate data and return pointer.

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

in your case

在你的情况中

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: As caf pointed out one can actually return the struct with an array in it, but of course no c-programmer in their right mind would do that.

编辑:正如caf指出的那样,一个人实际上可以返回带有数组的结构体,但在他们的头脑中当然没有一个c程序员会这么做。

#3


11  

You can never return a stack-allocated ("auto") variable of something other than a primitive (value) type, and structs of such. For other types, you need to allocate the memory from the heap, using malloc(), or wrap the (fixed-size) array into a struct.

除了原语(值)类型和此类类型的结构之外,您永远不能返回堆栈分配(“auto”)变量。对于其他类型,您需要使用malloc()从堆中分配内存,或者将(固定大小)数组包装到结构体中。

If you're using a fixed-size array, you can model it as a struct and use struct-return:

如果使用固定大小的数组,可以将其建模为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;
}

This is fine, and should not be more costly than the alternative, of using an explicit pointer:

使用显式指针是可以的,而且不应该比使用显式指针更昂贵:

void board_init(Board *b);

Since the former case of struct-return can be rewritten (by the compiler) to the latter. This is called return value optimization.

由于结构返回的前一种情况可以(由编译器)重写到后者。这称为返回值优化。

#4


1  

If you really want to do that you can try making the array A static, this way the storage for A is not determined by the scope of function and you can actually return the array(in form of pointer of course).

如果你真的想这样做,你可以试着让数组变成静态的,这样,A的存储不是由函数的作用域决定的,你可以返回数组(当然是指针的形式)。

But this is not a good way to do accomplish what you are trying to achieve, instead pass the array to function rand_grid . Thats what pass by address is meant for.

但是,这并不是实现目标的好方法,而是将数组传递给函数rand_grid。这就是“按地址传递”的含义。

#5


0  

All methods of which I am aware to return an array from a function have weaknesses and strengths.

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

Wrapping in a struc avoids the overhead of allocating and freeing memory, as well as avoids remembering to free. You have those problems on any solution that uses malloc, calloc, and realloc. On the other hand, wrapping in a struct requires knowing the maximum possible size of the array, and is decidedly wasteful of memory and execution time for large arrays (for example, loading a file into memory and passing the file contents around from function to function by copying).

在struc中进行包装,避免了分配和释放内存的开销,同时避免了对空闲内存的记忆。在使用malloc、calloc和realloc的任何解决方案上都存在这些问题。另一方面,封装结构需要知道数组的最大可能大小,对于大型数组来说,这无疑是浪费内存和执行时间(例如,将文件加载到内存中,并通过复制将文件内容从函数传递到函数)。