目录
0.阅读引用
An Insight to References in C++
从汇编层面看引用与指针的关系,也许引用最重要的特点就是比指针安全
1.形参&实参-值传递&指针传递&引用传递
1.1 理论部分
形参和实参的区别:
形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用.
实参出现在主调函数中,进入被调函数后,实参变量也不能使用.
值传递传递的是值,不影响实参的值;
指针传递是可以修改值的,但是有时候它没有修改其指向的内容的值,比如说我们下面的例子当中的
WrongSwap2,虽然传递了指针,但是并没有改变指针指向的内容,所以我们在编码的时候,不但要注
意有没有传递指针,而且要注意在子函数体内有没有正确地根据需求做对应的编码,比如说假设有函
数func(int *a){...},如果需要改变指针所指向的内容的值,在函数体内就要执行【*a = ...】的操作,
否则无法实现对应的功能.
指针传递拥有改变指针指向的值的能力,但是它不一定用了这个能力,比如说WrongSwap2中就没有用这个
能力.
*********************************************
值传递,指针传递,引用传递 的区别
值传递:
从被调用函数的角度来说,值传递是单向的(实参->形参),参数的值只能传入,不能传出
形参为实参的拷贝,形参有单独的内存空间,当函数内部需要修改参数,并且不希望这个改变影响调
用者时,采用值传递.
指针传递:
指针传递向形参传递的为实参的地址,即形参为一个指向实参地址的指针,形参的值为实参的地址,而形
参所在的地址并不是实参的地址,对形参指向内容的修改即改变了实参的值.
引用传递:
引用传递与指针传递不同是:引用传递中形参与实参的地址和参数值都是相同的,形参与实参只是名
字不一样(形参相当于实参的别名),实际上是一个对象.
1.2 值传递与地址传递的一个例子
#include <stdio.h>
#include <string.h>
void WrongSwap1(int a ,int b)
{
printf("In WrongSwap1 : &a = %p, &b = %p ,a = %d,b = %d .\n",&a,&b,a,b);
int temp = a;
a = b ;
b = temp ;
printf("In WrongSwap1 : &a = %p, &b = %p ,a = %d,b = %d .\n",&a,&b,a,b);
}
void RightSwap1(int* a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}
void WrongSwap2(int* a, int *b)
{
int *t;
t = a;
a = b;
b = t;
}
void RightSwap2(int** a,int **b){
int *t;
t = *a;
*a = *b;
*b = t;
}
int main(){
int a = 10;
int b = 20;
printf("a = %d, b = %d .\n",a,b);
printf("value propagation : &a = %p, &b = %p .\n",&a,&b);
WrongSwap1(a,b);// Value propagation
printf("a = %d, b = %d .\n",a,b);
/*
printf("a = %d, b = %d .\n",a,b);
printf("before ptr propagation : &a = %p, &b = %p .\n",&a,&b);
RightSwap1(&a,&b); // ptr propagation
printf("after ptr propagation : &a = %p, &b = %p .\n",&a,&b);
printf("a = %p, b = %p .\n",a,b);
int c = 10;
int d = 20;
int *p = &c;
int *q = &d;
printf("before value propagation : p is %p ,q is %p.\n",p,q);
WrongSwap2(p,q);// Value propagation
printf("after value propagation : p is %p ,q is %p.\n",p,q);
printf("*p is %d ,*q is %d.\n",*p,*q);
RightSwap2(&p,&q); // ptr propagation
printf("after ptr propagation : p is %p ,q is %p.\n",p,q);
printf("*p is %d ,*q is %d.\n",*p,*q);
*/
return 0;
}
1.3 值传递-地址传递-引用传递的一个例子
[muten@localhost 0036-value-pointer-ref]$ ./a.out
值传递,原始值x=3,y=4
值传递,为形参a,b 创建新的空间,在函数中,形参a与b的地址为
0x7ffed4d9c9ac 0x7ffed4d9c9a8
实参x与y地址为
0x7ffed4d9c9dc 0x7ffed4d9c9d8
值传递后实参的值为:
34
指针传递,原始值 x=3, y=4
地址传递,a与b都是指针,对应着地址,没有为形参a,b创建新的空间, 在函数中,形参a与b的地址为
0x7ffed4d9c9dc 0x7ffed4d9c9d8
实参x与y地址为
0x7ffed4d9c9dc 0x7ffed4d9c9d8
指针传递后实参的值为:
43
引用传递,原始值 a=3,b=4
引用传递,a和b都是引用,对应着一个不变的地址,没有为形参a,b创建新的空间,在函数中,形参a与b的地址为
0x7ffed4d9c9d4 0x7ffed4d9c9d0
实参a与b地址为
0x7ffed4d9c9d4 0x7ffed4d9c9d0
引用传递后实参的值为:
43
#include<iostream>
using namespace std;
void ValueTransfer(int a, int b)
{
int temp = a;
a = b;
b = temp;
//cout << a << b << endl;
cout << "值传递,为形参a,b 创建新的空间,在函数中,形参a与b的地址为\n";
cout << &a << ' ' << &b << endl;
}
void PointerTransfer(int *a, int *b)
{
int temp = *a;
*a = *b;
*b = temp;
//cout << *a << *b << endl;
cout << "地址传递,a与b都是指针,对应着地址,没有为形参a,b创建新的空间, 在函数中,形参a与b的地址为\n";
cout << a << ' ' << b << endl;
}
void QuoteTransfer(int &a, int&b)
{
int temp = a;
a = b;
b = temp;
//cout << a << b << endl;
cout << "引用传递,a和b都是引用,对应着一个不变的地址,没有为形参a,b创建新的空间,在函数中,形参a与b的地址为\n";
cout << &a << ' ' << &b << endl;
}
int main()
{
int x = 3;
int y = 4;
cout << "值传递,原始值x=3,y=4\n";
ValueTransfer(x, y);
cout << "实参x与y地址为\n";
cout << &x << ' ' << &y << endl;
cout << "值传递后实参的值为:\n";
cout << x << y << endl << endl;
x = 3;
y = 4;
cout << "指针传递,原始值 x=3, y=4\n";
PointerTransfer(&x, &y);
cout << "实参x与y地址为\n";
cout << &x << ' ' << &y << endl;
cout << "指针传递后实参的值为:\n";
cout << x << y << endl << endl;
int a = 3;
int b = 4;
cout << "引用传递,原始值 a=3,b=4\n";
QuoteTransfer(a, b);
cout << "实参a与b地址为\n";
cout << &a << ' ' << &b << endl;
cout << "引用传递后实参的值为:\n";
cout << a << b << endl << endl;
return 0;
}
2.为什么C++有时推荐使用引用但是不推荐使用指针呢?
引用和指针的不同:
(1)指针在定义的时候可以不初始化,但引用在定义的时候必须初始化;
(2)指针可以为空,引用不能为空;
(3)指针可以改变他的指向的对象,但引用不可以;
(4)引用比指针更安全。由于不存在空引用,并且引用一旦被初始化为指向一个对象,它就不能被改变为
另一个对象的引用,因此引用很安全。对于指针来说,它可以随时指向别的对象,并且可以不被初始化,
或为NULL,所以不安全。const 指针虽然不能改变指向,但仍然存在空指针,并且有可能产生野指针(即
多个指针指向一块内存,free掉一个指针之后,别的指针就成了野指针).
我个人觉得在一些情况下使用引用不使用指针最大的原因就是引用比指针安全.
// 发现是引用,转换为int* const ref = &a
void testFunc(int& ref)
{
ref = 100;// ref 是引用,转换为*ref = 100
}
void test06()
{
// 引用的本质是指针常量,在指针常量中,指针自身的值是一个常量,不可改变,始终指向同一个地址,在定义的同时必须初始化
int a = 10;
int& aRef = a;// 自动转换为int* const ref = &a,是指针常量,也说明为什么必须要初始化
aRef = 20; // 内部发现aRef是引用,自动帮我们转换成*aRef = 20
testFunc(aRef);
cout << "test 06,ref = " << aRef << ",a = " << a << endl;
}