目录
一、实验环境
Windows 10 系统
Visual Studio 2019
二、const 简介
C90标准新增了const
关键字,用于限定一个变量为只读。
const的意思是恒常性(constancy),是类型限定符,放在类型说明符前面使用。
格式:const 类型说明符 变量名;
或者:类型说明符 const 变量名;
即const int a和int const a都行,且完全一样。
例如:
const int a = 1;
//const a; 是错误的,const本身不是一种数据类型。
以const关键字声明的对象,其值不能通过赋值或递增、递减来修改。
#include<stdio.h>//这里不加这个头文件也可以,因为没有用啥相关的函数
int main(void)
{
const int a = 1;
const int b[5] = { 0,1,2,3,4 };
a = 2;//报错
b[2] = 5;//报错
return 0;
}
上述代码编译的时候编译器会报错(VS中Ctrl+B是只编译不运行):左值指定const对象。这说明const声明的对象不可修改,所以通常要对const声明的对象初始化,如果不初始化,那不就不能用了嘛。
三、const 的使用场景
1、在指针中使用const
声明普通变量和数组时使用const关键字很简单,但在指针里就有如下考虑:限定指针本身为const 还是 限定指针指向的值为const。
(1) 限定指针指向的值
格式:const 类型说明符 * 变量名;
例如:const int* p,指针p指向一个int类型的const值。
#include<stdio.h>
int main(void)
{
int a[5] = { 0,1,2,3,4 };
const int* p;
p = a;
a[1] = 5;//没有问题
p[1] = 6;//报错
return 0;
}
在p[1] = 6处,编译器报错:左值指定 const 对象。
const int* p:这里的const限定了指针指向的值
,所以不能通过指针修改其指向的值p[1]。但是由于数组a[5]本身没有const关键字限定,所以可以通过数组名a修改数组里的值。这里的指针p不受const限定
,所以可以对p赋值。
(2) 限定指针本身
格式:类型说明符 * const 变量名;
例如:int* const p,指针p是一个const指针。
#include<stdio.h>
int main(void)
{
int a[5] = { 0,1,2,3,4 };
int b[3] = { 5,6,7 };
int* const p = a;
a[1] = 5;//没有问题
p[2] = 6;//没有问题
p = b;//报错
return 0;
}
在p = b处,编译器报错:左值指定 const 对象。
int* const p,这里的const限定了指针本身
,所以指针p在声明后不能再被赋值,记住这时候要对指针p初始化,不然p就不能用了。这里指针p指向的值不受const限定
,所以可以通过指针p修改指向对象的值。
(3) 限定指针指向的值和指针本身
格式:const 类型说明符 * const 变量名;
例如:const int* const p,指针p是const类型,其指向的值也被限定为const。
#include<stdio.h>
int main(void)
{
int a[5] = { 0,1,2,3,4 };
int b[3] = { 5,6,7 };
const int* const p = a;
a[2] = 5;//没有问题
p[2] = 6;//报错
p = b;//报错
return 0;
}
这就是前两个综合起来,不多做解释了。
(4) 小结
上面三种格式中const int都可以替换成int const,只是写法不同,意义完全一样。例如:const int* p和int const *p是一样的。
把const放在 * 左侧任意位置,限定了指针指向的数据不能改变;const放在 * 的右侧,限定了指针本身不能改变。
2、在函数形参声明中使用const
通常主调函数调用其他函数,有时候会向调用的函数传递参数。如果参数是指针或者数组名,则调用的函数可能会因此而修改相应的数据(当然很多时候我们就是希望这样)。有时候为了防止调用函数意外修改数据,我们可以在被调函数的形参声明中使用const进行限定。
例如C语言中strcat()函数原型:
char* strcat(char* restrict s1, const char* restrict s2);
可以暂且忽略关键字restrict。函数strcat()在第一个字符串的末尾添加第二个字符串的副本,这更改了第一个字符串,但是未更改第二个字符串。
3、对全局数据使用const
使用全局变量很容易暴露数据,程序的任何部分都能更改数据。如果把数据设置为const,就可以避免这样的危险。可以创建const变量,const数组,const结构体。
我参考的书中还提到了在文件间共享const数据要注意的问题,也涉及到关键字static。由于我对多文件编程还有疑问,对static也不了解,这里就不做记录了。
四、总结
const的作用就是让变量变成只读,不能更改。主要注意在涉及指针的时候const限定的对象是谁。
在学习的过程中,还发现了一个奇妙的东西
:
#include<stdio.h>
int main(void)
{
const int a = 5;
int* p;
p = (int*)&a;//指针p指向a,p存储的是a的地址
*p = 6;
printf("a = %d\n*p = %d\n\n", a, *p);
printf("a的地址:%p\np的值是:%p", &a, p);
return 0;
}
上面指针p指向了变量a,a是const值不能被修改。但是却通过指针p修改了a的值,5变成了6。我查到的信息是这样的:通过指针修改const值的行为是未定义行为(undefined behavior),这部分的实现由编译器决定,也就是说不同编译器下可能有不同的结果。
我在运行上述代码时,编译器甚至都没有报warning,如果将语句p = (int*)&a去掉强制类型转换变成p = &a,我的环境下编译器也只会报warning C4090: “=”: 不同的“const”限定符。
五、文末声明
-
我学习参考的是书本和网络,文章旁征博引(这是个好词),对引用的部分我都标上了链接,有些遗漏的或者一两句话没标注的,如果侵权万分抱歉,联系我后必删。
-
我写博客旨在监督自己学习,与大家分享学习成果,脚踏实地,一步踩死一个bug。由于本人水平极其有限,文中有出错的地方还请读者批评指正。
-
本文主要参考《C Primer Plus 6th》