多维数组作为函数参数的衰减

16
我知道,例如这个例子:

我知道,例如这个例子:

void foo(int a[])// or a[x]

编译器会将其视为:

void foo(int *a)

但是我不知道,也没有找到任何地方说明编译器如何看待多维数组。

例如:

void foo(int a[3][4])

会是这样吗?

void foo(int (*a)[4])

或者像这样?

void foo(int **a)
4个回答

21
当数组退化时,它会转换为指向第一个元素的指针。在 int a [3] [4] 的情况下,a 是一个 int[4] 数组,因此指向 int [3] [4] 元素的指针具有类型 int(*)[4]
因此这样做:
void foo(int a[3][4])

等同于:

void foo(int (*a)[4])

6
编译器在不知道除最外层以外的每个维度的情况下,无法正确地索引传递给函数的多维数组。
因此,对于一维数组,不需要长度:
void foo(int a[]);

and

void foo(int a[3]);

尽管具有误导性,但“相等”的比较运算符在C语言中是可以使用的,因为C语言不关心数组的长度:这需要程序员自己保证正确。

对于二维数组,内部维度必须正确,否则编译器将无法索引它。因此,

void foo(int a[][3]);

虽然不错,但是

void foo(int a[][]);

无法被编码,

void foo(int a[42][3]);

这是好的但不必要的,也不具限制性,因为编译器只需要有关如何索引而不是索引多少信息。


2
"C语言对于数组的长度并不关心" - 这仅适用于函数参数的情况,而并非一般情况。 - M.M
@M.M 不确定是否如此。在 C 中,没有任何阻止我访问超出任何数组末尾的某些元素的东西。只是编译器可以自由进行一些静态分析来尝试猜测我是否正确,并警告我。 - Героям слава
2
@Wilson 在编程中需要注意实际(非函数参数)数组的大小,以便例如使 sizeof 运算符给出正确的大小。 - Ruslan
1
@Wilson,当为数组定义提供初始化数据时,编译器也会考虑数组的长度。我想让答案保持主题而不是关于数组的完整介绍。 - Weather Vane

1
多维数组常常是问题的源头,尤其是当你需要允许动态大小时。在一般情况下,我建议使用:
void foo(int* a, int size1, int size2);

或者

void foo(int* a, int numSizes, int* sizes);

显式传递大小限制可以避免指针衰减和缺乏检查导致的常见段错误。在大多数情况下,使用数组类型非常脆弱且不推荐使用。您还可能希望指定索引方法,通常为a[size1*i+j],但您可能需要其他内容。

1
void foo(int a[3][4])

a是一个长度为3的数组,由4个元素的int数组组成。
所以它看起来像这样:
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+

你可以添加行,但不能添加列,因为访问k[3][4]元素的方法是如下所示的a[3][2] = a[3*4 + 2]。这就是如何使用行和列信息找到上图中的一个框。方程式a[b][c] = a[b * row_number + c]在矩阵为非正方形时不适用。比如,

+---+---+---+---+---+
| 0 | 1 | 2 | 3 | 4 |
+---+---+---+---+---+
| 0 | 1 | 2 | 3 |
+---+---+---+---+

你明白吗?

看看上面的第一个表格,它可以用不同的方式进行枚举。比如:

+---+---+----+----+
| 0 | 1 | 2  | 3  |
+---+---+----+----+
| 4 | 5 | 6  | 7  |
+---+---+----+----+
| 8 | 9 | 10 | 11 |
+---+---+----+----+

实际上(因为它是一个数组,而不是一个表格)
+---+---+---+---+---+---+---+---+---+---+----+----+
| 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 |
+---+---+---+---+---+---+---+---+---+---+----+----+

在C语言中,二维数组是一维数组,只是索引不同。因此可以这样写:
void foo(int a[])

或者

void foo(int *a)

什么情况。
void foo(int **a)

这是一个整型数组的引用数组,而不是二维数组。相反,它可能很少有用。例如,当您想要拥有内部数组(行)具有不同长度的二维数组时。此外,这也是Java处理二维数组的方式。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接