在掌握一维数组与函数的声明、调用之后,需要弄清数组如何作为实参传入函数:既可以传递单个元素,也可以传递整个数组或二维数组。本节说明对应的形参写法,并说明数组形参为何会退化为指针,以及为何通常需要同时传入元素个数。
传递单个数组元素
若函数只关心数组中的某一个下标,可以把该元素作为普通变量传入,此时按值传递:函数收到的是该元素的一份副本,在函数内修改形参不会影响调用方的数组元素(除非传入的是指针,那是另一章的内容)。
#include <stdio.h>
void display(int age1, int age2) {
printf("%d\n", age1);
printf("%d\n", age2);
}
int main(void) {
int ageArray[] = {2, 8, 4, 12};
display(ageArray[1], ageArray[2]); /* 传入下标 1、2 的元素 */
return 0;
}输出:
8
4传递整个一维数组
要把整段连续元素交给函数处理,调用时一般只写数组名(表示首元素地址),形参可写成 float age[] 或等价的 float *age。下列程序通过函数计算数组元素之和:
#include <stdio.h>
float calculateSum(float age[], int n);
int main(void) {
float age[] = {23.4f, 55, 22.6f, 3, 40.5f, 18};
float result = calculateSum(age, 6);
printf("结果 = %.2f\n", result);
return 0;
}
float calculateSum(float age[], int n) {
float sum = 0.0f;
for (int i = 0; i < n; ++i) {
sum += age[i];
}
return sum;
}输出:
结果 = 162.50调用处写 calculateSum(age, 6):第一个实参是数组名,第二个实参是元素个数。定义处的 float age[] 表示接收指向 float 的指针;方括号内不写长度是允许的,因为函数内无法从形参本身可靠地得到数组总长度。
此处传递的是首元素地址,并不是把整个一维数组复制进函数;若在 calculateSum 内修改 age[i],调用方 main 中的 age 数组会同步改变。
传递二维数组
二维数组同样以数组名作为实参传入。形参必须标明列数(第二维长度),编译器才能按行计算下标偏移;行数可以写在第一维,也可以省略由另一参数传入。
#include <stdio.h>
void displayNumbers(int num[][2], int rows);
int main(void) {
int num[2][2];
printf("输入 4 个整数:\n");
for (int i = 0; i < 2; ++i) {
for (int j = 0; j < 2; ++j) {
scanf("%d", &num[i][j]);
}
}
displayNumbers(num, 2);
return 0;
}
void displayNumbers(int num[][2], int rows) {
printf("数组内容:\n");
for (int i = 0; i < rows; ++i) {
for (int j = 0; j < 2; ++j) {
printf("%d\n", num[i][j]);
}
}
}输出示例(输入 2、3、4、5 时):
输入 4 个整数:
2
3
4
5
数组内容:
2
3
4
5若写成 int num[2][2] 作为形参,则只适用于固定为 2 行 2 列的情形;更通用的写法是 int num[][2] 并增加 rows 参数,与一维数组传入长度的方式一致。
二维数组名同样表示首地址,传递的不是矩阵副本;函数内若改写 num[i][j],main 里读入的 num 数组内容也会一并改变。
数组形参退化为指针
用数组名调用函数时,实参传递的是首元素地址,而不是把整个数组按字节复制进函数栈。因此在函数内部:
- 通过下标或指针修改元素,会作用到调用方的原数组(双方共享同一段存储)。
- 形参
float age[]与float *age在类型上等价,均表示指向float的指针。 - 对形参使用
sizeof(age)得到的是指针类型的大小,而不是原数组占用的总字节数;这也是一维、二维数组作参数时通常要另传n、rows等原因。
三种常见写法可对照如下:
| 调用方式 | 典型形参 | 实际传递的内容 |
|---|---|---|
f(arr[i]) | int x | 单个元素的副本 |
f(arr) | int arr[] / int *arr | 指向首元素的指针 |
f(mat)(二维) | int mat[][COL] | 指向首行首元素的指针,列数 COL 须已知 |
小结:表中后两种写法传递的是首地址,并不是把整个数组按元素复制一份进函数;因此在函数内修改下标对应的元素时,调用方数组中的值会同步改变。仅第一种传递单个元素属于按值传递,函数内改动形参不会影响原数组。
#include <stdio.h>
int sum(int arr[], int n) {
int s = 0;
for (int i = 0; i < n; ++i) {
s += arr[i];
}
return s;
}
int main(void) {
int a[] = {1, 2, 3, 4, 5};
printf("%d\n", sum(a, 5));
return 0;
}C 语言中可以把数组(首地址)传入函数,但不能通过返回值安全地交回整个局部数组:若返回指向函数内局部数组的指针,函数结束后该存储可能失效。需要把结果写回调用方提供的缓冲区,或在堆上分配并由调用方负责释放。
本节说明了数组作实参时的写法与退化规则。下一章将系统介绍指针,进一步说明数组名与指针在表达式中的关系。