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 = # //可以改变指针所指
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 = # //将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 = # //报错
cnum = 520;
return 0;
}
指向指向常量的常量指针的常量指针:
#include <stdio.h>
int main()
{
int num = 520;
const int *const ccp = # //定义指向普通变量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;
}