###引用和指针

引用

在初始化变量时,初始值会被拷贝到新建对象中。在定义引用时,程序把引用和初始值绑定在一起,而不是将初始值拷贝给引用。

引用并非对象,相反,他只是为一个已经存在的对象七点另一个名字

int i, &ri = i;
i = 5; ri = 10
std::cout<<i<<" "<<ri<<std::endl;

10 10

指针

指针本身是一个对象,允许对指针赋值和拷贝,而且在指针的声明周期内可以先后指向几个不同的对象。

无需在定义时赋初值。

int ival = 42;
int *p = &ival;
cout<<*p;    	// 由符号*得到指针p所指对象,,输出42
double dval;
double *pd = &dval;
int *pi = pd; 	//错误,指针类型不匹配
pi = &dval;		// 错误,试图把double地址赋给int

指针存放在某个对象地址,获取地址使用取地址符&。

指针类型要与指向对象严格匹配

符号多重含义

int i = 42;
int &r = i; 	// 引用,&是声明的一部分
int *p;     	// 指针,*是声明的一部分
p = &i;     	// 取地址符
*p = i;     	// 解引用
int &r2 = *p; 	// &引用,*解引用

赋值和指针

指针和引用都能提供对其他对象的间接访问,但引用本身并非为一个对象,指针可以存放一个新的地址,从而指向一个新的对象

int i = 42;
int *pi = 0; 	// pi被初始化,但没有指向任何对象
int *pi2 = &i;	// pi2被初始化,存有i的地址
int *pi3; 		// pi3定义于块内,则pi3的值无法确定

pi3 = pi2; 		// pi3和pi2指向同一个对象i

pi = &ival; 	// pi值改变,指向ival
*pi = 0;   		// ival值被改变,指针pi并没有改变

一条赋值语句到底改变了指针的值还是改变了指针所指对象的值,赋值永远改变的是等号左侧的对象

int *p
if(p)  	// 判断p是否为nullptr
if(*p)  // 判断p指向的值是否为0

任何非0指针对应的条件值都是true

void* 指针

double obj = 3.14,
double *pd = &obj;
void *pv = &obj;   // 成立,obj可以是任意类型的对象
pv = pd; 		   // pv可以存放任意类型指针

指针和引用的主要区别

  1. 引用是已存在对象的另一个名字,指针本身就是一个对象
  2. 初始化,引用仍然绑定到他的初始对象,无法重新绑定,指针可以分配和复制
  3. 引用始终获取引用最初绑定的对象,单个指针在其生命周期内可以指向多个不同对象
  4. 必须初始化引用,指针在定义时无需初始化

指向指针的指针

int ival =1024;
int *p = &ival;
int **p2 = &p;
cout<< ival<<endl;
cout<< *p <<endl; // 解引用
cout<< **P2 <<endl;  // 解两层引用

指向指针的引用

int i= 42;
int *p;			// p是一个int指针
int *&r = p;    // r是一个对指针p的引用
r = &i;			// 给r幅值&i,令p指向i
*r = 0;     	// 解引用r得到i,p指向i,i值改为0

const

常量引用是对const引用

int i = 42;
const int &r1 = i;		// 合法
const int &r2 = r1;		// 合法
const int &r3 = r1*2;   // 合法
int &r4 = r1 * 2;		// 错误,r4是一个普通非常量引用

指针和const

与引用一样,可以令指针指向常量或非常量。

指向常量的指针不能用于改变其所指对象的值。

const double pi = 3.14;
const double *cptr = &pi;
*cptr = 42; // 错误,不能给*cptr赋值
int i = -1, &r = 0;         // 不合法, r必须引用对象.
int *const p2 = &i2;        // 合法.
const int i = -1, &r = 0;   // 合法.
const int *const p3 = &i2;  // 合法.
const int *p1 = &i2;        // 合法.
const int &const r2;       // 不合法, r2引用不可以是常量
const int i2 = i, &r = i;   // 合法.

顶层const

顶层const指针本身是常量,不能改变本身的值;

底层const指针所指对象是一个常量,可以改变指针指向;

常量表达式

值不会变并且在编译过程中就能得到计算结果的表达式。

const int amx_files = 20;  // 常量表达式
const int sz = get_size(); // 不是常量表达式,在运行后才知道具体数值

constexpr常量

C++11规定,允许将变量声明为constexpr类型,一边用编译器验证

你认定一个变量时常量表达式,就把他声明为constexpr类型

// P是一个指向整型常数的指针
const int *p = nullptr;
// q是一个指向整数的常量指针
constexpr int *q = nullptr;