C语言的参数传递机制
关于C语言中参数是如何传递的,ISO/IEC 9899:2018标准第6.5.2.2 Function calls节有这样两段话,原文如下:
In preparing for the call to a function, the arguments are evaluated, and each parameter is assigned the value of the corresponding argument.
A function can change the values of its parameters, but these changes cannot affect the values of the arguments. On the other hand, it is possible to pass a pointer to an object, and the function can then change the value of the object pointed to. A parameter declared to have array or function type is adjusted to have a pointer type as described in 6.9.1.
意思是:
函数调用时,将对实际参数进行评估,每个形式参数将被赋予对应实际参数的值。
函数能够改变形式参数的值,但不会影响实际参数的值。通过指针,函数可以改变指针指向对象的值。声明为数组类型或者函数类型的形式参数将被调整为ISO/IEC 9899:2018标准第6.9.1节描述的指针类型。
这也就是说C语言中参数是按值传递(pass by value)的。
下面通过具体例子讨论一下C语言中参数是如何按值传递的。
|
|
将输出:
Before swap in main function: a=3
Before swap in main function: b=7
Before swap in swap function: A=3
Before swap in swap function: B=7
After swap in swap function: A=7
After swap in swap function: B=3
After swap in main function: a=3
After swap in main function: b=7
下面按程序执行的先后顺序分析一下实际参数、形式参数的存在状态。
程序 执行顺序 |
执行main函数, 初始化实参a、b。 |
调用swap函数。 | 执行swap函数, 交换形参值。 |
swap函数 调用结束。 |
main函数 执行结束。 |
参数 | a(3) b(7) |
a(3) b(7) A(3) B(7) |
a(3) b(7) A(7) B(3) |
a(3) b(7) A(7) B(3) |
a(3) b(7) |
宿主环境中C程序的执行是从main函数开始按顺序执行的;执行实际参数a、b的初始化后,a、b的值分别为3、7;调用swap函数,形式参数A、B值通过对应的实际参数赋值获得;在swap函数中交换形式参数值,A、B中存储的值发生改变;swap函数调用结束,形式参数A、B将不可见;main函数执行结束,实际参数a、b将不可见;所以在这个过程中形式参数值的改变不会影响实际参数值。
|
|
将输出:
Before swap in main function: ptra=0028ff14
Before swap in main function: ptrb=0028ff10
Before swap in main function: a=3
Before swap in main function: b=7
Before swap in swap function: ptrA=0028ff14
Before swap in swap function: ptrB=0028ff10
After swap in swap function: ptrA=0028ff10
After swap in swap function: ptrB=0028ff14
After swap in main function: ptra=0028ff14
After swap in main function: ptrb=0028ff10
After swap in main function: a=7
After swap in main function: b=3
下面按程序执行的先后顺序分析一下实际参数、形式参数及其指向对象的存在状态。
程序 执行顺序 |
执行main函数,初始化实参ptra、ptrb及其指向对象a、b。 | 调用swap函数。 | 执行swap函数, 修改指向对象值。 |
执行swap函数, 交换形参值。 |
swap函数 调用结束。 |
main函数 执行结束。 |
参数 及其指向对象 |
a(3) b(7) ptra(&a) ptrb(&b) |
a(3) b(7) ptra(&a) ptrb(&b) ptrA(&a) ptrB(&b) |
a(7) b(3) ptra(&a) ptrb(&b) ptrA(&a) ptrB(&b) |
a(7) b(3) ptra(&a) ptrb(&b) ptrA(&b) ptrB(&a) |
a(7) b(3) ptra(&a) ptrb(&b) ptrA(&b) ptrB(&a) |
a(7) b(3) ptra(&a) ptrb(&b) |
调用swap函数,形式参数ptrA、ptrB值通过对应的实际参数ptra、ptrb赋值获得,所以ptrA、ptrB的值就是变量a、b的地址;对表达式*ptrA、*ptrB赋值就是对变量a、b赋值;swap函数调用结束后形式参数ptrA、ptrB不可见,但变量a、b仍然存在;通过这种方式函数可以修改指针指向对象的值。
为防止指向对象被意外修改,可以使用const类型限定符对指向对象进行限定。
按值传递对于小型数据特别有效;对于一些大型数据(例如:数组、结构等)可以通过指针的按值传递来提高效率。