C语言中,函数传递参数的方式有两种:
1.传值
void Swap(int x, int y)//传值
{
int tmp = x;
x = y;
y = tmp;
}
●以传值方式传递的参数,在函数调用过程中,会在目标函数内生成所要传递参数的临时拷贝(形参),当函数结束时,形参即销毁
●优点:避免了函数调用的副作用
●缺点:无法改变实参的值
2.传址(地址)
void Swap(int* p1,int * p2)
{
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
}
●以传址方式传递的参数,在函数调用的过程中,会直接把实参的地址交给函数,函数就可以直接通过地址来操作实参
●优点:可以直接对实参进行操作
●缺点:不安全
在C++中,结合了上面两种传递参数方式的优点,引入了引用。
●引用不是新定义一个变量,而是给已存在的变量取了一个别名,编译器不会为引用开辟内存空间,它和它引用的变量共用同一块内存空间
●类型& 引用变量名(对象名)=引用实体;
引用变量类型必须与引用实体一致
eg:
void Test()
{
int a = 2;
int &ra = a;
printf("%p\n",&a);
printf("%p\n",&ra);
}
//该程序打印的两个地址完全相同
引用的特性
●引用在定义时必须初始化
void Test()
{
int a = 0;
int ra;//这样书写是错误的,程序不会通过编译
ra = a;
}
●一个变量可以有多个引用
void Test()
{
int a = 0;
int ra = a;
int rb = a;
}
●引用一旦引用一个实体,再不能引用其他实体
void Test()
{
int a = 0;
int b = 1;
int ra = a;
ra = b;//这样书写不代表引用变量去引用b,而是将b的值赋值ra所引用的变量
}
挖掘引用内部的操作方式
用引用的方式交换两个参数的数值
void Swap(int& a,int& b)
{
int tmp = a;
a = b;
b = tmp;
}
int main()
{
int a = 2;
int b = 5;
Swap(2, 5);
return 0;
}
找出它的汇编代码:
函数传递引用时,也是将对象的地址传给函数的参数,当在函数内部用到引用的对象时,程序的底层会自动进行解引用
用传址的方式交换两个参数的数值
void Swap(int* a,int* b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
int main()
{
int a = 2;
int b = 5;
Swap(&a,&b);
return 0;
}
找出它的汇编代码:
对比引用和传址的汇编代码发现它们的汇编代码完全相同
普通类型的引用在底层对应的指针为—>类型名 * const p
指针和引用的区别
●引用在定义时必须初始化;指针可以不初始化
●引用的一生只可以和一个对象相结合;指针则可以根据需要指向不同的对象
●指针+数值=便偏移指针指向;引用+数值=>给引用的对象赋值
●指针无论指向什么对象,在32位平台上sizeof(指针)=4;sizeof(引用)=引用对象所占用的字节
●有多级指针;没有多级引用
●指针需要手动寻址;引用则通过编译器自动寻址
●引用比指针更加安全
传值、传址、引用的效率比较:
●传值过程中,函数会为临时变量开辟新的空间,而传址和引用没有新空间的开辟,所以传值相较传址和引用来讲,它的效率较低
●我们在上面已经看到,传址和引用在底层的操作方法是完全相同的,所以它们的效率应该是相差不大的。