前言
const关键字是一种修饰符。所谓“修饰符”,就是在编译器进行编译的过程中,给编译器一些“要求”或“提示”,但修饰符本身,并不产生任何实际代码。就 const 修饰符而言,它用来告诉编译器,被修饰的这些东西,具有“只读”的特点。
const对于最终代码没有影响,但是尽可能使用const,将帮助我们避免很多错误,提高程序正确率。
const 变量
1 const 变量指的是,此变量的值是只读的,不应该被改变。
2 如果我们在程序中试图修改 const 变量的值,在编译的时候,编译器将给出错误提示。
3 正因为 const 变量的值在给定以后不能改变,所以 const 变量必须被初始化。(如果不初始化,之后还怎么赋值呢?)如果我们不初始化 const 变量,编译时也会有错误提示。
#include<iostream>
using namespace std;
struct student
{
int math;
int english;
};
int main()
{
// const struct student a1; // 编译错误:未初始化只读变量(与编译器实现有关)
const struct student a2 = {100,100};
printf("math=%d,english=%d\n",a2.math,a2.english);
/* a2.math = 60;
a2.english = 60; 编译错误:不允许修改只读变量
*/
struct student a3 = {60,50};
printf("math=%d,english=%d\n",a3.math,a3.english);
a3.math = 100;
a3.english = 100;
printf("math=%d,english=%d\n",a3.math,a3.english);
return 0;
}
在C中,const 结构体变量表示结构体中任何数据域均不允许改变,且需要另一个结构体变量进行初始化。
指向 const 变量的指针
指向 const 变量的指针,指的是一个指针,其中保存着一个 const 变量的地址。
由于指针指向一个 const 变量,所以通过指针,不能修改这个 const 变量的值。
虽然指针指向的值不能改变,但是指针的指向可以改变。
#include<iostream>
using namespace std;
int main()
{
const int a = 10; // const 变量
int b = 10; // 普通变量
const int *p;
int *q;
p = &a; // 我们让指向 const 变量的指针指向一个普通变量
q = &b; // 让指向普通变量的指针,指向一个 const 变量
*q = 5; // 编译正常
// *p = 5; // 编译出错:位置为只读
return 0;
}
如果指针的类型为“指向const变量的指针”,即使其指向的内容是非const变量,也无法通过这个指针改变数据内容。反之,如果指针的类型是“指向非const变量的指针”,即使指向的是const变量,也可以通过这个指针改变const变量的内容(稍后讨论这一点)。所以,编译器是通过 “指针的类型” 来判断是否只读的。
const 指针
const指针指的是,一个指针本身经过 const 修饰,自身内容(指针指向)不应该发生改变。
指针的指向一经确定,不能改变。指针指向的内容,可以改变。
#include<iostream>
using namespace std;
int main()
{
const int a = 10; // const 变量
int b = 10; // 普通变量
const int *p;
int *q;
p = &a; // 我们让指向 const 变量的指针指向一个普通变量
q = &b; // 让指向普通变量的指针,指向一个 const 变量
*q = 5; // 编译正常
// *p = 5; // 编译出错:位置为只读
return 0;
}
const指针和指向const变量的指针,在写法上容易使人混淆。给大家介绍一种我自己用着比较顺手的区分方法:从右向左,依次结合,const就近结合。
比如,int * const p 可以这样进行解读:
1、int * ( const p ):变量p 经过 const 修饰,为只读变量。
2、int (* (const p)):(const p 现在作为一个整体) 只读变量p是一个指针。
3、(int (* (const p))):(同样的 * const p 作为一个整体) 这个只读的指针p,指向一个int型变量。
于是,可以区分出 int * const p 是一个指向 int 型的const指针。
再比如,const int * p 可以这样解读:
1、const int (* p):变量p是一个指针。
2、(const int) (* p):(const与就近的 int 结合)这个指针指向 const int 型变量。
指向 const 变量的 const 指针
是 const 指针和 指向 const 变量的指针的结合 指针指向不可以改 指针指向的值也不可以更改
const 变量作为函数参数
在函数调用的过程中,函数的参数是建立在函数的栈上的变量。既然是变量,就可以通过 const 进行修饰。
将函数参数声明为 const 类型,表示对于函数来说,这个参数是一个 const 变量。也就是说,函数内部不能够改变这个参数的值。
将函数参数是一个指针,把它声明为 “指向 const 变量的指针” ,允许上层使用 ”指向 const 变量的指针“ 或 普通指针 作为参数,调用函数。(如果参数声明的是普通指针,则不允许使用 指向 const 变量的指针 作为参数调用)(与编译器有关)
#include<iostream>
using namespace std;
// 接收一个int变量,并在函数内部,认为它是只读的
void Int1( const int a )
{
// a = 5; // 编译错误:不允许修改只读变量
printf("a = %d\n", a);
}
// 接收一个int变量,在函数内部,认为它是普通的
void Int2( int a )
{
a = 5; // 正常
printf("a = %d\n", a);
}
// 接收一个 指向const型整形数的指针
void Intp1( const int *a )
{
// *a = 5; // 编译错误:
printf("*a = %d\n", *a);
}
// 接收一个普通指针
void Intp2( int *a )
{
*a = 5;
printf("*a = %d\n", *a);
}
// 主函数
int main( int argc, char *argv[])
{
int a = 10;
const int b = 5;
Int1(a);
Int1(b);
Int2(a);
Int2(b);
Intp1(&a);
Intp1(&b);
Intp2(&a);
// Intp2(&b); // 编译错误:从 const int * 到 int * 转换失败(与编译器有关)
return 0;
}
Intp2函数要求的参数是:指向只读整形的指针。所以,只要调用时传入的参数不是一个指向只读整形数的指针,就会发生类型不匹配。
const 返回值
onst 型的返回值,指的是函数的返回值为一个 const 变量。
函数返回const返回值,主要用于函数返回const引用。
#include<iostream>
#include<string>
using namespace std;
string &output1(string &a)
{
a = "linruimiao";
return a;
}
const string &output2(string &a)
{
a = "linruimiao";
return a;
}
int main()
{
string a;
output1(a) = "linmu";
cout << a << endl;
output2(a);
// output2(a) = "linmu"; //编译错误,返回的引用为 const 引用,不允许修改。
cout << a << endl;
return 0;
}