C语言:const简介与使用方法

一、实验环境

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”限定符。

五、文末声明

  1. 我学习参考的是书本和网络,文章旁征博引(这是个好词),对引用的部分我都标上了链接,有些遗漏的或者一两句话没标注的,如果侵权万分抱歉,联系我后必删。

  2. 我写博客旨在监督自己学习,与大家分享学习成果,脚踏实地,一步踩死一个bug。由于本人水平极其有限,文中有出错的地方还请读者批评指正。

  3. 本文主要参考《C Primer Plus 6th》

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值