当二维数组和多维数组作为C语言中的函数参数
可能重复:
如何在C ++中使用数组?
一维数组作为函数参数:
#include #include int func(int a[], int n) { int i; for(i = 0; i < n; i++) printf("%d ", a[i][j]); } int main(void) { int a[2] = {1,2}; func(a, 2); }
它编译并正确运行。
但是当二维数组作为函数参数时:
#include #include int func(int a[][], int n) { int i, j; for(i = 0; i < n; i++) for(j = 0 ; j < n; j++) printf("%d ", a[i][j]); printf("\n"); } int main(void) { int a[2][2] = {{1,2}, {3,4}}; func(a, 2); }
它无法正确编译。 我必须修改这样的代码:
#include #include int func(int a[][2], int n) { int i, j; for(i = 0; i < n; i++) for(j = 0 ; j < n; j++) printf("%d ", a[i][j]); printf("\n"); } int main(void) { int a[2][2] = {{1,2}, {3,4}}; func(a, 2); }
我不知道为什么? 任何人都可以解释它是如何工作的? 非常感谢。
c中的数组(包括一维和多维)驻留在连续的内存块中。 这意味着当你定义char a[3]
,数组就像这样布局在内存中(原谅我可怕的ascii艺术技巧):
| a[0] | a[1] | a[2] |
对于二维数组char a[2][3]
,布局如下:
| a[0][0] | a[0][1] | a[0][2] | a[1][0] | a[1][1] | a[1][2] | ^ +--- first row ends here
因此,当您索引到二维数组a[i][j]
,编译器会生成与此等效的代码:
*(a + i*3 + j)
其中可以读作“跳过i行并在该行中获取单元格j”。 要实现此目的,编译器必须知道行的长度(这是第二个维度)。 这意味着第二个维度是类型定义的一部分!
因此,当您想要将2d数组传递给函数时,必须为类型定义指定所需的维度。
最近(例如C2011 ,也许是C99 ) C标准启用了可变长度数组,因此以下function确实有效
int sum (int n, int t[n][n]) { int s = 0; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) s += t[i][j]; return s; }
使用gcc-4.7 -std=gnu99 -Wall -O -c ex.c
编译时没有警告,生成的汇编程序就是你所期望的
至于为什么int t[][]
不起作用,这是因为整个t
每个元素都是int []
类型,它具有不确定的大小。
这是一个非常好的解释: http : //www.eskimo.com/~scs/cclass/int/sx9a.html
如果没有数组的第二个维度,编译器就不知道如何索引它。 这是因为编译器使用指针进行一些算术运算,找出在内存中找到值的位置。
C中的数组非常“弱”,通常仅在指向第一个元素的指针时在运行时表示。 当你声明像int a[][]
这样的东西时,不可能知道如何计算每个元素的地址,因为类型声明没有说明。 这就是为什么它不会编译,因为类型无效。
如果你可以使用int a[][]
,然后调用它传递int big[8][8]
或int small[2][2]
,那么函数内部的代码就无法神奇地“适应”这些不同arrays的正确地址计算。 这就是为什么它不起作用的原因。
您可以编写像int *matrix, size_t width
这样的通用函数int *matrix, size_t width
并手动进行地址计算,即元素“ matrix[i][j]
”在matrix[i * width + j]
进行行主要排序 。