7.1 函数参数

在讲解函数参数之前,先来看函数定义的一般形式:


类型说明符 函数名(参数)

{

函数体;

}


函数由以上几个部分所构成,如果函数在定义时不带有任何的参数,即参数为空,那么函数在调用时同样不用带参数,看下面的代码。


include<stdio.h>

void print()

{

printf("Hello Wrold!\n");

return;

}

int main()

{

print();

return 0;

}


运行结果:


Hello Wrold!


上面定义的print()函数没有任何参数,所以在调用的时候只需要使用函数名加括号的简单形式就可以实现函数调用。但是更多的时候使用的是带参数的函数,在使用带参数的函数时,需要注意的是传值和传址的区别:传值是一种简单的对于实参的复制,形参有自己的存储空间,所以在函数中对于形参的操作不会影响实参;而传址传递的是地址,实参和形参之间共享同一存储空间,在函数中对于形参的操作同样影响到实参。因此在写函数的时候,要清楚地知道需要采用传值还是传址。接下来通过下面的一段代码来了解数组作为函数参数的使用。


include<stdio.h>

void sort(int a[],int n)

{

int i,j,k,temp;

for(i=0;i<n-1;i++)

{

k=i;

for(j=i+1;j<n;j++)

{

if(a[j]<a[k])

k=j;

}

if(k!=i)

{

temp=a[i];

a[i]=a[k];

a[k]=temp;

}

}

return;

}

int main()

{

int i;

int arr[8]={99,65,45,15,89,57,28,23};

sort(arr,8);

for(i=0;i<8;i++)

printf("%d\t",arr[i]);

printf("\n");

return 0;

}


运行结果:


15 23 28 45 57 65 89 99


通过上面的代码可知,在sort()函数中对形参数组a进行排序,但是在main()函数中打印输出的arr数组是进行排序后的结果,这是什么原因呢?如图7-1所示为参数传递的示意图。

7.1 函数参数 - 图1

图 7-1 参数的传递

从图7-1中可以看出,形参和实参都指向同一片存储空间,所以会在函数中对形参进行排序,从而实现对实参的排序操作。但是需要注意的是,在采用一维数组作为参数的时候,在形参中并没有直接指定数组的大小,而是通过第二个参数来告知函数一维数组的长度。当然也可以直接指定数组的大小,如:


include<stdio.h>

void print(int a[8])

{

int i;

for(i=0;i<8;i++)

printf("%d\t",a[i]);

printf("\n");

return;

}

int main()

{

int arr[8]={99,65,45,15,89,57,28,23};

print(arr);

return 0;

}


运行结果:


99 65 45 15 89 57 28 23


从上面的代码可知,在函数的形参中指定了数组的大小,这样在调用函数时就需要注意,如果调用函数的数组长度小于形参中指定的数组长度,那么编译就会出现“error C2078:too many initializers”错误,这是因为在函数中形参的数组长度大于调用时的实参数组长度,使得形参中多余的数组元素没有确定值而出错,如果调用的数组长度大于形参中给定的数组长度,那么调用不会出现任何问题。

在前面已经多次提及,数组作为函数参数时会退化为指针,已经不再是数组了,通过下面一段代码来加深一下印象。


include<stdio.h>

void print(int a[8])

{

printf("sizeof(a)=%d\n",sizeof(a));

return;

}

int main()

{

int arr[8]={99,65,45,15,89,57,28,23};

printf("sizeof(arr)=%d\n",sizeof(arr));

print(arr);

return 0;

}


运行结果:


sizeof(arr)=32

sizeof(a)=4


由上面的运行结果可知,形参中的数组所占用的内存大小为4字节,而main()函数中的实参数组占用的内存大小为32字节,刚好为数组长度和每个数组元素所占用内存的乘积。而形参中的数组a[]实际已经不是数组,而是一个int型指针a,这也就是为什么在以数组作为参数时是传址的原因了。因为数组名就是数组的首地址,所以函数调用过程中传递的也就是数组的首地址。

接下来看多维数组作为函数参数的使用情况。


include<stdio.h>

void print(int row,int a[][3])

{

int i,j;

for(i=0;i<row;i++)

{

for(j=0;j<3;j++)

printf("%d\t",a[i][j]);

printf("\n");

}

return;

}

int main()

{

int arr[3][3]={99,65,45,15,89,57,28,23,45};

print(3,arr);

return 0;

}


运行结果:


99 65 45

15 89 57

28 23 45


在使用二维数组作为函数参数的时候需要注意的是,必须执行第二维的大小,否则会出错,前面介绍过多维数组在内存中是按照一维数组的方式来存储的,所以在使用多维数组作为函数参数的时候必须执行每行有多少个元素,否则无法区分每行有多少个元素,进而导致编译出错。当然,可以同时指定数组中每一维的长度,所以在使用所谓数组作为函数参数的时候,要尤其注意其使用格式。接下来再看看三维数组作为函数参数的使用。


include<stdio.h>

void print(int row,int a[][2][2])

{

int i,j,k;

for(i=0;i<row;i++)

{

for(j=0;j<2;j++)

{

for(k=0;k<2;k++)

printf("%d\t",a[i][j][k]);

printf("\n");

}

printf("\n");

}

return;

}

int main()

{

int arr[2][2][2]={99,65,45,15,89,57,28,23};

print(2,arr);

return 0;

}


运行结果:


99 65

45 15

89 57

28 23


从上面的代码中可以看到,对形参中的三维数组同样指定了后两维的长度,所以对于多维数组作为函数参数的情况,我们必须清楚地知道,除了第一维可以省略不写以外,其余每一维都必须给出其数组长度。但是同样需要注意的是,多维数组作为函数参数时,它也是指针,而且这时函数调用的实参和形参除了第一维大小可以不同以外,其余各维的大小必须一致,否则编译出错,同时第一维中形参大于实参的部分,其结果都是随机的。