C语言函数参数及其传递方式
C语言函数的参数
函数的参数有形式参数(简称形参)和实际参数(简称实参)两类。- 函数定义时的参数称为形参,形参在函数未被调用时是没有确定值的,只是形式上的参数。
- 函数调用时使用的参数称为实参。
【示例1】将两个数由小到大排序输出。代码如下:
#include<stdio.h> void order(int a,int b) /*a,b形式参数*/ { int t; if(a>b)/*如果a>b,就执行以下3条语句,交换a,b的值*/ { t=a; a=b; b=t; } printf("从小到大的顺序为:%d %d\n",a,b); /*输出交换后的a,b的值*/ } int main() { int x,y; printf("请输入两个整数:"); /*从键盘输入两个整数*/ scanf("%d%d",&x,&y); order(x,y); /*x,y是实际参数*/ }运行结果:
请输入两个整数:13 9
从小到大的顺序为:9 13
该程序由两个函数main() 和order()组成。order() 函数定义中的 a 和 b 是形参,在函数调用时接收实参传递过来的值;在 main() 函数中,通过“order(x,y);”调用子函数,其中的 x 和 y 是实参,在主函数中赋值,当函数调用时把值传递给形参 a 和 b。
1) 定义函数时,必须说明形参的类型,如【示例1】中,形参 a 和 b 的类型都是整型。
注意:形参只能是简单变量或数组,不能是常量或表达式。
2) 函数被调用前,形参不占用内存的存储单元。函数调用以后,形参才被分配内存单元。函数调用结束后,形参所占用的内存也将被回收,被释放。3) 实参可以是常量、变量或表达式。如在调用时可写成:
order(2,3); /*实参是常量*/
order(x+y,x-y); /*实参是表达式*/
4) 实参的个数、顺序和类型应该与函数定义中形参表中的形参个数、顺序和类型一一对应。
如上面代码中的 order() 函数,定义时有两个整型的形参,调用时,实参也要与它对应,即两个整型的实参,而且多个实参之间要用逗号隔开。如果不一致,则会发生“类型不匹配”的错误。
注意:对于特殊的字符型和整型,是可以互相匹配的,必要的时候还需要进行类型的转换。
C语言函数参数的传递方式
形参只是一个形式,在调用之前并不分配内存。函数调用时,系统为形参分配内存单元,然后将主调函数中的实参传递给被调函数的形参。被调函数执行完毕,通过 return 语句返回结果,系统将形参的内存单元释放。
由此可见,实参和形参的功能主要是数据传递,按照传递的是“数据”还是“地址”,分为“值传递”和“地址传递”。
“值传递”是“单向传递”,“地址传递”是“双向传递”。顾名思义,“单向传递”只能把实参的值传递给形参,形参的值不能回传给实参,而“双向传递”既可以把实参的值传递给形参,也可以把形参的值回传给实参。
下面就来了解一下这两种参数的传递方式。
1)“值传递”——单向传递
C 语言规定,实参对形参的数据传递是“值传递”,即单向传递,只能把实参的值传递给形参,而不能把形参的值再传回给实参。在内存当中,实参与形参占用不同的单元,不管名字是否相同,因此函数中对形参值的任何改变都不会影响实参的值。【示例2】使用函数交换两个变量的值。代码入下:
#include<stdio.h> void swap(int a,int b) /*定义swap()函数*/ { int temp; temp=a;a=b;b=temp; /*交换a,b值的3条语句*/ printf("a=%d,b=%d\n",a,b); /*输出交换后的结果*/ } int main() { int x,y; printf("请输入两个整数:\n"); scanf("%d%d",&x,&y); /*输入两个整数*/ printf("调用函数之前:\n"); printf("x=%d,y=%d\n",x,y); /*输出调用swap()函数之前x,y的值*/ printf("调用函数中:\n"); swap(x,y); /*调用swap()函数*/ printf("调用函数之后:\n"); printf("x=%d,y=%d\n",x,y); /*输出调用swap()函数之后x,y的值*/ }运行结果:
请输入两个整数:
6 8
调用函数之前:
x=6,y=8
调用函数中:
a=8,b=6
调用函数之后:
x=6,y=8
本例中为什么在 swap() 函数内变量 a 和 b 的值互换了,而主调函数 main() 中实参 x 和 y 却没有交换呢?这是参数按值传递的缘故。
main() 函数中定义的变量 x 和 y 在内存中各自占用了存储单元,在调用 swap() 函数时,为形参 a 和 b 另外分配了内存单元,形参与实参的存储单元是不同的,将 x 的值传给 a,y 的值传给 b,如下图中左图所示。
被调函数的形参是局部变量,只在被调函数内部起作用,且形参的值不能反过来传给主调函数。因此在 swap() 函数执行过程中,尽管把 a 和 b 的值交换了,但不能影响 main() 函数中的实参 x 和 y 的值,如下图中右图所示。函数调用完成,形参的内在单元将被释放。
如图所知,在函数调用过程中,形参的值发生改变,并不会影响实参的值。
提示:在“值传递”的过程中,按参数顺序传递数据,即第 1 个实参传给第 1 个形参,第 2 个实参传给第 2 个形参……与变量名无关,如【示例 2】中的两个形参写成 x 和 y 也仍然是不同的变量,实参和形参各有各的存储单元。形参 a 和 b 交换,并不会影响实参 x 和 y 的值。
C语言变量可分为局部变量和全局变量两种。
- 局部变量一般定义在函数和复合语句的开始处,使用它可以避免各个函数之间变量的相互干扰,尤其是同名变量。
- 全局变量一般定义在程序的最前面,在所有函数的外面,作用范围比较广,对作用域内所有的函数都起作用。
2)“地址传递”——双向传递
我们知道,数组名表示的是数组在内存中分配的存储空间的起始地址。如果把数组名作为参数进行传递就是“地址传递”,即把实参数组的起始地址传递给形参数组。这样形参数组和实参数组就占用了共同的存储空间,在子函数中对形参数组做的任何操作实际上就是对实参数组的操作。
子函数结束时不需要用 return 返回任何数据,当子函数结束后形参数组仍然作为局部变量被释放掉存储空间,返回主函数中继续向下执行代码,这时实参数组的元素已经进行了更新。
例如,主函数中调用子函数的语句如下。
int array[5];
findMax(array);
void findMax(int a[5])
形参数组的长度“5”也可以省略,写成下面的形式。void findMax(int a[ ])
【示例3】下面通过一个示例,具体说明将数组名和简单变量作为参数传递时实参的值是否会被改变。
#include <stdio.h> #define MAXELS 5 void findMax(int [ ],int); /*声明函数*/ int main() { int nums[MAXELS] = {0}; /*数组初始化*/ int i,value=0; printf("调用函数前输出结果:\n"); for (i = 0; i < MAXELS; i++) printf("nums[%d] = %d\n", i,nums[i]); printf("value = %d\n", value); findMax(nums,value); /*调用函数,传递数组名和简单变量*/ printf("调用函数后输出结果:\n"); for (i = 0; i < MAXELS; i++) /*循序输出数组元素*/ printf("nums[%d] = %d\n", i,nums[i]); printf("value = %d\n", value); return 0; } void findMax(int vals[ ],int m) /* 查找最大值函数 */ { int i; m=1; printf("findMax输出结果:\n"); for (i = 0; i < MAXELS; i++) { vals[i] = i; printf("vals[%d] = %d\n", i,vals[i]); } printf("max=%d\n m = %d\n", vals[--i],m); }运行结果:
调用函数前输出结果:
nums[0] = 0
nums[1] = 0
nums[2] = 0
nums[3] = 0
nums[4] = 0
value = 0
findMax输出结果:
vals[0] = 0
vals[1] = 1
vals[2] = 2
vals[3] = 3
vals[4] = 4
max=4
m = 1
调用函数后输出结果:
nums[0] = 0
nums[1] = 1
nums[2] = 2
nums[3] = 3
nums[4] = 4
value = 0
从结果分析,数组名是用地址传递方式进行的函数调用,形参和实参指向的是内存中的同一个存储区。
C语言带参数的主函数
从开始学 C 语言,我们就一直使用 main() 函数,都知道一个 C 程序必须有并且仅有一个主函数,C 程序的执行总是从 main() 函数开始的。main() 函数在使用过程中应该注意以下几点。
- main() 函数可以调用其他函数,包括本程序中定义的函数和标准库中的函数,但其他函数不能反过来调用 main() 函数。main() 函数也不能调用自己。
- 我们应该知道main() 函数没有在函数头中提供参数。其实,main() 函数可以带有两个参数,其一般形式如下。
int main(int argc,char *argv[ ])
{
函数体
}
注意:如果读者熟悉 DOS 的行命令操作系统,就会知道使用计算机命令是在提示符后面输入相应的命令名;如果有参数,就在命令后面输入相应的参数(如文件名等),并且命令与各参数之间用空格隔开,最后按【Enter】键运行该命令。
用户编写的 C 程序经过编译、连接后形成的可执行文件,可以像命令一样使用,其后面当然也可以跟命令行的参数,这个参数就传递给了 main() 函数。【示例4】输出包含几个字符串的一行文字。串之间用空格隔开,有几个字符串就相当于有几个参数。
#include <stdio.h> int main(int argc, char *argv[]) { int count; printf("The command line has %d arguments: \n",argc-1); for(count=1;count<argc;count++) /*依次读取命令行输入的字符串*/ printf("%d: %s\n",count,argv[count]); }运行结果:
The command line has 3 arguments:
1: I
2: am
3: happy!
- argv[0]→I
- argv[1]→am
- argv[2]→happy!
argc 的值即是参数的个数,程序在运行时会自动统计。
在命令行中的输入都将作为字符串的形式存储于内存中。也就是说,如果输入一个数字,那么要输出这个数字,就应该用 %s 格式,而非 %d 格式或者其他。
main() 函数也有类型。如果它不返回任何值,就应该指明其类型为 void;如果默认其类型为 int,那么在该函数末尾应由 return 语句返回一个值,例如 0。