1. 引言
在 C 语言中,数组以特殊的方式传递给函数。当你将数组传递给函数时,实际传递的是指向其第一个元素的指针。这意味着函数操作的是原始数组,而不是副本。理解这一行为对于编写高效且正确的 C 程序至关重要。
2. 数组如何传递给函数
当你编写一个接受数组作为参数的函数时,编译器会将参数视为指针。例如,以下两个函数声明是等价的:
c
void print_array(int arr[], int size);
void print_array(int *arr, int size);
两者都告诉编译器 arr 指向一个整数数组的第一个元素。由于数组是通过引用(即指针)传递的,函数内部所做的任何修改都会影响调用者中的原始数组。
3. 将数组传递给函数
要将数组传递给函数,只需使用不带方括号的数组名。数组名会退化为指向其第一个元素的指针。
c
#include <stdio.h>
void print_array(int arr[], int size) {
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");
}
int main() {
int numbers[] = {10, 20, 30, 40, 50};
int n = sizeof(numbers) / sizeof(numbers[0]);
print_array(numbers, n);
return 0;
}
输出:
10 20 30 40 50
注意,在 main 函数中,sizeof(numbers) 给出的是数组的总字节数,因此除以 sizeof(numbers[0]) 可以得到元素的个数。然而,在函数内部,sizeof(arr) 只会给出指针的大小,而不是整个数组的大小。这就是为什么必须显式传递数组大小的原因。
4. 在函数内部修改数组
由于数组是通过引用传递的,你可以在函数内部直接修改原始数组,而无需返回任何内容。
c
#include <stdio.h>
void double_values(int arr[], int size) {
for (int i = 0; i < size; i++) {
arr[i] *= 2;
}
}
int main() {
int numbers[] = {1, 2, 3, 4, 5};
int n = sizeof(numbers) / sizeof(numbers[0]);
double_values(numbers, n);
for (int i = 0; i < n; i++) {
printf("%d ", numbers[i]);
}
printf("\n");
return 0;
}
输出:
2 4 6 8 10
函数 double_values 直接修改了 numbers 的元素,这些修改在调用返回后于 main 函数中仍然可见。
5. 使用指针运算
由于数组参数实际上是一个指针,你可以在函数内部使用指针运算来遍历数组。
c
#include <stdio.h>
int sum_array(int *arr, int size) {
int total = 0;
for (int i = 0; i < size; i++) {
total += *(arr + i);
}
return total;
}
int main() {
int numbers[] = {5, 10, 15, 20};
int n = sizeof(numbers) / sizeof(numbers[0]);
int result = sum_array(numbers, n);
printf("Sum: %d\n", result);
return 0;
}
输出:
Sum: 50
在这里,*(arr + i) 等价于 arr[i]。两种形式访问的是同一个元素。
6. 二维数组
传递二维数组时需要指定第二维的大小,因为编译器需要知道每一行有多少列,才能正确计算地址。
c
#include <stdio.h>
void print_matrix(int matrix[][3], int rows) {
for (int i = 0; i < rows; i++) {
for (int j = 0; j < 3; j++) {
printf("%d ", matrix[i][j]);
}
printf("\n");
}
}
int main() {
int grid[][3] = {
{1, 2, 3},
{4, 5, 6},
{7, 8, 9}
};
print_matrix(grid, 3);
return 0;
}
输出:
1 2 3
4 5 6
7 8 9
参数 int matrix[][3] 表示一个指向包含 3 个整数的数组的指针。第一个维度可以省略,但第二个维度必须存在。
7. 常见陷阱
- 忘记传递数组大小 :在函数内部,
sizeof(arr)返回的是指针的大小,而不是数组的大小。务必显式传递元素的个数。 - 在只需要读取时却进行了修改 :如果函数不应修改数组,应将参数声明为
const int arr[],以防止意外修改。 - 误以为数组会被复制:数组在传递给函数时永远不会被复制。如果需要副本,请在函数内部手动创建。
8. 总结
- 数组作为指向其第一个元素的指针传递给函数。
- 函数内部的修改会影响原始数组。
- 始终单独传递数组的大小。
- 使用
const保护只读数组。 - 对于多维数组,除第一维外,必须指定所有维度。
掌握在函数中操作数组是编写简洁高效 C 代码的关键一步。