学了四年的计算机,一直让自己比较苦恼的问题是C语言的参数传递问题,之所以说是苦恼,是因为在某年的一个学期,不幸接触到数据结构,光一个链表就把自己弄得死去活来的,而且自已一直就楞以为在操作的过程中,传递参数的指针也在发生变化,结果可想而知,数据结构成了自己专业课里面险些挂彩的一门课程。
直至最近,拿出数据结构打算恶补一下前些年欠下的债,第一件事情,还是先解决好当时困扰自己半年之久的C语言参数传递问题吧。
C语言课堂上,自己明明记得参数传递问题我已经搞懂了,只不过当时没有接触过C plus plus,所以除了值传递和地址传递,我就根本不知道还有一种引用传递。现在想起来,自己那时候学的还是马马虎虎,太过自信认为自己已经完全掌握参数传递的实质。闲话少说,直入正题。
C语言中,函数参数传递有三种形式:值传递、地址传递和引用传递。
弄懂C语言参数传递之前,我们先要清楚以下几个概念:函数参数中的形式参数和实际参数
首先定义上面
形式参数:形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用。 实际参数:实参出现在主调函数中,进入被调函数后,实参变量也不能使用。
形参和实参的功能是作数据传送。发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送。
函数的形参和实参具有以下特点:
1. 形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能再使用该形参变量。
2. 实参可以是常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须具有确定的值,以便把这些值传送给形参。因此应预先用赋值,输入等办法使实参获得确定值。
3. 实参和形参在数量上,类型上,顺序上应严格一致,否则会发生类型不匹配”的错误。
4. 函数调用中发生的数据传送是单向的。即只能把实参的值传送给形参,而不能把形参的值反向地传送给实参。 因此在函数调用过程中,形参的值发生改变,而实参中的值不会变化。
对于函数参数值传递形式,其参数传递的过程是:
(1)行参与实参各占一个独立的存储空间。
(2)行参的存储空间是函数被调用时才分配的。调用开始,系统为行参开辟一个临时存储区,然后将各实参之值传递给行参,这时行参就得到了实参的值。
(3)函数返回时,临时存储区也被撤销。
传值的特点:单向传递,即函数中对行参变量的操作不会影响到调用函数中的实参变量。
示例:
#include <stdio.h>
以下为值传递的被调函数
void change_by_value( int x ){
//函数change_by_value接受的参数即为形参 x = x + ; //x的值为13,但其值的变化不会影响到a的值
}
主函数,调用被调函数并输出
int main(){
int a = ;
printf( " a = %d\n" , a );
change_by_value( a ); // 此时的a作为实参传递给函数
printf( "a = %d\n",a ); //a的值并没有改变
return 0; }
程序的输出为:
a = 3 a = 3
void change_by_value(int x)内部发生的动作应当是当函数被调用时(堆栈调用)在堆栈上临时分配了一块区域,调用结束,出栈。其详细解释如下:
void change_by_value( int x ){
int _x = x; //拷贝一份传递给临时变量_x
_x = _x + ; //改变的是_x,不是x
}
对于函数参数地址传递形式,其原理和值传递方式一样,当调用函数时也要为形式参数分配内存,被调函数执行完毕后也要回收内存。不同的是:地址传递传递的是实参变量地址的拷贝值,而不是实参变量的值。被调函数中对地址所指对象的操作会改变实参的值。例如:
#include <stdio.h>
以下为地址传递的被调函数
void change_by_address( int *x ){
*x = *x + ;
}
主函数,用于调用被调函数
int main(){
int a = ;
printf( "a = %d\n", a );
change_by_address( &a ); //如果定义的不是指针变量或者数组,变量名前要加上取址符号
printf( "a = %d\n", a );
return ;
}
程序输出为:
a = a =
地址传递方式:参数是地址
void change_by_address( int *x ){
*x = *x + ;
}
实参和行参共享一个存储单元,对行参的操作相应的就改变了实参,此时参数传递是双向的。
小结:
值传递:作为参数的变量,传递给函数执行后,自己的变量值是不变的。它(实参)仅仅只是把值赋给了形参,自己实际上是没有参与函数运算的,参与的是形参,这个就是参数的值传递。值传递好比是你把文件复制一份,通过网络传给他,然后他可以在他本机上对文件做任何的修改,修改会保存下来,但是你机器上的文件不会发生任何的变化。即形参与实参是两个不同的变量,各自占用不同的存储单元。
地址传递:地址传递跟值传递也没有什么不同,值传递是把变量的值传递给形参去参与函数运算,而地址传递则把变量的地址传递给形参去参与函数运算。当然,如果函数改变了变量地址的值,实参的值也会变化的。地址传递好比是你把文件在网络上的地址告诉他人,他人通过网络访问你机器上的文件,他可以对文件进行修改并保存,此时,文件的内容就会发生变化。即形参与实参是相同的变量,占用同一段内存空间。