9.3.2 以数组名作为函数的参数
在C语言中,可以使用数组名作为函数的参数。以数组名作为函数的参数与以数组元素作为实参有如下几点不同。
当以数组元素作为实参时,只要数组类型和函数形参变量的类型一致,这样作为下标变量的数组元素的类型也和函数形参变量的类型是一致的。因此,它并不要求函数的形参也是下标变量。也就是说,数组元素的处理是按普通变量来对待的。当以数组名作为函数参数时,要求形参和相对应的实参必须是类型相同的数组,都必须有明确的数组说明。当形参和实参二者不一致时,会发生错误。
当以普通变量或下标变量作为函数参数时,形参变量和实参变量是两个由编译系统分配的不同的内存单元。函数调用时的数据传送是把实参变量的值赋给了形参变量。在用数组名作为函数参数时,进行的不是值的传送,即不是把实参数组中每一个元素的值都赋给了形参数组的各个元素。因为实际上形参数组并不存在,编译系统不为形参数组分配内存。因此在用数组名作为函数参数时所进行的传送只是地址的传送,也就是说,实参数组的首地址赋值为形参数组名。形参数组名取得该首地址之后,也就等于有了实在的数组。实际上是形参数组和实参数组为同一数组,共同拥有一段内存空间。
在变量作为函数参数时,所进行的传送是单向的。即只能从实参传向形参,不能从形参传回实参。形参的初值和实参相同,而形参的值发生改变后,实参并不变化,二者的终值是不同的。本书前面的实例就很好地说明了这个问题。
而当用数组名作为函数参数时,情况则不同。由于实际上形参和实参为同一数组,因此当形参数组发生变化时,实参数组也会随之变化。当然这种情况不能理解为发生了“双向”传递。但从实际情况来看,调用函数之后实参数组中的值将由于形参数组值的变化而变化。为了说明这种情况,看下面的一段代码。
void nzp(int a[5]){ int i; printf("\nvalues of array a are:\n"); for(i=0; i<5; i++) { if(a[i]<0) a[i]=0; printf("%d ", a[i]); } } int main(void){ int b[5], i; printf("\ninput 5 numbers:\n"); for(i=0; i<5; i++) scanf("%d", &b[i]); printf("initial values of array b are:\n"); for(i=0; i<5; i++) printf("%d ", b[i]); nzp(b); printf("\nlast values of array b are:\n"); for(i=0; i<5; i++) printf("%d ", b[i]); } void nzp(int a[5]) { …… }
在上述代码中,函数nzp的形参为整数组a,其长度为5。在主函数中实参数组b也为整型,长度也为5。在主函数中首先输入数组b的值,然后输出数组b的初始值。然后以数组b为实参调用nzp函数。在nzp中,按要求把负值单元清零,并输出形参数组a中的值。返回主函数之后,再次输出数组b中的值。从运行结果可以看出,数组b的初值和终值是不同的,数组b的终值和数组a中的是相同的。这说明实参和形参为同一数组,它们的值同时发生了改变。
在C语言中,用数组名作为函数参数时应注意如下几点。
❑ 形参数组和实参数组的类型必须一致,否则将引起错误。
❑ 形参数组和实参数组的长度可以不相同,因为在调用时,程序只传送首地址而不检查形参数组的长度。当形参数组的长度与实参数组不一致时,虽不至于出现语法错误(编译能通过),但执行结果将与实际不符,这是应加以注意的。例如可对于上面的代码进行如下修改。
void nzp(int a[8]) { int i; printf("\nvalues of array aare:\n"); for(i=0; i<8; i++) { if(a[i]<0)a[i]=0; printf("%d", a[i]); } } int main(void){ int b[5], i; printf("\ninput 5 numbers:\n"); for(i=0; i<5; i++) scanf("%d", &b[i]); printf("initial values of array b are:\n"); for(i=0; i<5; i++) printf("%d", b[i]); nzp(b); printf("\nlast values of array b are:\n"); for(i=0; i<5; i++) printf("%d", b[i]); }
上述程序与前段程序相比,nzp函数的形参数组长度改为了8,在函数体中,for语句的循环条件也改为i<8。因此,形参数组a和实参数组b的长度不一致,编译也能够通过。但是从结果来看,数组a中的元素a[5]、a[6]、a[10]显然是无意义的。
在函数形参表中,允许不给出形参数组的长度,或用一个变量来表示数组元素的个数。例如可以写为如下格式。
void nzp(int a[])
也可以写为如下格式。
void nzp(int a[], int n)
其中,形参数组a没有给出长度,而是由n值动态地表示数组的长度。n值由主调函数的实参进行传送。
多维数组也可以作为函数参数。在进行函数定义时形参数组可以指定每一维的长度,也可省去第一维的长度。所以以下两种写法都是合法的。
int MA(int a[3][10]) int MA(int a[][10])