神奇的const,我们研究C、C++经常碰到的一个问题(const的简单用法,不变的函数参数,const int *p,int * const p)这些都是我们所必须要消灭的一点东西。
C++在变量声明使用限定符const
Const用法主要是防止定义的对象再次被修改,定义对象变量是要初始化变量,简单地来讲,就是它把一个对象转化成了一个变量
1,Const与define
在C中,可以使用#define来定义符号常量,例如:
#define PI 3.14159
在C++中,提供了一种更灵活, 更安全的方式来定义关键字const来定义符号常量,例如:
const float PI 3.14159; //PI是一个常量
const int x; //error: 定义常量是应赋值,否则出错
void f(){
PI =40; //error :不能修改常量的值
}
简单地说:用define定义常量后面必须没有分号,并且不要求指出其具体的类型,const定义常量相当于一条语句,后面有分号,并且要求指出其具体的类型(如果没有,C++编译器会默认其为int),还要同时给常量赋值。
(请大家注意:在C++中,
const int a;
int const a;
上面两条语句的实质是一样的,没有区别,完全等价,至于采用哪种写法,完全根据个人习惯)
2, const int * p与int * const p与int const * p
#include <stdio.h>
int main(){
int a=100, b = 200;
const int *p = &a;
int *const q = &b;
printf("a = %d, *p = %d\n", a, *p);
printf("b = %d, *q = %d\n", b, *q);
/*不可使用*p间接的更改变量a的值
*p = b;
*/
/*但是可以将p指针指向另一变量的地址*/
p = &b;
printf("*p = %d\n", *p);
/*不可更改q指针指向另一变量的地址
q = &a;
*/
/*但可以使用q指针间接更改变量b的值*/
*q = 123;
printf("*q = %d\n", q);
return 0;
}
const int *p = &a;
const修饰的是整个*p,所以*p是个常量,是不能被赋值的。
p前面并没有用const修饰,所以p是指针变量,故可以被赋值重新指向另一个内存
int const *p 与 const int *p完全相同,其都是修饰整个*p
int * const q = &b;
q因为有了const修饰,所以q值是不可修改的。
整个*q的前面没有const的修饰,也就是说,*q是变量,所以可以通过*q来修改它所指向内存的值
但是,但是,但是,我们切不可把常量指针赋值给非常量指针,反过来可以
const int * p1;
int * p2;
p1 = p2; //ok
p2 = p1; //error (如果这样的话,会不经意间改变p2所指向的值,来间接的改变p1所指向的值,导致错)
p2 = (int *)p1; //ok,(非要转化的话,我们可以通过强制类型转化啊)
3,const int * const p 与int const *p const与int const *const p;
上面这几种情况,我们一定要注意const各自的位置
对于第一个和第三个他们其实是一样的,所以不用纠结,但是对于第二个(这个写法没有)
#include <stdio.h>
int main(){
int a=100, b = 200;
const int * const p = &a;
//p = &b;
//*p = b;
return 0;
}
对于const int * const p = &a,首先通过第一个const明白*p是常量,
故不可以给: *p赋值, 如:*p = 200;
通过第二个const明白p是常量
故不可以给:p指向另一变量 如: p = &b;
4, const修饰函数
当一个指针送给一个函数后,函数可能修改该指针所指向的变量,然而,如果指针在参数说明段用const修饰,函数就无法修改指针所指向的内容了,
实际上,在C标准库中许多的函数在其参数说明中都使用了const,
basic_string(const basic_string& __str, size_type __pos,
size_type __n, const _Alloc& __a);
上面是在dev-c++中的string源文件中找见的,有兴趣的可以去看看
#include <iostream>
using namespace std;
void print(const float *salary){
*salary = *salary +1; //直接修改了一个常量,编译肯定出错
cout<<*salary<<endl;
}
int main(){
float mysalary;
cin>>mysalary;
print(&mysalary);
return 0;
}
对于上面print函数而言,它的参数是:const float *salary,就意味着*salary不可被随意更改,上面的程序内部更改了这个常量,故编译一定出错
当时一时兴起,将其改为:
*salary++;
cout<<*salary<<endl;
然后编译一直没报错,哈哈,一时之间,想不太懂,后来才想明白了。
因为,对于这个语句,编译器先执行++,就是说它的地址先改变了一下,然后输出了所指向的值,故也是正确的