const和指针的结合
在定义一个const指针常量的时候,不同位置的const产生的结果也是不同的。
首先我们需要知道,一个普通的指针是不能指向一个常量的地址的:
#include <stdio.h>
int main()
{
const int a = 10;
int* p = &a;
}
上面的代码编译时无法通过的,这是因为a是一个常量,而如果我们把a的地址泄露给了一个普通的指针p,就相当于我们可以通过*p来间接修改a内存的值,这就有违背使用常量的初衷。但我们用一个常指针指向一个普通的变量是允许的。
要定义一个可以指向常量地址的指针,就需要用到const和指针的结合。
const和一级指针结合
const和一级指针的结合有三种方式:
const int *p;
或int const *p;
(这两条代码的效果是一致的)int * const p;
const int * const p;
或int const * const p;
第一种方式的const修饰的是*p,就相当于我们无法再通过 *p来修改 p指向变量的值了,如在上面的代码中,我们要定义指向常量的指针,就可以用这种方式定义。
第二种方式的const修饰的是p,相当于我们无法再改变p的指向,如面向对象编程中的this指针。
第三种方式就是第一种方式和第二种方式的结合。
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a;
const int* p1 = &a;
int* const p2 = &a;
const int* const p3 = &a;
cout << typeid(p1).name() << endl;
cout << typeid(p2).name() << endl;
cout << typeid(p3).name() << endl;
}
上面程序的运行结果中,我们可以看到,第二种方式定义的指针,const和指针的类型是没有关系的,因此,第二种方式定义的指针赋值给一个普通的指针肯定也是可以的。
通过上面的分析我们可以知道:
const int a = 10; int *p = &a;
或int a; const int* p1 = &a; int* p2 = p1;
用一个普通的指针指向一个const修饰的量是不允许的int a; const int *p = &a;
用一个const指针指向一个普通的变量是可以的int a; int* const p1 = &a; int *p2 = p1;
是允许的
const和二级指针结合
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a = 10;
int* p1 = &a;
const int** p2 = &p1;
}
上面的代码能不能编译通过呢?按照我们之前对一级指针的分析, int* p1; const int *p2 = p1;
是允许的,那const int** p2 = &p1;
是不是也可以呢?
答案是不行的:
这里解释以下错误的原因:
二级指针p2涉及三个表达式:p2、*p2、**p2
const修饰的是 **p2,**p2的值不能修改,但是 *p2的值是可以修改的。
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a = 10;
int* p1 = &a;
const int** p2 = &p1;
const int b = 20;
*p2 = &b;
}
分析上面的代码,假设可以编译通过,如果我们把 *p2指向一个常量的地址,那么就可以通过 *p1 修改 常量b的值,也就是把一个常量的地址泄露给了一个普通的指针,这是不允许的。
要使编译可以通过,我们可以这样修改,把p1声明为const int* p1 = &a;
,这样我们就不能通过 *p1修改值了;或者把p2声明为const int* const * p2 = &p1;
这样 *p2就不能被修改,就不会发生上面的错误了。
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a = 10;
const int* p1 = &a;
const int** p2 = &p1;
}
#include <iostream>
#include <typeinfo>
using namespace std;
int main()
{
int a = 10;
int* p1 = &a;
const int* const * p2 = &p1;
}
其他const和二级指针结合的情况可以用和一级指针结合的情况来分析,这里就不再赘述。