指针的定义
指针是"指向"另外一种类型的复合类型, 实现了对其他对象的间接访问, 然而指针与引用有很多不同点:
- 指针本身就是一个对象, 允许对指针赋值和拷贝
- 在指针的声明周期内它可以先后指向几个不同的对象
- 指针无需在定义时赋初值. 在块作用域内定义的指针如果没有被初始化, 也将拥有一个不确定的值
定义指针的方法
- 将声明符写成
*d
的形式, 其中d
是变量名. - 如果在一条语句中定义了几个指针变量, 则每个变量前面都必须有符号*
int main(){
int *ip1, *ip2;
double dp, *dp2; // dp 是 double 型的对象, dp2 是指向double型对象的指针
return 0;
}
获取对象的地址
- 指针存放某个对象的地址, 要想获得该地址, 需要用到 取地址符
&
.(不加取地址符会报错)
int main(){
int ival = 42;
int *p = &ival;
cout << p <<endl; // p 是指向对象的地址
cout << *p << endl; // *p 是指向的对象
return 0;
}
输出如下
执行完成,耗时:0 ms
0x7ffe95bfab40
42
- 引用不是对象, 没有实际地址, 所以不能定义指向引用的指针.
- 指向指针的指针, 例子如下
int main(){
int ival = 42;
int *p1 = &ival;
int *p2 = p1; //正确: 初始值是指向int对象的指针
cout << *p2 << endl;
return 0;
}
输出如下
执行完成,耗时:0 ms
42
指针值
指针的值应该属于下列四种状态之一
- 指向一个对象
- 指向紧邻对象所占空间的下一位置
- 空指针, 不指向任何对象
- 无效指针, 即除上述情况的其他值
利用指针访问对象
- 如果指针指向了一个对象, 则允许使用 解引用符
*
来访问该对象.
int main(){
int ival = 42;
int *p = &ival;
cout << *p << endl;
return 0;
}
输出为: 42
- 给解引用的结果赋值, 实际上也就是给指针所指的对象赋值.
int main(){
int ival = 42;
int *p = &ival;
*p = 30;
cout << *p << endl;
return 0;
}
输出为: 30
3. 解引用操作仅适用于那些确实指向了某个对象的有效指针
空指针
以下列出几个生成空指针的方法
int main(){
int *p1 = nullptr;
int *p2 = 0;
// 需要先 #include cstdlib
int *p3 = NULL;
return 0;
}
赋值和指针
- 指针和引用的区别: 引用本身并非对象, 一旦定义了引用就无法令其再绑定到另外的对象. 指针和它存放的地址之间就没有这种限制了. 给指针赋值就是令它存放一个新的地址, 从而指向一个新的对象.
- 区分: 一条赋值语句改变了指针的值还是改变了指针所指对象的值
方法: 赋值永远改变的是等号左侧的对象
int main(){
int i1 = 42;
int i2 = 21;
int *pi = &i1;
cout << *pi << endl;
pi = &i2; // pi的值被改变, 现在pi指向i2
cout << *pi << endl;
*pi = 0; // i2 的值被改变, 指针 pi 并没有改变
cout << *pi << endl;
return 0;
}
输出为:
执行完成,耗时:0 ms
42
21
0
其他指针操作
- 只要指针拥有一个合法值, 就能将他用在条件表达式中.
- 如果指针的值是 0, 条件取
false
. - 任何非 0 的指针对应的条件都是
true
.
int main(){
int ival = 1024;
int *pi1 = 0;
int *pi2 = &ival;
if(pi1){
cout << "pi1的值不为0" << endl;
}else{
cout << "pi1的值为0" << endl;
}
if(pi2){
cout << "pi2的值不为0" << endl;
}else{
cout << "pi2的值为0" << endl;
}
}
输出如下
执行完成,耗时:0 ms
pi1的值为0
pi2的值不为0
void* 指针
void*
是一种特殊的指针类型, 可用于存放任意对象的地址- 不能直接操作
void*
指针所指的对象, 因为我们不知道这个对象是什么类型的. - 以
void*
的视角来看内存空间也就仅仅是内存空间, 没办法访问内存空间中的所存的对象.