c语⾔参数传递机制优缺点,C语⾔中的参数传递机制详解
本⽂尝试讨论下C中实参与形参的关系,即参数传递的问题。
C语⾔的参数传递
值传递
⾸先看下列代码:
编译后执⾏结果如下:
可以看到,在调⽤函数 change 时,会在内存中单独开辟⼀个空间⽤于存放形式参数 i ,实参 n 的值会复制给形参 i 。对于形参的任何操作都不会影响到主调函数中的实参 n 。这种参数传递⽅式是便是典型的值传递。
上例中的参数类型是int型,实际上,对于整形(int、short、long、long long)、浮点型(float、double、long double)、字符型(char)等基本类型的参数都是值传递。
指针参数
在下⾯的例⼦中,函数的参数类型是⼀个指针:
编译后执⾏结果如下:
指针是C语⾔中的⼀种特殊类型,它本⾝占⽤⼀定的内存空间,⽽存储的值却是某个内存地址。上例中,函数change的参数是指向int型变量的指针,实参p是指向变量n的⼀个指针,在调⽤函数change时,指针型的形参i也会得到⼀块内存空间,其值由实参p复制⽽来,都是主调函数中变量n的地址。对于指针类型,⼀般不会太关注其本⾝⽽更多的是考虑它所指向的值,所以,在change函数内是通过指针来操作指针所指的内容(主调函数中的变量n)。这样,便实现了在被调函数内操作主调函数中数据的效果。
虽然通过指针型参数传递可以达到让被调函数内的操作作⽤于主调函数内数据的效果,但从实参和形参的⾓度来看,这种参数传递并没有和⼀般的传递⽅法有什么本质的区别,也是值传递⽅式。
当参数传递⽅式是值传递时,形参和实参都存储在各⾃的内存空间中,相互独⽴互不影响,它们之间唯⼀的联系便是在形参初始化时会使⽤实参的值。
数组参数
在C语⾔中,数组名可以看作⼀个指向数组⾸元素的指针常量,那么当数组作为参数是⼜是如何传递
呢?实际上,当函数形参是数组类型时,作为形参的数组名便不再代表数组,⽽是被编译器解析成⼀个指针。通过下⾯的例⼦可以看出,数组类型的形参只是在函数签名中看上去是⼀个数组,但在函数体内,它已经彻底沦为⼀个指针。
结构体数组不能作为参数传递给函数编译后执⾏结果如下:
可以看出,虽然形参arr被声明为int型数组,但在函数内部,arr已不再拥有数组的性质,⽽拥有了指向int型的指针的性质:
arr的⼤⼩是指针的⼤⼩(8),⽽⾮数组的⼤⼩(数组的⼤⼩是所有元素⼤⼩的总和,上例中:4×3=12)
arr可以被修改,⽽数组名不可以被修改
arr与a的内存地址不同但值相同(都是数组⾸元素地址),所以,在函数被调⽤时,真正被传递的值是数组⾸元素的地址,并以此地址初始化了⼀个指向实参数组⾸元素的指针作为形参。因为实际的形参是⼀个指针,所以这种情况也是属于值传递。同时,与指针参数效果⼀样,在函数内对“数组”的修改会直接作⽤于外部。
由此我们看到,数组作为参数与指针作为参数并没有什么区别,因为编译器会⾃动将形参中的数组名转换为⼀个指针。所以,以下⾯代码中的两个函数签名是等效的:
实际上,如果我们同时定义了它们,编译器会报“redefinition”错误⽽⽆法编译。
此外需要注意的是,虽然我们可以将形参声明成⼀个数组,但在编译器看来它只是⼀个指针⽽已,因此形参中有关数组长度的信息会被⾃动忽略,在实际调⽤时实参数组的长度与形参指定的数组长度没有任何关系,⽽且在函数内也⽆法通过 sizeof(arr)/sizeof(arr[0]) 得到数组的长度。
⾃定义类型参数
数组这种“组合”类型在作为参数传递时被解析为指针⽅式传递,那么当结构体(struct)、共同体(union)以及枚举类型作为参数传递时是否也是如此呢?
枚举类型本质上是int,所以当形参被声明为枚举类型时,在编译器看来就是int型,以下⾯代码中的两个函数签名是等效的,编译器会
报“redefinition”错误:
下⾯是结构体和共同体分别作为参数时的⽰例:
编译后运⾏,输出如下:
我们发现,C中的⾃定义类型作为参数传递时,和基本类型⼀样,也是按值传递。
⼩结
C语⾔中,参数类型为字符型、整型、浮点型以及枚举型、结构体(struct)和共同体(union)时,都是常规的值传递。⽽指针作为⼀种特殊的类型,其值为⼀个地址,所指向的基类型可以任意其他类型(包括void)甚⾄可以指向函数,所以,指针作为参数时虽然本质上属于值传递,但因为传递的是⼀个地址,可以让被调函数通过对指针所指内容的操作直接作⽤于外部数据,属于参数传递中特殊的值传递⽅式。虽然可以把形参声明为数组,但实际的形参却是指针,因此,数组作为参数的传递⽅式也是特殊的值传递。
我们通过依次考察C语⾔中各种数据类型发现: C语⾔中只有值传递!

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。