声明一个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); }
有几件事要指出。
首先,你不能像在这里一样分配一个数组对象:
char A[WIDTH][HEIGHT]; A=rand_grid(WIDTH,HEIGHT);
数组types的对象是不可修改的。
其次,C中的函数不能返回数组types。 但是他们可以返回指向数组的指针 :
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必须是一个编译时常量的整型expression式(macros,数字文字或者由macros和/或数字文字组成的算术expression式)。 我不确定这是否也适用于C99。
根据你发布的代码片段,你想要做的是获得一个你已经分配的数组并初始化它的内容。 请记住,在大多数情况下,数组types的expression式将隐式转换为指向基本types的指针。 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,这就限制了函数的用处。 你想要的是一个可以处理任意大小的二维数组的函数。 我所知道的最好的方法是,不是传递指向数组的指针,而是传递数组[1]中第一个元素的地址,并将行数和列数作为单独的parameter passing:
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); ... }
- 即使expression式
&A[0][0]
和A
产生相同的值(A的基地址),两个expression式的types也是不同的。 第一个expression式的计算结果为char(char *
)的简单指针,第二个expression式的计算结果为char(char (*)[HEIGHT]
)的char (*)[HEIGHT]
数组的指针。
你不能。 你可以传递指向数组的指针作为参数,并对函数进行修改,或者函数本身可以分配数据并返回指针。
在你的情况
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
,但当然没有一个在他们正确的思想的程序员会这样做。
你永远不能返回一个基本(值)types以外的其他东西的堆栈分配(“ auto
”)variables,以及这样的struct
。 对于其他types,您需要使用malloc()
从堆中分配内存,或者将(固定大小)数组包装到struct
。
如果您使用的是固定大小的数组,则可以将其build模为一个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);
由于前一种结构返回的情况可以被编译器重写为后者。 这被称为返回值优化 。
如果你真的想这样做,你可以尝试使数组A的静态,这样A的存储不是由函数的作用域决定的,你实际上可以返回数组(当然是指针的forms)。
但是,这不是一个很好的方法来完成你想要实现的,而是传递数组到rand_grid
函数。 那是通过地址的意思。
我知道从函数返回一个数组的所有方法都有弱点和长处。
包装在一个架构避免了分配和释放内存的开销,以及避免记住自由。 在使用malloc,calloc和realloc的任何解决scheme上都有这些问题。 另一方面,包装在一个结构中需要知道数组的最大可能的大小,并且对于大型数组来说肯定是浪费了存储器和执行时间(例如,将文件加载到内存中并将文件内容从函数传递到函数通过复制)。