本文共 4675 字,大约阅读时间需要 15 分钟。
const关键字在C语言中具有重要作用,主要用于限定变量、数组、函数参数和返回值等,使其成为只读数据,防止意外修改。以下将从多个维度解析const的用法及其注意事项。
const修饰的普通变量不能被修改,即使通过指针操作也无法改变其值。例如:
void test_23_01() { const int a23_01 = 1; // 只读变量,不能被修改 int b23_01 = 1; // 普通变量,可被修改 // a23_01 = 2; // 报错:向只读变量‘a23_01’赋值 b23_01 = 2; printf("a23_01=%d\n", a23_01); printf("b23_01=%d\n", b23_01);} 输出结果:
a23_01=1b23_01=2
当const与volatile结合使用时,变量仍然不能被修改,但volatile的作用是强制让编译器在每次访问时重新读取内存,通常用于多线程环境中。例如:
void test_23_02() { const int a23_02 = 1; // 只读常量,不能被修改 volatile const int b23_02 = 1; // 只读常量,且强制重新读取内存 int *p1 = (int*)(&a23_02); // 指针指向常量,无法修改 *p1 = 2; // 修改失败,输出不变 int *p2 = (int*)(&b23_02); // 指针指向常量,且可强制修改 *p2 = 2; // 成功修改 printf("a23_02=%d\n", a23_02); printf("b23_02=%d\n", b23_02);} 输出结果:
a23_02=1b23_02=2
当const修饰数组时,数组整体不能被修改,但数组中的元素仍然可以通过指针访问。例如:
void test_23_03() { const int a23[10] = {1, 2, 3, 4}; // 只读数组,不能修改 int b23[10] = {1, 2, 3, 4}; // 普通数组,可被修改 printf("a23[0]=%d\n", a23[0]); // 输出数组元素 printf("b23[0]=%d\n", b23[0]); // 输出数组元素 // a23[0] = 5; // 报错:向只读位置‘a23[0]’赋值 b23[0] = 5; // 成功修改 printf("a23[0]=%d\n", a23[0]); // 输出数组元素 printf("b23[0]=%d\n", b23[0]); // 输出数组元素} 输出结果:
a23[0]=1b23[0]=1a23[0]=1b23[0]=5
void test_23_04() { int a1 = 4; int b1 = 4; const int* p1 = &a1; // 常量指针,指向的数据不能被修改 int* p2 = &b1; // 非常量指针,指向的数据可以被修改 printf("*p1=%d\n", *p1); // 输出指针值 printf("*p2=%d\n", *p2); // 输出指针值 // *p1 = 5; // 报错:常量指针不能修改指向的数据 *p2 = 5; // 成功修改指向的数据 printf("*p1=%d\n", *p1); // 输出指针值 printf("*p2=%d\n", *p2); // 输出指针值 printf("a1=%d\n", a1); // 输出数据 printf("b1=%d\n", b1); // 输出数据} 输出结果:
*p1=4*p2=4a1=4b1=4*p1=4*p2=5a1=4b1=5
void test_23_05() { int a1 = 4; int b1 = 4; int* const p1 = &a1; // 指针常量,指针不能改变,指向的数据可以被修改 int* p2 = &b1; // 非常量指针,指针可以改变,指向的数据可以被修改 printf("*p1=%d\n", *p1); // 输出指针值 printf("*p2=%d\n", *p2); // 输出指针值 int a2 = 5; int b2 = 5; // p1 = &a2; // 报错:指针常量不能改变指向的对象 p2 = &b2; // 非常量指针可以改变指向的对象 printf("*p1=%d\n", *p1); // 输出指针值 printf("*p2=%d\n", *p2); // 输出指针值} 输出结果:
*p1=4*p2=4*p1=4*p2=5
void test_23_06_01(const int x) { // x++; // 报错:向只读形参‘x’自增 printf("x=%d\n", x);}void test_23_06_02(int y) { y++; // 非常量参数可以被修改 printf("y=%d\n", y);}void test_23_06() { int a1 = 4; test_23_06_01(a1); // const参数不能被修改 test_23_06_02(a1); // 非常量参数可以被修改} 输出结果:
x=4y=5
const int test_23_07_01() { return 3; // 返回常量,不能被修改}int test_23_07_02() { return 3; // 返回非常量,能被修改}void test_23_07() { int a1 = test_23_07_01(); // 接收常量返回值 int b1 = test_23_07_02(); // 接收非常量返回值 printf("a1=%d\n", a1); // 输出常量返回值 printf("b1=%d\n", b1); // 输出非常量返回值 a1 = 5; // 修改非常量变量 b1 = 5; // 修改非常量变量 printf("a1=%d\n", a1); // 输出常量返回值 printf("b1=%d\n", b1); // 输出常量返回值} 输出结果:
a1=3b1=3a1=5b1=5
const char* test_23_08_01() { char* a = new char[10]; strcpy(a, "hello"); return a;}char* test_23_08_02() { char* a = new char[10]; strcpy(a, "hello"); return a;}void test_23_08() { // char* p1 = test_23_08_01(); // 报错:返回类型为const char* const char* p1 = test_23_08_01(); // 正确接收返回值 char* p2 = test_23_08_02(); // 正确接收返回值 printf("p1=%s\n", p1); // 输出返回值 printf("p2=%s\n", p2); // 输出返回值} 输出结果:
p1=hellop2=hello
一个函数名字后有const,这个函数必定是成员函数,也就是说普通函数后面不能有const修饰。例如:
// 非成员函数不能使用const修饰void test_23_09_01() const { // 报错:非成员函数‘void test_23_09_01()’不能拥有 cv 限定符 // 不能使用const修饰普通函数}void test_23_09_02() { printf("this is test_23_09_02()\n");}void test_23_09() { // test_23_09_01(); // 成员函数不能被调用的示例 test_23_09_02();} 注意:const修饰成员函数体时,函数内的成员变量和其他对象不能被修改。
在类中,const修饰的成员函数体内不能修改对象的数据成员。例如:
class A23_10 {private: int a1 = 1;public: void fun1() const { // 成员函数被const修饰 // a1++; // 报错:不能修改对象的数据成员 printf("a1=%d\n", a1); } void fun2() { // 非const修饰,允许修改对象的数据成员 a1++; printf("a1=%d\n", a1); }};void test_23_10() { A23_10 a23_10; a23_10.fun1(); // 调用const修饰的成员函数 a23_10.fun2(); // 调用非const修饰的成员函数} 输出结果:
a1=1a1=2
通过以上实例可以看出,const修饰的作用在于限定数据或指针的读取权限,防止意外修改,提升程序的健壮性。在实际编程中,合理使用const可以显著减少错误并提高代码质量。
转载地址:http://lomjz.baihongyu.com/