如何创建一个返回数组的函数?我试过这个
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);
}
答案 0 :(得分:79)
需要指出几点。
首先,您无法像在此处一样分配数组对象:
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,如果你将一个N元素数组T传递给一个函数,那么函数实际接收的是一个指向T的指针:
void foo (T *p) {...}
...
T arr[N];
foo(arr);
对于二维阵列,它有点丑陋:
void foo (T (*p)[M]) {...}
...
T arr[N][M];
foo(arr);
这也依赖于M在编译时已知,这限制了函数的有用性。你想要的是一个可以处理任意大小的二维数组的函数。我知道要做到这一点的最好方法是将指针传递给数组,传递数组[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);
...
}
&A[0][0]
和A
产生相同的值(A的基址),两个表达式的类型也不同。第一个表达式求值为一个指向char(char *
)的简单指针,而第二个表达式求值为指向二维char(char (*)[HEIGHT]
)数组的指针。 答案 1 :(得分:15)
你做不到。您可以将指针作为参数传递给数组,并让函数对其进行修改,或者函数本身可以分配数据并返回指针。
在你的情况下
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
,但当然没有正确思维的程序员会这样做。
答案 2 :(得分:11)
您永远不能返回堆栈分配(“auto
”)变量,而不是基本(值)类型和struct
这样的变量。对于其他类型,您需要使用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的前一种情况可以被(由编译器)重写为后者。这称为return value optimization。
答案 3 :(得分:1)
如果你真的想这样做,你可以尝试使数组A静态,这样A的存储不是由函数的范围决定的,你可以实际返回数组(当然是以指针的形式)。
但这不是一个很好的方法来完成你想要实现的目标,而是将数组传递给函数rand_grid
。这就是通过地址的意思。
答案 4 :(得分:0)
我知道从函数返回数组的所有方法都有弱点和优势。
在一个struc中包装可以避免分配和释放内存的开销,并避免记忆释放。您在使用malloc,calloc和realloc的任何解决方案上都存在这些问题。另一方面,在结构中包装需要知道数组的最大可能大小,并且明显浪费大型数组的内存和执行时间(例如,将文件加载到内存中并将文件内容从函数传递到函数通过复制)。