目录
一.概念
指针是“指向”另外一种类型的复合类型,实现了对其他对象的间接访问。指针本身就是一个对象,它是有空间的,它允许对指针赋值和拷贝,而且可以先后指向不同的对象。
int *a;
int b=10;
int *o=b;
二.注意
- 除两种例外的情况:指向常量的指针、指向基类的指针,其余所有的指针类型都要与它所指向的对象类型相匹配。
三.指针值状态
指针的值应该属于下列四种状态之一:
- 指向一个对象。
- 指向紧邻对象所占空间的下一个位置。
- 空指针,意味着指针没有指向任何对象。
- 无效指针,也就是上述情况之外的其他值。
四.指针的使用原理
int a=10;
int *P=&a;
P是一个标识符,这个标识符里通过取地址符(&)存储着a的地址,通过解地址符(*)可以获取地址所存储的值*p。
五.指针的操作
int *val=NULL; //这是c++11以前版本,置指针为空指针的操作,NULL是一个预处理变量,现在已经不推荐使用了
int *val=nullptr; //这是C++11定义的新特性,如今使用的置空指针的操作。
int *val=0; //这个也是置空指针操作
if(val) //判断val如果为空,则不进行下列语句
/...
5.1 指针与数组
string nums[]={"one","two","three"};
string *p=nums; //实际进行的转换 *p=&nums[0];
string *p=&nums[0];
所以由上可知,对于数组的操作实际上是指针的操作,比如:
- auto关键字
int ia[]={0,1,2,3};
auto ia2(ia); //实际进行操作是 ia2(&ia[0]);
ia2=42; //err,因为ia2现在是一个指向ia数组第一个元素的整型指针,而不能给它赋值42这个字面常量值
2.decltype关键字(特殊)
decltype(ia) ia3={0,1,2,3};
ia3=p; //err,因为decltype关键字,不会发生&ia[0]的转换
ia3[4]=10; //true
5.2 指针也是迭代器
迭代器对容器的操作,在指针对数组的操作中也是能做到的,指针也支持使用自增运算符来让指针指向数组的下一个位置的值:
int ok[]={1,2,3};
int *p=ok;
++p; //p指向ok[1];
int *e=&ok[3]; // 获取ok末尾的指针,这个指针指向未知位置,不能取值只能判断
for(int *p=ok;p!=e;++p) //遍历ok数组
{
...
}
六.void* 指针
6.1 概念
void* 指针是一种特殊的指针类型,可用于存放任意对象、任意类型的地址,但是不能对它进行操作,因为你并不知道它存储的是什么类型的对象。
6.2 获取void*指针所存地址
.......
七.VS的指针格式
在VS里指默认的指针格式是int* p=0; 因为在C#里是只允许前放的,在《C++ prime》里推荐使用靠后的方式即int *p=0; 这样是为了区分 * 只是一个修饰符,它并不对后面的变量产生影响,即如果这样写int *p,i; 这样这个i只是int类型,而不是向靠前书写一样会造成i是一个int型指针的误解,要在VS里改变这个指针格式也很简单,就在菜单栏—工具—选项—文本编辑器—C/C++—代码样式—格式设置—间距换行—指针/引用对其方式,里修改即可。
八.指针与引用的复合
阅读一下代码
true:
int i = 100;
int *a = &i;
int **b = &a;
false:
int ***c = &a; // err,因为这时候**c就存储的是a的地址,*c存储的是i的地址,但c此时存储的却不是地址类型,而是i的值。
true:
int *&c = a;
c = &i;
false:
int *&c=&i; // err,因为这时候c是一个int指针类型的引用,而引用有个要求就是引用绑定的对象类型必须与引用类型相同,而这里引用绑定的类型是一串地址,引用本身的类型却是int指针类型,所以是错误的。
int &*c=i; // err,因为引用不是一个对象,不能定义一个指向引用类型的指针,因为它没有分配空间,而指针是一个对象是需要空间的,所以不能这样使用。
true:
*c = 0; // 此时c是a的别名了,对c的操作就是对a的操作
cout << *a << endl;
技巧:可以从右往左读,离变量名最近的符号对变量有直接影响,如上面的int *&c=a;从右往左读,先得到c是一个引用类型,然后再得到它是一个int指针类型的引用。
九.指针和const
9.1 指向常量的指针
指向常量的指针不能用于改变其所指对象的值,要想存放常量对象的地址,只能使用指向常量的指针。同时其左右类型不必相同。
const int a = 10;
const int *o = &a;
int b = 10;
const int *c = &b;
指向常量的指针的变量存储的是对象的地址,但是常量const修饰的是这个int型指针,所以对于这个int型指针的赋值操作不能进行。
int b = 10;
const int *c = &b;
b = 20;
cout << *c << endl; // *c=20;
9.2 const指针(常量指针)
把指针本身定为常量。即:
int a=10;
int *const p=&a;
注意:
- 常量指针必须初始化,而且一旦初始化完成,将不可改变
- 常量指针存储的是指向对象的地址,常量const修饰的是这个变量,而这个变量存储的是地址,所以地址是不能改变的,不过也意味着,这个地址指向的对象的值是可以改变的。
9.3 指向常量的指针和指针常量的区别
1.指向常量的指针和指针常量都可以间接的改变所指向对象的值。
int b = 10;
const int *c = &b; // *c=10;
b = 20;
cout << *c<< endl; // *c=20;
int *const d = &b; //*d=20;
b = 30;
cout << *d << endl; // *d=30
2.指向常量的指针可以修改其所指向的对象,常量指针不能指向其所指向的对象。
int b = 10;
const int *c = &b;
int k = 20;
c = &k; // true, 修改c所指向的对象
int *const d = &b;
int h = 40;
d = &h; // err,不能修改d所指向的对象
3.指向常量的指针不能通过指针来修改所指向对象的值,常量指针可以通过指针来修改所指向对象的值。
int b = 10;
const int *c = &b;
*c = 20; // err,指向常量的指针不能通过指针来修改对象的值
cout << *c<< endl;
int *const d = &b;
*d = 20; //true,常量指针可以通过指针来修改对象的值
cout << *d << endl;
综上,指向常量的指针和指针常量之间的区别主要是看const修饰的内容,const修饰的什么内容,那么这个内容就不能修改。