const在C语言中可以限制对象的可修改性。在处理函数参数时,这有助于保护数据不被意外修改。声明的关键区别取决于const修饰符所指向的对象,以及它相对于指针的位置。
各种声明示例:
void func(const int *ptr); // 指向常量int的指针 void func(int * const ptr); // 常量指针指向int void func(const int *const ptr); // 指向常量int的常量指针
const int *ptr — 数据不可修改,指针可以重新分配。int *const ptr — 数据可修改,但指针不可重新分配。const int *const ptr — 数据和指针在函数内都不可修改。正确使用const的好处:
void print_array(const int *arr, size_t n) { for (size_t i = 0; i < n; ++i) { printf("%d\n", arr[i]); // arr[i] = 10; // 错误:试图修改const数据 } }
问题: 可以将常量变量的地址赋值给普通指针吗?
预期错误答案: "是的,如果在指针声明中去掉const,编译器允许这样做。"
正确答案: 只允许通过显式类型转换(casting)进行“降级const”,但是试图修改被声明为const的对象会导致未定义行为。这样做是不可取的 — 这会破坏const的语义并导致运行时错误。
示例:
const int x = 5; int *ptr = (int*)&x; *ptr = 10; // UB:修改const对象
记录
在一个大型项目中,程序员尝试绕过const保护,将const指针强制转换为普通指针,并修改只读内存段的数据。在某些平台上,这导致程序崩溃(段错误),在其他平台上则出现难以调试的隐性错误。
记录
在一个处理数组的库中,开发者忘记将参数声明为const。结果是错误的函数调用意外修改了原始数据,导致数组状态不同步,以及在后续处理块中出现严重bug。
记录
在编写传递给第三方库的回调函数时,忘记为输入缓冲区指定const。库试图修改常量字符串中的数据,导致在某些操作系统上崩溃,并导致对问题源的长时间争议。