const变量与指向常量的常量指针

C语言中的变量与常量,顾名思义,可变与恒定。

const的存在就是将变量修饰为常量,即让变量变为只读属性。(并不是真的变为常量)

只读的变量

使变量属性变为只读,像常量一样无法通过赋值进行更改。

定义方式:

	const int cnum = 1024;

那么,cnum就是类似常量的只读变量,我们就无法再使用赋值语句对它保存的数据进行更改。

指向常量的指针:

指针本身可以更改指向,但是所指向的变量的数据不可通过解引用的方式更改。

定义方式:

	const int *pc = &cnum; 

const int 为指向整形常量的指针,它可以改变指针pc的存储(就是指针的指向),不可通过解引用改变指针所指数据。

以上我们是使用了指向常量的指针*pc指向了只读的变量cnum。

如果我们这么做:让普通指针指向只读变量,并对其解引用来更改数据。

        const int cnum = 1024;
        int *p = &cnum;

这是一件很矛盾的事情,cnum为只读属性,但是*p为普通指针,是可以通过p更改p所指向变量的数据的。

于是会出现Warning:赋值从指针目标类型中丢弃“const”限定符 。 也就是说出现冲突,const这个限定符号被丢弃了。cnum又变为普通变量。

也就是说,如果我们定义的只读变量不想被指针用解引用的方式进行修改,只能将指针定义为指向常量的指针。

 我们再让const修饰的指针pc指向普通变量:

        int num = 520;
        const int *pc = # 

也就是说指向常量的指针现在指向的不是只读变量,是普通变量,

再次指向*pc = 888;语句,会发生什么?

答案是编译器报错,也即是说,如果指向常量的指针指向了变量num,也不可通过对指针pc解引的方式来改变num的数据。

既然不可以通过解引用改变普通num的值,那么可以直接通过赋值的方式改变num吗?

答案是可以。

总结:const int *pc:会使 通过解引用更改所指数据的方法失效,但是pc存储的地址是可以改变的,即它可指向其它数据。

 如果让指向常量的指针指向了变量,进行解引用更改变量同样是会报错的。

常量指针:

常量指针,顾名思义,就是具有常量属性的指针。一旦定义,它的指向就无法更改的指针。

定义方式:

	int num = 520;
        int *const p = # 

将const写在*后边,指针类型的变量的前面,表示定义的指针变量p为常量指针  它指向的是变量num。

常量指针本身存储地址不可被改变但是它指向的变量是可以改变的,即可以通过解引用来改变所指变量的数据。

既然常量指针可以解引用来改变指向的值,如果我们让常量指针指向一个只读变量,然后使用解引用更改变量的值会怎样? 

        int num = 520;
        int *const pc = &cnum;

        *pc = 111;

 答案是编译器警告,上面我们提到的问题:赋值从指针目标类型中丢弃“const”限定符 , 也就是说const这个限定符号被丢弃了。 由于它指向的变量可以改变数据并被成功更改了,丢弃的const的只能是cnum从而变为可修改常量 。

总结:int *const pc:会使自己更改指向(存储的地址)的功能失效,但是可以对其使用解引用的方法来更该指针指向变量的数据。与const int *p正好相反。

指向常量的常量指针:

本身指向不可被更改,所指也不可被更改(通过解引用)。

定义方式:

        const int cnum = 1024;  
	const int *const pcc = &cnum; 

此种指针类型叫作指向常量的常量指针,结合前两种指针,本身不可更改,所指也不可更改。
 即以下对它的操作都是不合法的:

        *pcc = 520 ;  //报错 
	ppc = #   //报错 

指向指向常量的常量指针的常量指针:

二级指针。

定义方式:

        int num = 520;
        const int *const ccp = #
        const int *const *ccpp = &ccp; //定义指向 指向常量的常量指针 的常量指针ccpp  为二级指针 

指向 指向常量的常量指针 的常量指针为二级指针,所以为其赋值就只能取一级指针的地址给它了,所以我们应该先定义一级指针:指向常量的常量指针;由于定时指针ccpp时与ccp添加条件相同,ccpp具有与ccp相同的约束限制。即都是不能更改自身,所指变量也无法更改。

当需要多个const修饰时就容易记混,可以梳理一下方便理解:

const习惯上放在int*左边,表示指针所指向的int型数据不可通过指针解引用的方式进行修改,此时指针就叫作指向常量的指针。

当const放在int *右边,指针变量名左边,表示修饰的是指针,指针不可被更改,此时指针叫做常量指针。

