指针是“指向”另外一种类型的符合类型。
指针和引用的不同点:
- 指针本身就是一个对象,允许对指针赋值和拷贝,而且在指针的生命周期内它可以先后指向几个不同的对象。
- 指针无须在定义时赋值。和其他内置类型一样,在块作用域内定义的指针如果没有被初始化,也将拥有一个不确定的值。
定义指针类型的方法:将声明符写成*d的形式,其中d是变量名。
一条语句中定义了几个指针变量,每个变量前面都必须有符号*:
int *ip1, *ip2;//ip1和ip2都是指向int型对象的指针 double dp, *dp2;//dp2是指向double型对象的指针,dp是double型对象
获取对象的地址
指针存放某个对象的地址,要想获取该地址,需要使用取地址符&:
int ival = 42; int *p = &ival;//p存放变量ival的地址,或者说p是指向变量ival的指针
第二条语句把p定义为一个指向int的指针,随后初始化p令其指向名为inval的int对象。因为不是对象,没有实际地址,所以不能定义指向引用的指针。
double dval; double *pd = &dval;//正确:初始值是double型对象的地址 double *pd2 = pd;//正确:初始值是指向double对象的指针 int *pi = pd;//错误:指针pi的类型和pd的类型不匹配 pi = &dval;//错误:试图把double型对象的地址赋给int型指针
因为在声明语句中指针的类型实际上被用于指定它所指向对象的类型,所以两者必须匹配。如果指针指向一个其他类型的对象,对该对象的操作将发生错误。
指针值
- 指向一个对象
- 指向紧邻对象所占空间的下一个位置
- 空指针,意味着指针没有指向任何对象
- 无效指针,也就是上述情况之外的其他值
利用指针访问对象
如果一个指针指向了一个对象,则允许使用解引用符(操作符*)来访问对象:
int ival = 42; int *p = &ival;//p存放着变量ival得地址,或者说p是指向变量ival得指针 cout << *p;//由符号*得到指针p所指的对象,输出42
对指针解引用会得出所指的对象,因此如果给解引用的结果赋值,实际上也就是给指针所指的对象赋值:
*p = 0;//由符号*得到指针p所指的对象,即可经由p为变量ival赋值 cout << *p;//输出0
为*p赋值实际上是为p所指的对象赋值
空指针
空指针不指向任何对象,在试图使用一个指针之前代码可以首先检查它是否为空,生成空指针的方法:
int *p1 = nullptr;//等价于int *p1=0; int *p2 = 0;//直接将p2初始化为字面常量0 //需要#include cstdlib int *p3 = NULL;
得到空指针最直接的办法用字面值nullptr来初始化指针
把int变量直接赋给指针是错误的,即使int变量的值恰好等会0
int zero = 0; pi = zero;//错误:不能把int变量直接赋给指针
赋值和指针
指针和引用都能提供对其他对象的间接访问,但引用本身不是一个对象,一旦定义了一个引用,就无法令其再绑定到另外的对象,之后每次访问引用都是访问它最初绑定的那个对象。
指针和它存放的地址就没有这种限制了,给指针赋值就是令它存放一个新的地址,从而指向一个新的对象:
int i = 42; int *pi = 0;//初始化,没有指向任何对象 int *pi2 = &i;//初始化,存i的地址 int *pi3;//如果pi3定义于块内,pi3的值无法确定 pi3 = pi2;//pi3和pi2指向同一个对象i pi2 = 0;//pi2不指向任何对象
不容易搞清楚一条赋值语句到底是改变了指针的值还是改变了指针所指对象的值,最好的办法是记住赋值永远改变的是等号左侧的对象。
pi = &ival;//pi的值被改变,现在pi指向了ival
意思为pi赋一个新的值,也就是改变了那个存放在pi内的地址值。相反的:
*pi = 0;//ival的值被改变,指针pi并没改变
则*pi(也就是指针pi指向的那个对象)发生改变
其他指针操作
只要指针拥有一个合法值,就能将它用在条件表达式中。和采用算数值作为条件遵循的规则类似,如果指针的值为0,条件则为false
if (pi)//pi的值是0,因此条件的值是false if (pi2)//pi2指向ival,因此它的值不是0,条件的值是true
总结:任何非0指针对应的条件值都是true。
对于两个类型相同的指针,可以用相等操作符(==)或不等操作符(!=)来比较它们。比较的结果是布尔类型。如果两个地址存放的地址值相同,则它们相同;反之它们不相同。
两个指针存放的地址值相同有三种可能:
- 它们都为空
- 都指向同一个对象
- 都指向同一个对象的下一个地址
注意:一个指针指向某对象,另一个指针指向另外一个对象的下一个地址,此时也有可能两个指针值相同
void* 指针
void*是一种特殊的指针类型,可用于存放任意对象的地址。
double obj = 3.14, *pd = &obj;//正确:void*能存放任意类型对象的地址 void *pv = &obj;//obj可以存放任意类型的对象 pv = pd;//pv可以存放任意类型的指针
利用void*指针能做的事比较有限:拿它和别的指针比较、作为函数的输入和输出,或者赋给另外一个void*指针。
不能直接操作void*指针所指的对象,因为我们并不知道这个对象到底是什么类型,也就无法确定在这个对象上做哪些操作。