C 不像大多数语言那样对待数组;如果您想在 C 中使用数组,则需要了解以下概念。
除非它是 sizeof 或一元 & 运算符的操作数,或者是用于在声明中初始化另一个数组的字符串文字,否则 表达式 类型为 "N- T" 的元素数组将被转换 ("decay") 为类型为 "pointer to T" 的表达式,表达式的值将是数组第一个元素的地址。这个结果不是左值;它不能是赋值的目标,也不能是++ 或-- 运算符的操作数。
这就是为什么你不能定义一个函数来返回一个数组类型;作为return 语句的一部分,数组表达式将被转换为指针类型,此外,无论如何都无法将结果分配给另一个数组表达式。
信不信由你,这是有充分的技术原因的;最初开发 C 时,Dennis Ritchie 从 B 编程语言中借鉴了很多概念。 B 是一种“无类型”语言;一切都存储为无符号字或“单元格”。内存被视为“单元”的线性阵列。当您将数组声明为
auto arr[N];
B 将为数组内容留出 N 个“单元”,以及一个绑定到 arr 的附加单元,以存储第一个元素的偏移量(基本上是一个指针,但没有任何类型语义)。数组访问被定义为*(arr+i);您从存储在a 中的地址偏移i 单元格并取消引用结果。这对 C 非常有用,直到 Ritchie 开始将结构类型添加到语言中。他希望结构的内容不仅能以抽象的术语描述数据,而且能物理地表示位。他使用的例子是这样的
struct {
int node;
char name[14];
};
他想为节点留出 2 个字节,紧接着为名称元素留出 14 个字节。他想要一个这样的结构数组布局,这样你有 2 个字节,然后是 14 个字节,然后是 2 个字节,然后是 14 个字节,等等。他想不出一个处理数组指针的好方法,所以他完全摆脱了它。 C 没有为指针留出存储空间,而是简单地从数组表达式本身计算它。这就是为什么您不能为数组表达式分配任何东西的原因;没有什么可以将值分配给 。
那么,如何从函数中返回二维数组?
你没有。你可以返回一个指针指向一个二维数组,比如:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
这种方法的缺点是必须在编译时知道N。
如果您使用的是支持可变长度数组的 C99 编译器或 C2011 编译器,则可以执行以下操作:
void func2( size_t rows, size_t cols, int (**app)[cols] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...; // the parens are necessary
...
}
如果您没有可用的可变长度数组,那么至少列维度必须是编译时常量:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
您可以将内存零碎地分配到像二维数组一样的东西中,但行不一定是连续的:
int **func4( size_t rows, size_t cols )
{
int **p = malloc( sizeof *p * rows );
if ( p )
{
for ( size_t i = 0; i < rows; i++ )
{
p[i] = malloc( sizeof *p[i] * cols );
}
}
return p;
}
p 是不是一个数组;它指向一系列指向int 的指针。出于所有实际目的,您可以像使用二维数组一样使用它:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
请注意,C 没有任何垃圾收集;你有责任清理自己的烂摊子。前三种情况,很简单:
int (*arr1)[N] = func(rows);
// use arr[i][j];
...
free( arr1 );
int (*arr2)[cols];
func2( rows, cols, &arr2 );
...
free( arr2 );
int (*arr3)[N];
func3( rows, &arr3 );
...
free( arr3 );
在最后一种情况下,由于您进行了两步分配,因此您需要进行两步释放:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)