编程C开发者

详细介绍C语言中在函数中传递数组的机制。这种模型的风险是什么,以及如何正确组织函数内数组的安全操作?

用 Hintsage AI 助手通过面试

答案

在C语言中,数组并不是通过值传递给函数的。如果将数组作为参数传递,实际上传递的是指向数组第一个元素的指针。这导致函数修改的是原始数组,而不是它的副本。

例如:

void fillArray(int arr[], int n) { for (int i = 0; i < n; ++i) arr[i] = i*i; } int main() { int myarr[5]; fillArray(myarr, 5); // 正确 }

在函数内部

  • 无法通过 sizeof(arr) 知道原始数组的大小——这将返回指针的大小,而不是数组的大小。
  • 只能操作我们明确传递的那块内存的大小。

正确和安全地处理数组可以这样做:

  • 始终显式传递数组的大小作为单独的参数;
  • 使用常量或宏包装器来表示大小;
  • 如果需要保护数组不被修改,传递 const int *arr

误导性问题

问题: 在函数内部是否可以通过参数 int arr[] 使用 sizeof(arr) 来获取传递的原始数组的大小?

答案: 不可以!在函数内部,sizeof(arr) 将返回指向类型的指针的大小(例如,4 或 8字节),而不是数组的大小。

示例:

void f(int arr[]) { printf("%zu\n", sizeof(arr)); // 指针的大小,而不是数组的大小! } int main() { int x[10]; f(x); // 通常将输出8(x86_64)或4(x86) }

实际错误示例


故事

在一个工业项目中,复制数组的函数尝试在运行时计算数组的长度,使用 sizeof(arr)/sizeof(int) 在函数内部。这导致仅复制数组的一部分,因为大小始终等于1(8/8),数据被不可预测地覆盖。


故事

在一个网络应用中,数据发送函数接受一个数组形式的缓冲区而没有明确指示其大小,导致整个缓冲区未能发送,或者越界读取垃圾数据,造成传输错误和连接不稳定。


故事

在编写图像处理库时,程序员没有为图像数组着色函数提供必需的大小参数。这导致缓冲区溢出和程序在某些输入下崩溃,仅在对大图像的集成测试中发现。