作为一个C程序员,const是最常用到的关键字之一,当然也是C语言面试最常被问到的经典问题之一。初学者常被这个关键字困扰,也因此在面试时倒在const的石榴裙下。这个关键字也困扰了我很长时间,为了让自己记忆深刻一点,故做了这个学习笔记。
(注:在写本篇学习笔记时,本人学习和参考了网络文章,并做了借鉴,感谢各位前辈的分享。如果本文对您有所帮助,您可以随意分享,如果发现文中有误,也请指教,谢谢。本文用到的调试工具:C-free 5.0,操作系统:Windows 7)
const常见的几种用法可归纳如下:
1、修饰常量;
2、修饰指针;
3、修饰函数参数及其返回值;
4、修饰类的常量及其成员函数;(本文适用对象为C语言,暂按下不表)
1、修饰常量:const int NUM=10; 或者 int const NUM=10;
解释:(1)很多人看到const这个关键字首先想到的就是常量,其实const并不能把变量变成常量,我更喜欢把const理解为“只读”,意思是被const修饰的部分为只读,不能被修改。
由于这里const修饰的是int,意为NUM为一个只读变量,但如果你能取到NUM的地址,人为将NUM的地址修改,这是被允许的。比如:
NUM=20; // 错误,只读常量不可被修改
int * num=#
*num=20; // 允许,这个时候NUM的值被修改为20
看到这里,是不是有一种不怕贼偷就怕贼惦记的感觉,如果你想改变一些事,你总能找到办法。当然,我们只是解释const的作用域,如果你在程序中写出这样的语句,我本人是很不提倡的,如果你想修改这个变量,又何必将其用const修饰,如此大费周章,程序也会让后人维护的时候费解。
(2)const在修饰常量的时候,经常会被拿来与#define对比。比如:
#define PI 3.14
const double Pi=3.14;
说到const和#define的区别,教科书中的记录为:
无参宏不是符号常量,没有数据类型,没有值,在内存中不分配地址,在预处理的时候做宏替换,不会做类型检查;
const定义的常量是符号常量,有数据类型,也有值,在内存中有地址,编译时做类型检查。
说到这里,前辈指点后辈的时候都会语重心长的说:能用const就不要用#define。其实除此之外,const还有个好处,节约内存,如下;
#define PI 3.14 // 使用#define宏
const double Pi=3.14; // 使用const,这时候Pi并没有放入内存中
double a=PI; // 编译时分配内存
double b=Pi; // 在该变量作用域内,第一次出现时分配内存,之后再次出现都不分配内存
double c=PI; // 编译时分配内存
double d=Pi; // 不再分配内存
const定义的常量,系统只为它分配一次内存,而使用#define定义的宏常量,之后的每次出现都会分配内存,由此可见const可以节约不少空间。看到这里,有的朋友表示,八九十年代用C语言抠内存,是因为那个年代内存小,而今非昔比,现在内存白菜价,动辄4G、8G,这样实则没有必要。而我认为,内存优化永远都是系统优化的重中之重,特别是作为并发服务器,积少成多非常明显,更何况,作为一个C语言爱好者,程序的完美轻巧应该是我们永远的追求。
2、修饰指针,看如下几种典型用法:
(1)const int * a=10; // 修饰常量-指向常量的指针
(2)int const * b=20; // 修饰常量-指向常量的指针
(3)int * const c=30; // 修饰指针-常指针
(4)const int * const d=40; // 修饰常量和指针-指向常量的常指针
判断const的作用域,有个小技巧:如果const出现在最左边,则修饰在它右边最近的第一个字符,否则const修饰的是它左边全部的字符。
在这里,(1)和(2)是同等的,都是指向常量,所以:
*a=11; // 错误,常量不可被修改
*b=21; // 错误,常量不可被修改
int n=100; // 声明一个整型变量
a=&n; // 正确,地址可被修改,执行后*a=100
b=&n; // 正确,地址可被修改,执行后*b=100
在这里,(3)是表示常指针,意思是地址不可被修改,如下:
int n=100; // 声明一个整型变量
c=&n; // 错误,地址为只读,不可被修改
*c=100; // 可以,值可以被修改
在这里,(4)为指向常量的常指针,意思是地址和值都不能被修改,所以:
int n=100; // 声明一个整型变量
d=&n; // 错误,地址为只读,不可被修改
*d=100; // 错误,常量不可被修改
3、修饰函数参数及其返回值,如下:
(1)char * strcpy(char * dest, const char * src);
(2)const int fun();
函数(1)对于C语言学习者来说一定不会陌生,const在这里是为了保护源字符串不被修改。在指针或者引用传值的场合,如果想保护源值不被修改,const的出现就非常必要。
函数(2)保护返回值不被修改。有部分学习者认为,接收const的返回值,其接收变量也必须为const修饰,否则会报错,比如:
const int a=fun(); // 正确
int b=fun(); // 错误
但是我在C-free 5.0中,第二种情况并不会报错。或许因为工具版本的问题,这个留下来给各位讨论吧。