天天看點

指針常量和指向常量的指針

首先,我們從const 說起。

const 有兩種寫法格式:const int n=20 和 int const n=20,它們相同嗎?毫無疑問它們是相同的,這點務必記住。總之記住const 和 int 哪個放前面哪個放後面沒關系,都是一樣的。有了這個概念後,我們再來看const int *p 和int const *p,按照你的了解它們相同嗎?其實它們也是相同的,還是那句話int 和const的前後位置不影響語義。好了,到現在我們明白了這一對的關系,那麼int * const p 和它們相同嗎?下面我們具體分析它們的語義。

一、const int *p的語義(當然int const *p也是一樣的)

下面先看一個例子:

//********代碼開始*******
int a=30;
int b=40;
const int *p=&a;
p=&b;			//1、注意,p可以重新指派一個新記憶體位址
b=80;			//2、想想看,這裡能用*p=80;來代替嗎?當然不能
printf("%d",*pi);//3、輸出是80
//********代碼結束*******
           

語義分析:從這個例子中不難看出,p的值可以被修改,即它可以重新指向另一記憶體位址。但是不能通過*p來修改b的值。為什麼呢?

首先,const修飾的是整個*p(注意我寫的是*p不是p),是以*p是常量,是不能被指派的(盡管p所指的b是變量,不是常量)。

其次,pi前沒有被const修飾,是以p是指針變量,即能被指派重新指向另一記憶體位址。

二、int *const p

下面還是先看一個例子:

//********代碼開始*******
int a=30;
int b=40;
int *const p=&a;
//p=&b;				4、注意,p不能再這樣重新指派了,即不能再指向另一個新位址。
a=80;				//5、想想看,這裡能用*p=80;來代替嗎?可以,這裡可以通過*p修改a的值
printf("%d",*pi);	//6、輸出是80
//********代碼結束*******
           

語義分析:從這段代碼有沒有發現,pi的值不能重新指派修改了。它隻能永遠指向初始化時的記憶體位址。相反,這次你可以通過*p來修改a的值了。看下面的分析:

首先,p因為有了const的修飾,是以隻是一個指針常量。也就是p不能修改了,即p不能重新指派指向b了(如第4行)

其次,整個*p的前面沒有const的修飾,也就是說*p是變量而非常量。是以我們可以通過*p來修改它指向記憶體a的值(如第5行的注釋)

是以我們可以發現,p是指向int變量類型資料的指針常量。

最後總結兩句:

1)如果const放在*p前,則不能修改的是*p(即不能這樣 *p=80)而不是指p;

2)如果const放在p前,則p不能修改(即不能p=&b)

三、補充三種情況

情況一:int *p指向const int i常量的情況

//********代碼開始*******
const int i=30;
int *p;
p=&i;	//可行嗎?不行,const int類型的i的位址是不能指派給
		//指向int類型位址的指針的,否則p豈不是可以修改i的值了嗎
//********代碼結束*******
           

我自己試了,雖然有警告,但是可行,而且可以利用p來修改i的值。如*p=100。(當然直接修改i的值肯定不行)是以為了避免我們可以把指針定義為const int *p

情況二:const int *p指向const int i常量的情況

//********代碼開始*******
const int i=30;
const int *p;
p=&i;	//兩個類型相同,可以這樣指派。
		//很顯然,i的值無論是通過p還是i都是不能修改的
//********代碼結束*******
           

情況三:用const int *const p申明的指針

//********代碼開始*******
int i=30;
const int *const p;
p=&i;	//你能想象p能夠做什麼操作嗎?p值不能改,
		//也不能通過p的值修改i的值。因為不管是*p還是p都是const的
//********代碼結束*******