大多处刚接触程序的小伙伴在学习C/C++的过程中都会遇到函数传值调用,传址调用和传引用的概念,刚开始接触时肯定一时无法理解三者的区别和联系,可能有一部分小伙伴可能学了很长接触很长时间也一直对三者的概念有一定的困扰,以及如何去应用,因为我也有类似的经历。
本文将总结关于传值调用,传址调用和传引用三者的区别,如有不妥之处请私信,我将再次改正;
一.传值调用:
传值调用最早接触应该是在学C语言的阶段,接下来我们将通过一段简单的代码进行解析:
#include <stdio.h>
#include <stdlib.h>
void Swap(int x,int y){
int tmp=x;
x=y;
y=tmp;
}
int main(){
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
Swap(a, b);
printf("a=%d b=%d\n", a, b);
system("pause");
return 0;
}
输出结果为:
为什么交换之后输出的值和之前没有改变??并没有完成交换,因为在传参调用中,main调用swap时候,将实参a, b的值分别拷贝给形参x, y,然后a, b就不再和swap有关了,swap交换的是x, y的值,但是x, y的作用域只在swap中,他们确实完成了交换,但是swap结束之后,x, y的值也就随之销毁了,所以根本不会对行参有任何影响,当然就不会实现实参的交换;
因为在传值调用的过程中实参和形参有不同的内存块,修改形参不会影响实参;即形参是实参的临时拷贝
二.传址调用:
传址调用的过程中把函数外部创建的临时变量的内存地址传递给函数参数,这种调用可以让函数和函数外边的变量建立起联系,函数内部可以直接操作函数外部;
#include <stdio.h>
#include <stdlib.h>
void Swap(int *x, int *y){
int tmp = *x;
*x = *y;
*y = tmp;
}
int main(){
int a = 10;
int b = 20;
printf("a=%d b=%d\n", a, b);
Swap(&a, &b);
printf("a=%d b=%d\n", a, b);
system("pause");
return 0;
}
输出结果为:
函数参数完成了交换,原因是这样的,传址调用实际上还是实参到形参的拷贝,不过这次实参是要交换的两个数字的指针(即地址),而不是要交换的两个数本身,虽然形参在swap结束后被销毁,但是形参是根据要交换的两个数的地址完成交换的,所以对这两个数字产生影响,也就完成交换。
三.传引用调用:
传引用调用是我们在学习C++阶段接触到的知识点,在C语言中是没有的;
#include<iostream>
using namespace std;
void swap(int &x, int &y){
int tmp = x;
x = y;
y = tmp;
}
int main(void){
int a = 10;
b = 20;
printf("a=%d, b=%d\n", a, b);
swap(a, b);
printf("a=%d, b=%d\n", a, b);
system("pause");
return 0;
}
输出结果为:
函数参数完成了交换,但是他的底层实现和以上两种都不相同,传值和传值调用的方式都是形参和实参在不同的内存块,然后进行调用,涉及形参和实参之间的拷贝;但是在传引用的调用过程中并没有涉及到实参和形参,而用的是同一块内存空间,而是直接将main里面的a, b传到swap里面,所以当然交换的就是a, b的值。
传引用调用的原理:
传引用调用过程中,被调函数的形式参数虽然也作为局部变量在堆栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过堆栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的参数变量;
引用传递方式是在函数定义时在形参前面加上引用运算符‘&’。在函数被调用时,参数传递的内容不是实参的值,而是实参的地址,即将实参的地址放到C++为形参分配的内存空间中,因此形参的任何操作都会改变相应实参的值。