当两个位置(指针类型及指针类型变量)前面均存在const,代表这个指针两者皆占,即它本身不可被改变,所指向的数据也不可通过指针被改变。

千万不要给乱七八糟的 const 给弄晕了,记住一点:const 永远限制紧随着它的标识符。const int * const *q = &p; 相当于 (const int) * (const *q) = &p;,即第一个 const 限制的是 **q 的指向,第二个 const 限制的是 *q 的指向,唯有一个漏网之鱼 —— q 没有被限制。如果想要使用 const 同时限制 q、*q 和 **q,声明应该写成:const int * const * const q = &p。

请问 const int * const *q; 和 cosnt int const **q; 有何区别?

答:const int * const *q; 限制了 *q 和 **q 的指向,而 cosnt int const **q; 只限制了 **q 的指向。
验证const的完整代码:

指向常量的指针:

#include <stdio.h>

int main()
{
	int num = 520;
	const int cnum = 1024;
	const int *pc = &cnum;  //const int 为指向整形常量的指针 它可以改变指针的存储,不可通过解引用改变指针所指数据。 
//	int *p = &cnum; warning :赋值从指针目标类型中丢弃“const”限定符 , 也就是说const这个限定符号被丢弃了。 
	
	printf("cnum: %d,&cnum: %p\n",cnum,&cnum);
	printf("*pc: %d,pc: %p\n\n",*pc,pc);
	
	pc = &num;   //可以改变指针所指 
	printf("num: %d,&num: %p\n",num,&num);
	printf("*pc: %d,pc: %p\n\n",*pc,pc);
	
//	*pc = 888;  //即使指向了变量num 也不可通过解引用改变num数据
	num = 1024;  //可以直接通过变量来修改变量数据 
	printf("num: %d,&num: %p\n",num,&num);
	printf("*pc: %d,pc: %p\n",*pc,pc);
	
//总结:一旦定义了指向常量的指针,那么该指针只可以修改存储的地址,不可对其解引用来修改所指变量的数据,即使所指是本身可以修改的变量。	
	return 0;
}

常量指针:

#include <stdio.h>

int main()
{
	int num = 520;
	const int cnum = 1024;  //定义属性为只读的变量cnum 
	int *const p = &num;  //将const写在*后边,指针类型的变量的前面,表示定义的指针变量p为常量指针  它指向的是变量num
	int *const pc = &cnum;
	//常量指针本身存储地址不可被改变 但是它指向的变量是可以改变的,即可以通过解引用来改变所指变量的数据。 
	
	*p =  1024;
	printf("*p = %d ,p = %p\n",*p,p);
	
//	p = &cnum;  //常量指针本身的存储的地址不可以被改变 
 	*pc = 111; //编译器警告:赋值从指针目标类型中丢弃“const”限定符 , 也就是说const这个限定符号被丢弃了。 它指向的变量是可以改变并且数据被成功更改了,丢弃的const的只能是cnum从而变为可修改常量 
	printf("*pc = %d ,pc = %p\n",*pc,pc);

//总结:
//定义为const的常量就是成为只读属性。只能由指向常量的指针即const int *p (此种指针只可更改其存储的地址,而不得对其所指的变量数据进行更改)来存储其地址。若由普通指针或常量指针存储其地址,const会丢失
//常量指针 

	return 0;
 } 

指向常量的常量指针:

#include <stdio.h>

int main()
{
	int num = 520;
	const int cnum = 1024;  
	const int *const pcc = &cnum;  //指向常量的常量指针 结合前两种指针,本身不可更改,所指也不可更改。
	
	printf("*pcc = %d ,pcc = %p\n",*pcc,pcc);
	
//	*pcc = 520 ;  //报错 
//	ppc = &num;   //报错 
	cnum = 520; 
	return 0;
 } 

指向指向常量的常量指针的常量指针:

#include <stdio.h>

int main()
{
	int num = 520;
	
	const int *const ccp = &num;  //定义指向普通变量num的常量指针 ccp
	const int *const *ccpp = &ccp;  //定义指向 指向常量的常量指针 的常量指针ccpp  为二级指针 
	 
	printf("*ccp: %d,  &ccp: %p\n",*ccp,ccp);  // 打印出指针ccp的指向的数据以及ccp的地址 
	printf("*ccpp: %p,  **ccpp: %d\n",*ccpp,**ccpp);  //打印出指针ccpp存储的地址 以及 两次解引用取得的数据 

//结果 :成功打印出ccpp指针存储的地址,且与ccp的地址相同。 
//由于定时指针ccpp时添加条件相同,ccpp具有与ccp相同的约束限制。 
 
	return 0;
 } 



 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章