我最近开始编程C只是为了好玩.我在一个非常熟练的程序员C# .NET和Java台式机领域内,但这是谈到了是有点太多对我来说是挑战.
我试图做一些"简单"的事情,如从函数返回一个二维数组.我已经尝试过在网上进行研究,但我很难找到有用的东西.
这是我到目前为止所拥有的.它没有完全返回数组,它只填充一个.但即使这样也无法编译(我相信如果你是一名熟练的C程序员,原因必须是显而易见的).
void new_array (int x[n][n]) {
int i,o;
for (i=0; i<n; i++) {
for (o=0; o<n; o++) {
x[i][o]=(rand() % n)-n/2;
}
}
return x;
}
Run Code Online (Sandbox Code Playgroud)
用法:
int x[n][n];
new_array(x);
Run Code Online (Sandbox Code Playgroud)
我究竟做错了什么?应该提到的n是具有该值的常量3.
编辑:尝试定义常量时,这是一个编译器错误:http://i.imgur.com/sa4JkXs.png
C不像大多数语言那样处理数组; 如果要在C中使用数组,则需要了解以下概念.
除非它是sizeof或一元运算&符的操作数,或者是用于初始化声明中的另一个数组的字符串文字,否则"N元素数组" 类型的表达式T将被转换("衰减")为表达式输入"指向T",表达式的值将是数组第一个元素的地址.这个结果不是左值; 它不能是一个赋值的目标,也不能是一个操作数的++或--运营商.
这就是为什么你不能定义一个函数来返回一个数组类型; 数组表达式将转换为指针类型作为return语句的一部分,此外,无论如何都无法将结果分配给另一个数组表达式.
信不信由你,这有一个坚实的技术原因; 当他最初开发C语言时,Dennis Ritchie从B编程语言中借用了很多概念.B是一种"无类型"的语言; 一切都存储为无符号字或"单元格".记忆被视为"细胞"的线性阵列.当您将数组声明为
auto arr[N];
Run Code Online (Sandbox Code Playgroud)
B将为数组内容留出N个"单元",以及绑定的附加单元arr以将偏移存储到第一个元素(基本上是指针,但没有任何类型语义).数组访问定义为*(arr+i); i从存储的地址中偏移单元格a并取消引用结果.这对C来说很有用,直到Ritchie开始在语言中添加结构类型.他希望结构的内容不仅用抽象术语描述数据,而且用于物理地表示位.他使用的例子是这样的
struct {
int node;
char name[14];
};
Run Code Online (Sandbox Code Playgroud)
他想为节点留出2个字节,紧接着是name元素的14个字节.并且他想要布置一系列这样的结构,使得你有2个字节后跟14个字节,然后是2个字节,接着是14个字节,等等.他无法找到一个处理数组指针的好方法,所以他彻底摆脱了它.C不是为指针设置存储空间,而是从数组表达式本身计算它.这就是为什么你不能为数组表达式赋值; 没有什么可以赋值给.
那么,如何从函数返回2D数组?
你没有.您可以返回指向 2D数组的指针,例如:
T (*func1(int rows))[N]
{
T (*ap)[N] = malloc( sizeof *ap * rows );
return ap;
}
Run Code Online (Sandbox Code Playgroud)
这种方法的缺点是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
...
}
Run Code Online (Sandbox Code Playgroud)
如果没有可用的可变长度数组,那么至少列维必须是编译时常量:
#define COLS ...
...
void func3( size_t rows, int (**app)[COLS] )
{
*app = malloc( sizeof **app * rows );
(*app)[i][j] = ...;
}
Run Code Online (Sandbox Code Playgroud)
您可以将内存零碎分配到类似于2D数组的内容中,但行不一定是连续的:
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;
}
Run Code Online (Sandbox Code Playgroud)
p是不阵列; 它指向一系列指针int.出于所有实际目的,您可以像使用2D数组一样使用它:
int **arr = foo( rows, cols );
...
arr[i][j] = ...;
printf( "value = %d\n", arr[k][l] );
Run Code Online (Sandbox Code Playgroud)
请注意,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 );
Run Code Online (Sandbox Code Playgroud)
在最后一种情况下,由于您执行了两步分配,因此需要执行两步重新分配:
int **arr4 = func4( rows, cols );
...
for (i = 0; i < rows; i++ )
free( arr4[i] )
free( arr4)
Run Code Online (Sandbox Code Playgroud)