C++ Primer 笔记四 初识指针和引用

C++ Primer 笔记四 初识指针和引用


引用
引用是某个已存在对象的别名,实现了对其他对象的间接访问。引用本身不是对象。其定义如下:

int ival = 1024;
int &refVal = ival;

    一般初始化变量时,初始值被拷贝到新建对象中。而定义引用时,程序把引用和它的初始值绑定在一起,一旦初始化完成,将无法把引用重新绑定到另一个对象上,因此引用必须被初始化。
    对引用进行操作,实际上是对引用所绑定的对象进行操作。

refVal = 2048; 			// 实际上是把2048赋值给refVal所绑定的对象ival

// 以引用作为初始值,实际上是把引用绑定的对象作为初始值
int ival2 = refVal; 		// 用ival初始化ival2
int &refVal2 = refVal; 	// refVal2绑定到ival上

    因为引用本身不是对象,所以不能定义引用的引用,且引用只能绑定到对象上,而不能与某个字面值表达式的结果绑定在一起。引用的类型要和与之绑定的对象严格匹配。

double dval = 3.14;

// 下面的操作将引发错误
// error: invalid initialization of non-const reference of type 'int&' from an rvalue of tye 'int'
int &refVal3 = dval;

double &dRef = &dval;
dRef = refVal2; 	// 实际上是将ival的值赋值给dval,执行隐式转化

指针
    指针是指向另外一种类型的复合类型,同样实现了对其他对象的间接访问。不同于引用的是,指针本身就是一个对象。指针的定义如下:

int ival = 44;
int *p1, *p2 = &ival;	// 使用取地址符 & 获取对象的地址

    因为指针本身就是一个对象,所以允许对指针赋值和拷贝,且在指针的生命周期内,指针可以先后指向几个不同的对象,对指针进行赋值就令指针指向了一个新的对象。并且,指针无需在定义时赋初值,块作用域内定义的指针若没有被初始化,将拥有一个不确定的值。
    指针的值是一个地址,且应该是下面4种状态之一:

  1. 指向一个对象;
  2. 指向紧邻对象所占空间的下一个位置;
  3. 空指针,意味着指针没有指向任何对象;
  4. 不属于上面3种情况,为无效指针;

    试图拷贝或者访问一个无效指针都将引发错误,且编译器并不检查此类错误。建议初始化所有的指针,未确定指向对象时应该初始化为nullptr或者0.
    因为引用本身不是对象,没有实际地址,因此不能定义引用的指针。但指针是对象,所有存在对指针的引用。
    指针的类型和它所指的对象严格匹配。把int变量直接赋值给指针是错误的操作,即便int的值恰好为0。

int *iptr = &ival;	// 正确,iptr指向ival
iptr = &ival2;		// 现在iptr指向ival2

// 下面的操作将引发错误
// error: cannot convert 'double' to 'int*' in initialization.
int *iptr1 = &dval;

ival2 = 0;

// 下面的操作将引发错误
// error: invalid conversion from 'int' to 'int*'
int *iptr2 = ival2;
//error: invalid conversion from 'int' to 'int*'
iptr2 = 32;

// OK
iptr2 = 0;

    使用别名可以直接访问引用所绑定的对象,而要访问指针指向的对象,必须使用解引用符(*):

std::cout << *iptr << std::endl;	// 输出iptr指向对象ival2的值
std::cout << iptr << std::endl; 	// 输出iptr指向对象ival2的地址
*iptr = 32; 						// 把32赋值给iptr指向的对象ival2

    空指针表示不指向任何对象,可以使用下面的方法来生成空指针:

int *ptr = 0;			// 直接将指针初始化为字面常量0
int *ptr1 = NULL;		// 等价于 int *iptr1 = 0; 
						// NULL为预处理变量,定义在cstdlib头文件中,NULL的值为0
int *ptr2 = nullptr; 	// C++11引入的方法,nullptr是一个指针字面值

    如果指针拥有一个合法值,则可以将指针用在条件表示式中。任何非0指针对应的条件值都为true

int ival = 1024;
int ival1 = 2048;
int *iptr = 0;
int *iptr1 = &ival;

if (iptr) {	// iptr是空指针,因此条件的值为false
	// TODO
}

if (iptr1) {	// iptr2指向ival,因此条件的值为true
	// TODO
}

    对两个指针进行比较,若存放地址相同,则它们相等;反之不相等。

if (iptr == iptr1) { // 结果为false
	// TODO
}

int *iptr2 = 0;
if (iptr1 == iptr2) {	// 结果为true
	// TODO 
}

    两个指针存放的地址相同,有下面三种情况:

  1. 它们都为空;
  2. 两个指针指向相同的对象;
  3. 两个指针指向同一个对象的下一个地址。

    void*指针是一类特殊的指针,可存放任意对象的地址,其地址的对象的类型是不确定的,因此不能直接操作void*所指向的对象。void*所能进行的操作有:

  1. 和别的指针进行比较;
  2. 作为函数的输入或输出;
  3. 赋值给另外一个void指针。
double dpi = 3.14;
double *dptr = &dpi;

void *vptr = &dpi;	// dpi可以是任意类型的对象
vptr = dptr;		// vptr可以存放任意类型的指针

需要注意的是,void类型既无操作也无值,不能定义一个void类型的变量,因此也不可以有void类型的引用。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值