C++ 指针和引用

指针与引用都是让你间接引用其他对象
 
解释:
指针:从本质上讲就是存放变量地址的一个变量,在逻辑上是独立的,它可以被改变,包括其所指向的地址的改变和其指向的地址中所存放的数据的改变
例如: int * p = NULL ;声明一个int *类型的指针变量指向空
引用:是一个别名,逻辑上不是独立的,它的存在具有依附性,所以引用必须在一开始就被初始化,而且其引用的对象在其整个生命周期中是不能被改变的(自始至终只能依附于同一个变量)(引用的主要功能是传递函数的参数和返回值)
例如: int m = 0 ; int &n = m;  //n是m的别名,n 既不是m 的拷贝,也不是指向m 的指针,其实n就是m 它自己
 
操作符:
指针用操作符“*”和“->”
引用使用操作符“&”
 
  不存在指向空值的引用这个事实意味着使用引用的代码效率比使用指针的要高。因为在
使用引用之前不需要测试它的合法性。
void printDouble(const double& rd)
{
  cout << rd; // 不需要验证rd为空,它肯定指向一个double
}
 
  指针与引用的另一个重要的不同是指针可以被重新赋值以指向另一个不同的对象。但是引用则总是指向在初始化时被指定的对象,以后不能改变。
string s1("Nancy");
string s2("Clancy");
string& rs = s1; // rs 引用 s1
string *ps = &s1; // ps 指向 s1
rs = s2; // rs 仍旧引用 s1// 但是 s1 的值现在是"Clancy"
ps = &s2; // ps 现在指向 s2; s1 没有改变

  

总的来说,在以下情况下你应该使用指针:
一:    你考虑到存在不指向任何对象的可能(在这种情况下,你能够设置指针为空)
二:    你需要能够在不同的时刻指向不同的对象(在这种情况下,你能改变指针的指向)。如果总是指向一个对象并且一旦指向一个对象后就不会改变指向,那么你应该使用引用。
还有一种情况,就是当你重载某个操作符时,你应该使用引用。最普通的例子是操作符[]。这个操作符典型的用法是返回一个目标对象,其能被赋值。
vector<int> v(10);   // 建立整形向量(vector),大小为 10;
v[5] = 10;      // 这个被赋值的目标对象就是操作符[]返回的值
如果操作符[]返回一个指针,那么后一个语句就得这样写:
*v[5] = 10;
但是这样会使得 v 看上去象是一个向量指针。因此你会选择让操作符返回一个引用。当你知道你必须指向一个对象并且不想改变其指向时,或者在重载操作符并为防止不必要的语义误解时,你不应该使用指针。而在除此之外的其他情况下,则应使用指针。
 
 

★相同点:

  都是地址;

★不同点

  1:引用是变量的一个别名,内部实现是只读指针

  2:引用只能在初始化时被赋值,其他时候值不能被改变,指针的值可以在任何时候被改变

  3:引用不能为NULL,指针可以为NULL

  4:引用必须被初始化,指针可以不用(合法但不安全)

  5:引用变量内存单元保存的是被引用变量的地址(类似指针指向被引用单元)

  6:“sizeof 引用" = 指向变量的大小 , "sizeof 指针"= 指针本身的大小

  7:引用可以取地址操作,返回的是被引用变量本身所在的内存单元地址

  8:引用使用在源代码级相当于普通的变量一样使用,做函数参数时,内部传递的实际是变量地址

 

指针和引用充当函数参数时的区别:

  • 指针传递参数本质上是值传递的方式,它所传递的是一个地址值。值传递过程中,被调函数的形式参数作为被调函数的局部变量处理,即在栈中开辟了内存空间以存放由主调函数放进来的实参的值,从而成为了实参的一个副本。值传递的特点是被调函数对形式参数的任何操作都是作为局部变量进行,不会影响主调函数的实参变量的值。
  • 而在引用传递过程中, 被调函数的形式参数虽然也作为局部变量在栈中开辟了内存空间,但是这时存放的是由主调函数放进来的实参变量的地址。被调函数对形参的任何操作都被处理成间接寻址,即通过栈中存放的地址访问主调函数中的实参变量。正因为如此,被调函数对形参做的任何操作都影响了主调函数中的实参变量。
  • 如果想通过指针参数传递来改变主调函数中的相关变量,那就得使用指向指针的指针,或者指针引用

指针的引用:

int m = 1;
int *p = &m;
int *&rp = p;   //即rp是p的别名

cout << "m的值"<< m << endl;
cout << "&m的值" <<&m << endl;
cout << "p的值" <<p << endl;
cout << "*p的值" << *p << endl;
cout << "&p的值" << &p << endl;
cout << "rp的值" << rp << endl;
cout << "*rp的值" << *rp << endl;
cout << "&rp的值" << &rp << endl;

 

 

 

 

const修饰详解:

  • 常量指针VS常量引用

常量指针:指向常量的指针,在指针定义语句的类型前加const,表示指向的对象是常量。定义指向常量的指针只限制指针的间接访问操作,而不能规定指针指向的值本身的操作规定性。

常量指针定义"const int* pointer=&a"告诉编译器,*pointer是常量,不能将*pointer作为左值进行操作。

常量引用:指向常量的引用,在引用定义语句的类型前加const,表示指向的对象是常量。也跟指针一样不能利用引用对指向的变量进行重新赋值操作。

  • 指针常量VS引用常量

在指针定义语句的指针名前加const,表示指针本身是常量。在定义指针常量时必须初始化!而这是引用天生具来的属性,不用再引用指针定义语句的引用名前加const。

指针常量定义"int* const pointer=&b"告诉编译器,pointer是常量,不能作为左值进行操作,但是允许修改间接访问值,即*pointer可以修改。

  • 常量指针常量VS常量引用常量

常量指针常量:指向常量的指针常量,可以定义一个指向常量的指针常量,它必须在定义时初始化。常量指针常量定义"const int* const pointer=&c"告诉编译器,pointer和*pointer都是常量,他们都不能作为左值进行操作。

而就不存在所谓的"常量引用常量",因为跟上面讲的一样引用变量就是引用常量。C++不区分变量的const引用和const变量的引用。程序决不能给引用本身重新赋值,使他指向另一个变量,因此引用总是const的。如果对引用应用关键字const,起作用就是使其目标称为const变量。即没有:Const double const& a=1;只有const double& a=1;

总结:有一个规则可以很好的区分const是修饰指针,还是修饰指针指向的数据——画一条垂直穿过指针声明的星号(*),如果const出现在线的左边,指针指向的数据为常量;如果const出现在右边,指针本身为常量。而引用本身与天俱来就是常量,即不可以改变指向。

 

posted @ 2022-03-14 15:11  好好看书,天天向上  阅读(81)  评论(0)    收藏  举报