一、const的介绍
在c++中const关键字可以定义常量、修饰指针、修饰函数、类的成员变量和类的成员函数等,本文是关于const修饰变量和指针部分。
在c++中,const修饰的变量变成了真正的常量,在定义时会放入到符号表中,编译器在编译过程中,遇到const修饰的变量时,直接从符号表取出常量的值进行替换。
const变量只有在使用extern声明为全局变量或者使用取地址操作&时,才会分配存储空间。
实例:
#include <iostream>
using namespace std;
int main()
{
const int a = 0;//定义一个const修饰的局部变量
int *p = (int*)&a;//这里使用了&操作,会分配存储空间
//a = 6;//尝试直接修改a的值,编译器报错,a是常量,不能修改。
*p = 5;//a是常量,在c语言中可以通过这种方式修改它的值,一般不建议做这样的操作。
cout << "a=" << a << "," << "*p=" << *p << endl;
return 0;
//输出a=0,*p=5
}
输出结果为:
a=0,*p=5;
为什么c++中通过*p修改了值为5,a的值依然为0呢?
因为代码中使用&操作时,从符号表中取出a的值,并将值存在一个新分配的地址空间里,*p指向的是新分配出来的地址,修改的也只是新分配的地址空间里的值,而a还常量,访问时还是从符号表中取出原来的常量值。
二、const和define宏定义有什么区别
在c++中const修饰的变量值无法被修改,是否感觉和宏定义一样了?但是这两者是不同的。
const修饰的变量在编译时是由编译器处理的,在编译时检查值的类型和作用域,例如const int a = 0,int类型的常量,同时在函数中定义的const常量,作用域只在函数内部。
define修饰的为宏定义,编译时由预处理器进行处理,直接进行文本的替换,不会进行类型和作用域检查。
实例:
#include<iostream>
using namespace std;
void func()
{
#define name "xiaoming" //定义一个宏
const int a = 1;//定义一个局部变量,用const修饰。
}
int main()
{
func();
cout << "name=" << name << endl;//输出name=xiaoming
cout << "a=" << a << endl;//编译报错,因为a的作用域在func内。
return 0;
}
三、const修饰指针
const修饰指针分类两种情况,也是比较容易混淆的。这两种情况分别是:允许修改指针指向的地址中的内容和允许修改指针指的值(指向别的地址)。
3.1允许修改指针指向的地址中的内容(const位于*的右侧)
指针常量,不能修改指针的值,也就值指针指向的地址,但是可以修改指针指向的地址中的内容,常量指针定义是必须初始化,不能指向空。
例如:int *const p = &a;
我们可以这样理解,const修饰的是p,p是个常量,p的值是指向对象的地址,p是常量不能修改,所以不能重新赋别的值给p,也就是不能修改p的指向,类似于引用&。
实例:
#include<iostream>
using namespace std;
int main()
{
int num1 = 1, num2 = 2;
int * const p = &num1;//常量指针
//p = &num2;//错误,不能修改p的值。
*p = 10;//这个是允许的,修改的是p指向的地址中的内容,也就是*p
cout << "num1=" << num1 << endl;//输出num1=10
return 0;
}
3.2允许修改指针指向的地址(const位于*左侧)
常量指针,const修饰指针指向的对象是个常量,不能修改该对象的内容,但是可以修改指针指向别的对象。
例如:const int *p。
我们可以这样理解,const修饰的是*p,而*p是指p指向的地址的内容,所以表示内容是常量,而p是可以修改的。
实例:
#include<iostream>
using namespace std;
int main()
{
int num1 = 1, num2 = 2;
const int *p = &num1;//指针常量
//*p = 3;//错误,不能修改*p的值,*p是常量。
p = &num2;//这个是允许的,修改的是p,p指向别的对象地址。
cout << "*p=" << *p << endl;//输出*p=2
return 0;
}
四、总结:
const修饰指针时,主要看const在*的左边还是右边,决定是指针常量还是常量指针。