C与C++中const用法的区别
C语言
概念
const是一个C语言的关键字,具有着举足轻重的地位。它限定一个变量不允许被改变,产生静态作用。使用const在一定程度上可以提高程序的安全性和可靠性。另外,在观看别人代码的时候,清晰理解const所起的作用,对理解对方的程序也有一定帮助
用法
C中const修饰的变量称作常变量,处理机制是在编译阶段,判断这个常变量是否作为左值,如果作为左值则会报错,除过这个其他处理和变量是一样的。例如下面代码,只有a=20;这一语句会报错,其余语句都是正确的。
int main()
{
const int a;
a = 20;//报错
int *p =&a;
*p = 20;
printf("a:%d\n",a);
return 0;
}
C++语言
概念
const 限定符,它把一个对象转换成一个常量。
用法
C++中const修饰的变量称为常量,即可以将修饰的变量作为数组长度(int arr[a];)处理机制是在编译阶段,把用到常量的地方替换成了常量初始化的数值。
注意事项
- 一定要初始化,如下代码我们通过调试会发现在执行完*p=20;这一行后会显示a的值为20,
但是在我们真正执行后会打印出a:10
会出现这样的原因是因为在C++中被const修饰的变量在编译阶段已经将所有用到a的地方替换为常量10,所以在运行阶段真正运行的是cout<<“a:”<<10<<endl;这一语句,因为我们要在编译阶段将用到的变量进行替换所以一定要进行初始化。
int main()
{
const int a = 10;
int *p = (int*)&a;
*p = 20;
cout<<"a:"<<a<<endl;//cout<<"a:"<<10<<endl;
}
- 杜绝间接访问来修改常量内存的风险
int main()
{
const int a = 10;
//int *p = &a;//报错,杜绝风险
const int *p = &a;//改为这样便正确
*p = 20;
cout<<"a:"<<a<<endl;
}
进行分析可知const修饰a,则直接访问为a,间接访问a都为*p,所以为了杜绝访问修改常量内存的风险,在 *p前面加上const即可。
判断const用法的正确与否
- 根据大小权限的判断,如下代码我们可以发现&a类型为int *,p类型为int *const,这是其中int *权限大于int *const权限也就是我们所说的权限缩小,所以这行代码是正确的。接下来q的类型为int *这是用大权限指向小权限也就是我们常说的权限扩大,这是不允许的,按道理说这行代码会出错。但是,最终结果并没有报错。
int main
{
int a = 10;
int *const p = &a;
cout<<typeid(p).name()<<endl;
int *q = p;
}
接下来我们分析一下,加上typeid§.name()这一行代码获取p的类型。经过打印我们发现p的类型并不是我们所想的int *const,而是如下图所示的int *。
所以当有笔试题出现这样的情况我是不建议去用权限判断来做的。
其实如果我们用C++中const中的第2个注意事项来判断会更加合理些,即杜绝间接访问来修改常量内存的风险,我总结的分析步骤如下:
- 找到const修饰的对象,然后从这行代码往下开始逐句分析。
- 判断const修饰对象的直接访问量。
- 判断对直接访问量的间接访问量。
- 如果间接访问量没有加const修饰我们加上const关键字即可。
接下来我们来分析一下上面的这道例题。
- const修饰对象为p
- 直接访问量为p
- 间接访问量无。因为p为一级指针所以其间接访问量至少要达到二级指针。
通过以上分析我们可以发现并无间接访问来修改常量内存的风险
,所以说代码是正确的。
为了加深印象我们再分析一道例题
int main
{
int a = 10;
int *p = &a;
const int ** q = &p;
//改为const int *const* q = &p或者
//int const* p = &a;
}
- const修饰对象为**q
- 直接访问量为a
- 由于下面没有代码了所以很多人以外没有间接访问量了,其实不然。当前行还包含了一个隐藏的间接访问量*q。
我们通过模拟内存指向可以发现*q=&a,即 *q间接访问了a,所以我们在 *q前面加上const关键字即可。而且我们可以发现 *q=&a与上一行的int *p=&a是一样的所以在 *p前加上const也是可以的。