四、void*指针
void* 指针是C++提供的一种特殊的指针类型,他可以保存任何类型对象的指针:
double obj = 3.14;
double *pd = &obj;
void *pv = &obj;
pv = pd;
以上关于void* 指针 pv 的定义都是合法的。
void* 表明该指针与一地址值相关,但不清楚存储在此地址上的对象的类型。
void* 指针只支持几种有限的操作: 与另一个指针进行比较;向函数传递 void* 指针或从函数返回 void* 指针; 给另一个 void* 指针赋值。 不允许使用 void* 指针操纵它所指向的对象。
五、指针和引用的比较
指针和引用(reference)都可间接访问一个值,但他们之间有2个重要区别:
1. 引用总是指向某个对象:定义引用时没有初始化是错误的。
2. 赋值行为的差异:给引用赋值修改的是该引用所关联的对象的值,而并不是使引用与另一个对象关联。引用一经初始化,就始终指向同一个特定对象。
给出以下例子说明:
#include <iostream>
using namespace std;
int main(){
int ival1 = 1024, ival2 = 2048;
int *pi1 = &ival1, *pi2 = &ival2;
cout << ival1 << endl;
cout << ival2 << endl << endl;
cout << *pi1 << endl;
cout << *pi2 << endl << endl;
cout << pi1 << endl;
cout << pi2 << endl << endl;
pi1 = pi2;
cout << ival1 << endl;
cout << ival2 << endl << endl;
cout << *pi1 << endl;
cout << *pi2 << endl << endl;
cout << pi1 << endl;
cout << pi2 << endl << endl;
pi1 = &ival1;
int &ri1 = ival1, &ri2 = ival2;
ri1 = ri2;
cout << ival1 << endl;
cout << ival2 << endl << endl;
cout << pi1 << endl;
cout << pi2 << endl << endl;
return 0;
}
上面代码输出如下:
注意到,当执行
pi1 = pi2;
后,pi1 指向的对象不再是 ival1, 而是 ival2。
之后执行的代码
cout << *pi1 << endl;
cout << *pi2 << endl << endl;
cout << pi1 << endl;
cout << pi2 << endl << endl;
验证了这一点。无论是 *pi1 还是 *pi2, 输出的也是 ival2 的值。 而 pi1, pi2存储的也是 ival2 的地址。
但对于引用 ri1 和 ri2,当执行代码
int &ri1 = ival1, &ri2 = ival2;
ri1 = ri2;
后,ival1 的值就变成了 ival2的了。
ri1 绑定的对象是 ival1, 当对 ri1 进行赋值, 那并不会使得 ri1 解除对 ival1 的绑定,反而是使得 ri1 绑定的对象 ival1 的值被修改。
之后的代码也验证了这点。
cout << ival1 << endl;
cout << ival2 << endl << endl;
cout << pi1 << endl;
cout << pi2 << endl << endl;
通过检查 pi1 和 pi2 的输出, ival1 的地址并没有改变,改变的只是该地址上存储的内容。
六、指针的指针
指针本身也是可用指针指向的内存对象。指针占用内存空间存放其值,因此指针的存储地址可存放在指针中。下面程序段:
int ival = 1024;
int *pi = &ival;
int **pi = π
定义了指向指针的指针。 C++ 使用 ** 操作符指派一个指针指向另一个指针, 即 pi 的内存空间存储了 ival 的地址, 而 ppi 的内存空间则存储了 pi 的地址。图示可表示如下:
在这里注意一点,假如一个指向 “指针的指针”的指针,那如何定义呢? 用 *** 符号?
答案是 是的
如下对指针的定义是合法的:
int ival = 1024;
int *p1 = &ival;
int **p2 = &p1;
int ***p3 = &p2;
可能有人会认为, p2 其实也是一个指针, 那 p3 假如要指向 p2, 那 p3 应该就是一个指向指针的指针, 用 ** 符号能够操作正确,那我们执行下面定义
int **p3 = &p2;
程序编译会提示如下错误:
&p2 是一个 int*** 类型, 他无法被转换为 int** 类型;
那么,执行如下代码呢?
#include<iostream>
using namespace std;
int main(){
int ival = 1024;
int *p1 = &ival;
int **p2 = &p1;
int ***p3 = &p2;
int **p4 = (int**) &p2;
cout << p3 << endl;
cout << p4 << endl << endl;
}
输出结果如下:
从输出结果可见, p3 和 p4 均存储了 p2 的地址, p4 的类型是 int**, 但这里用到了强制类型转换
这个过程看似可以,可假如要通过 p4 取 ival 的值,那应该 *(*p4) 还是 *(*(*p4)) ?
执行如下代码:
cout << *(*p4) << endl;
cout << ival << endl;
输出结果如下
可见, *(*p4) 并不能获取 ival 的值。实际上,通过以下执行以下代码:
cout << p1 << endl;
cout << hex << *(*p4) << endl;
输出如下:
可见,实际上 *(*p4) 输出的是 ival 的地址, 而不是 ival 的值。
要获得 ival 的值, 应该执行以下代码:
cout << *((int*)(*(*p4))) << endl;
先将 *(*p4) 结果 强制转换成 (int*) 类型后再解引用。
另外,假如执行
cout << *(*(*p4)) << endl;
则会直接提示错误
因为 p4 并不是一个 int*** 型