当二维数组和多维数组作为C语言中的函数参数时

When two-dimensional array and multidimensional array as function parameters in C language

本问题已经有最佳答案,请猛点这里访问。

0

一维数组作为函数参数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
#include <string.h>

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);
}

它编译并正确运行。

但当二维数组作为函数参数时:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>
#include <string.h>

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("
"
);
}

int main(void)
{  
    int a[2][2] = {{1,2}, {3,4}};
    func(a, 2);
}

它不能正确编译。我必须这样修改代码:

2

我不知道为什么?有人能解释它的工作原理吗?多谢。


C中的数组(一维和多维)驻留在连续的内存块中。这意味着,当您定义char a[3]时,数组在内存中的布局如下(请原谅我糟糕的ASCII艺术技巧):

1
| a[0] | a[1] | a[2] |

对于二维数组char a[2][3],布局如下:

2

因此,当索引到二维数组a[i][j]中时,编译器生成的代码相当于:

1
*(a + i*3 + j)

这可以理解为"跳过i行并在该行中取单元格j"。为此,编译器必须知道行的长度(第二个维度)。这意味着第二个维度是类型定义的一部分!

因此,如果要将二维数组传递给函数,则必须为类型定义指定所需的维度。


最近的(例如,c211和c99)c标准启用了可变长度数组,因此以下函数可以工作

1
2
3
4
5
6
7
8
9
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 []类型,其大小不确定。


C中的数组非常"弱",通常在运行时仅由指向第一个元素的指针表示。当您声明类似于int a[][]的东西时,不可能知道如何计算每个元素的地址,因为类型声明没有说明。这就是它不编译的原因,因为类型无效。

如果您可以使用int a[][],然后通过int big[8][8]int small[2][2]调用它,那么函数中的代码就无法神奇地"适应"这些不同数组的正确地址计算。这就是它不起作用的原因。

您可以编写一个像int *matrix, size_t width这样的通用函数,并手动进行地址计算,即元素"matrix[i][j]位于matrix[i * width + j]处,用于行主排序。


如果没有数组的第二个维度,编译器就不知道如何对其进行索引。这是因为编译器用一个指针做了一些算术运算,以找出在内存中查找值的位置。


以下是一个很好的解释:http://www.eskimo.com/~scs/cclass/int/sx9a.html