编程嵌入式C开发者

描述如何在C语言中声明和使用多维数组。在将它们传递到函数中和初始化时有什么陷阱?

用 Hintsage AI 助手通过面试

回答

问题的背景

C语言中的多维数组最初被设计用于简化与表格和矩阵的操作。经典的二维数组是数组的数组,可以使用简单的语法来处理表格数据的元素。随着时间的推移,尤其是在处理可变长度数组时,这种方法得到了发展。

问题

不正确的声明和初始化多维数组会导致编译错误或逻辑故障。在将多维数组传递到函数时,许多开发者会因为规范的要求而感到困惑——必须明确指定除第一个维度之外的所有维度的大小。

解决方案

声明二维数组:

int matrix[3][4];

完全初始化:

int matrix[2][3] = { {1, 2, 3}, {4, 5, 6} };

传递到函数时——必须明确指定除第一个以外的所有尺寸:

void printMatrix(int m[][3], int rows) { for (int i = 0; i < rows; ++i) { for (int j = 0; j < 3; ++j) printf("%d ", m[i][j]); printf(" "); } }

随着C99标准的引入,可以声明接受可变长度数组的函数:

void foo(int rows, int cols, int a[rows][cols]);

关键特性:

  • 在传递到函数时,必须显式指定除第一个维度外的所有维度的大小。
  • C中的多维数组是数组的数组;元素在内存中按行存储(行主序)。
  • 部分初始化将未指定的元素初始化为零。

隐藏问题。

1. 可以声明一个不指定第二个大小的二维数组的函数吗?

不可以,C要求在编译时所有尺寸,除了第一个,必须是已知的。这与访问元素时的指针算术有关。

错误示例:

// 错误: void process(int arr[][], int rows); // 不可以

2. 如果不初始化所有的多维数组元素会发生什么?

如果数组是静态或全局的,剩余的元素将自动填充为零。对于局部数组的部分初始化,隐式初始化的元素也将为零。

int a[2][3] = {{1}, {4}}; // a[0][1] 和 a[0][2],a[1][1] 和 a[1][2] 将变为 0

3. 指针数组和二维数组之间有什么区别?

二维数组是一个连续的内存块。指针数组是指向单独的一维数组的指针的集合,这在为“破碎的”数组分配内存时很重要。

常见错误和反模式

  • 声明含有多维数组的函数时的错误(未指定“内部”维度的大小)。
  • 在处理行主序布局时行和列混淆。
  • 用真正的多维数组替代指针数组,反之亦然。

生活中的例子

消极案例

尝试声明并在函数中传递一个没有指定第二个大小的二维数组,这将导致编译错误。表面的修复通过替换为指针导致进一步计算时的未定义或不正确行为。

优点:

  • 函数声明简单(乍一看)。

缺点:

  • 编译错误、不正确的索引算术、数据损坏。

积极案例

开发者明确指定所有维度的大小,在文档中解释元素在内存中的存储顺序,从而减少后续维护中的错误数量。

优点:

  • 安全、正确且可移植的代码。

缺点:

  • 数组的大小或“宽度”必须在编译时已知,或者需要C99标准和可变长度数组。