图5.3程序运行结果说明:定义函数时指定的形参变量在未出现函数调用时,并不占用内存的存储单元。图5.4程序运行结果说明:程序中实参与形参同名,但两者的作用范围不同,程序开始执行时,为主函数中的变量n分配存储空间,实参n 在主函数main()中有效;主函数调用函数s(),有效的是形参n。程序的运行结果表明,当函数调用时,实参的值传送给形参,在被调函数内部,形参的变化不会影响实参的值。......
2023-10-21
大多数情况下,在调用函数时,主调函数和被调函数之间有数据的传递关系。在5.1.2节中已经提到了形式参数和实际参数的概念:在定义函数时函数名后面的参数称为“形式参数”(简称“形参”),在主调函数中调用一个函数时,函数名后面的参数(可以为一个表达式)称为“实际参数”(简称“实参”)。C语言提供了两种参数传递方式:按值传递和按地址传递。
1.按值传递
按值传递:调用时,主调函数把实参的值传给被调函数的形参,形参的变化不会改变实参的值,这是一种单向的数据传递方式。
当实参是变量名、常数、表达式或数组元素,而形式参数是变量时,参数传递方式采用的是“按值传递”的方式。我们通过下面的示例来说明按值传递方式中参数在函数之间的传递。
例5.2 给出函数power(m,n)的定义及调用它的主程序(power(m,n)函数用于计算整数m的正整数次幂n,如power(2,5)的值为32)。
#include<stdio.h>
说明:
例5.2中,main()函数在printf语句中两次调用了函数power():
printf("%d%d%d\n",i,power(x,i),power(y,i));
我们以第一次调用(即power(x,i))为例,在第一次调用中,x和i分别复制了一份值传递给被调函数power()的形参m和n,然后在被调函数中进行数据的处理,最后把计算的结果传回给调用它的main函数中的printf()函数。
说明:
(1)定义函数时,定义的形参并不占用实际的存储单元,只有在被调用时系统才给它分配存储单元,在调用结束后,形参所占用的存储单元被释放。
(2)实参的个数与类型应与形参一致,否则将会出现编译错误。
(3)C语言规定,函数间的参数传递是“按值传递”(即单向传递)时,实参可以把值传给形参,但形参的值不能传给实参,也就是说对形参的修改不会影响对应的实参。这是由于在内存中,实参与形参是不同的存储单元,如图5.1所示。
2.按地址传递
按地址传递:函数调用时,主调函数把实参的地址传给被调函数的形参。由于传递的是地址,使得形参与实参共享同一存储单元中的数据,这样通过形参可以直接引用或处理该地址中的数据。(www.chuimin.cn)
图5.1 实参与形参传递示意图
当数组名作为函数参数时,函数传递数据方式采用的是“按地址传递”的方式,但要求形参和相对应的实参都必须是类型相同的数组。我们通过下面的例子来说明按地址传递方式中参数在函数之间的传递。
例5.3 顺序查找。顺序查找是把给定的值与这组数据中的每个值顺序比较。如果找到,就输出这个值的位置;如果找不到则返回一个查找失败的信息。下面是顺序查找的程序。
本程序中使用了一个数组名作为参数。函数seq_search()中形参v没有指定数组的长度,要处理的元素的个数由其后所跟的参数n决定,当然也可以把形参v声明为
int v[SIZE];
但这样在实际应用中并不方便,它使函数seq_search()依赖于具体问题,失去了通用性,所以最好是按程序中那样来写。
C语言中规定,一个数组名代表存放那个数组的内存首地址,所以它实际上是一个地址值。那么传递一个地址值对程序会造成什么影响呢?假定数组d的首地址是2000,则数组d的各元素值顺序地存放在从2000开始的存储单元中,如图5.2所示。
图5.2 数组d的存储形式
当函数seq_search被调用时,将实参d的首地址传给形参v,于是数组v的首地址也变为2000,各元素放置在以2000开始的地址空间中,这样两个数组就共占一段内存单元。如图5.3所示。
图5.3 数组v的存储形式
这样一来,形参数组中元素值的改变就会反过来影响到实参数组。这一点与变量做函数参数的情况是完全不一样的。我们在程序设计的过程中可以利用这个特点来改变实参数组元素的值(如数组的排序)。
有关C语言程序设计 第2版的文章
图5.3程序运行结果说明:定义函数时指定的形参变量在未出现函数调用时,并不占用内存的存储单元。图5.4程序运行结果说明:程序中实参与形参同名,但两者的作用范围不同,程序开始执行时,为主函数中的变量n分配存储空间,实参n 在主函数main()中有效;主函数调用函数s(),有效的是形参n。程序的运行结果表明,当函数调用时,实参的值传送给形参,在被调函数内部,形参的变化不会影响实参的值。......
2023-10-21
不带参数的宏定义一般形式是:#define宏名字符串例如:#definePI3.1415926其中,宏名用标识符表示,也就是前面讨论过的符号常量,上面示例中的PI就是宏名。正确使用“宏定义”的关键是宏调用时的“原样替换”。宏定义使用的简单示例。④宏定义不存在类型问题,它的参数也是无类型的。⑦宏定义允许嵌套。如:#defineN100#defineM2*N#defineK5+M⑧可以用#undef或不带替换字符串的宏定义终止宏定义的作用域。......
2023-11-20
程序的执行过程中,一个函数调用另外一个函数以完成某一特定的功能称为函数调用。如果函数调用出现在一个表达式中,该表达式亦称为函数表达式。函数调用时,实参的值传递到形式参数中就实现了数据由主调函数到被调函数的传递。图5.2swap函数值传递调用时参数的变化情况③控制流程转移到被调函数执行。在设计传值调用函数时,函数的形式参数是普通变量。......
2023-11-20
如果被调函数的形式参数是指针型参数,则主调函数中对应的实际参数就必须是同类型指针值(地址量),这种函数调用参数传递的方式称为传地址值方式。地址值参数传递函数调用示例。在例5.6的程序中,函数调用时将实参a和b的值复制给函数summul的形式参数x和y,实参变量mul将自己的地址传递给指针形式参数v。......
2023-11-20
项目2:输入一行字符,分别统计出其中英文字母、空格、数字和其他字符的个数。图3.15兔子问题输出结果根据以上的分析可以知道,循环次数可以为0,因此该程序是一个条件型循环,可以利用while语句编写程序。熟悉了循环结构在程序设计中的运用,循环结构语句包含了while语句、do…......
2023-11-18
图5.7两层函数嵌套调用示意图函数的嵌套调用即一个函数在被调用的过程中又调用了另外的一个函数。函数fac和powers的返回值类型均被设计为double型,其主要目的是为了避免n!x:0.5//0.5从键盘输入的数据0.50 powers of e=1.648721//程序执行结果......
2023-11-20
C语言把括号、赋值、强制类型转换等都作为运算符处理,灵活使用各种运算符可以实现在其他高级语言中难以实现的运算,功能强大。另外,C语言还把括号、下标、强制类型转换、取地址等都作为运算符处理,并通过与算数运算符的组合达到不同的目的,从而使程序更加简洁明了。C语言具有超强的可移植性。总之,C语言在运算符方面是比较容易让人混淆的。......
2023-11-18
C语言规定,主函数也可以带参数。若主函数带参数,则执行目标程序时,应按下列格式给出相应的实际参数:程序名实际参数1实际参数2…实际参数n此时,系统会自动在内存中开辟区域依次存放程序名和所有的实际参数,同时给主函数的形式参数赋值,结果如下:形参argc赋值为n+1,表示连同程序名在内共有n+1个参数。例7.22编写一个带参数的主函数。注意:程序运行时,在程序名后带有2个整数,程序的功能是输出这2个整数的和。......
2023-11-18
相关推荐