【C 语言八股文】const 关键字 - 底层本质 + 易混场景 + 面试真题,一篇吃透
【C 语言八股文】系列文章目录
第一章 static 关键字 - 内存 + 用法 + 面试题,一篇吃透
第二章 volatile 关键字 - 底层原理 + 实战场景 + 面试真题,一篇搞懂
第三章 const 关键字 - 底层本质 + 易混场景 + 面试真题,一篇吃透
文章目录
前言
const是 C 语言中最基础也最易踩坑的关键字之一 —— 面试中面试官不会只问 “const 是什么”,而是会深挖 “const 修饰指针的几种写法区别”“const 和 #define 的对比”“函数参数加 const 的意义” 等实战问题。很多初学者只会用const定义 “常量”,但分不清const int *p和int *const p的区别,甚至滥用const导致代码逻辑错误。这篇文章会从const的底层本质出发,拆解所有高频用法,梳理面试必考点和避坑指南,帮你彻底搞定这个基础且重要的八股文考点。
一、核心定义 & 本质
核心定义:
const(常量的)是 C 语言的类型限定符(type qualifier),用于修饰变量、指针、函数参数等,表明被修饰的对象只读,程序代码无法修改其值(编译器会对修改操作报错)。
本质:
- 编译期约束:const的限制仅作用于编译阶段,编译器会检查是否有代码试图修改const对象,一旦发现则直接报错;运行期const对象仍存储在内存中(非只读内存区,可通过指针绕过限制)。
- 并非 “常量”:const修饰的变量是 “只读变量”,而非真正的常量(如宏定义)—— 它有内存地址,不能用于数组长度、case 标签等编译期常量场景(C99 前)。
二、核心用法(分点 + 代码示例)
用法 1:修饰普通变量(只读变量)
作用:限制变量值不能被直接修改,增强代码可读性和安全性(明确表示变量值不应被修改)。
代码如下(示例):
#include <stdio.h>
int main()
{
// 定义只读变量:编译期禁止直接修改
const int MAX_NUM = 100;
// 错误示例:直接修改const变量,编译器报错(error: assignment of read-only variable ‘MAX_NUM’)
// MAX_NUM = 200;
// 注意:可通过指针绕过(仅演示,实际开发禁止这么做)
int *p = (int *)&MAX_NUM;
*p = 200; // 运行期可修改(未定义行为,部分编译器/平台可能保护)
printf("MAX_NUM = %d\n", MAX_NUM); // 输出:200(或100,取决于编译器优化)
return 0;
}
关键说明:const变量本质是 “只读” 而非 “常量”——C99 标准前,const int n = 5; int arr[n];会编译报错(数组长度需编译期常量),而#define N 5; int arr[N];合法。
用法 2:修饰指针(核心高频场景)
作用:根据修饰位置不同,限制 “指针指向的值” 或 “指针本身” 不可修改,是面试必考的核心场景。

代码如下(示例):
#include <stdio.h>
int main() {
int a = 10, b = 20;
// 场景1:const int *p → 限制指向的值不可改
const int *p1 = &a;
// *p1 = 100; // 报错:不能修改指向的值
p1 = &b; // 合法:指针本身可改
// 场景2:int *const p → 限制指针本身不可改
int *const p2 = &a;
*p2 = 100; // 合法:指向的值可改
// p2 = &b; // 报错:不能修改指针本身
// 场景3:const int *const p → 两者都不可改
const int *const p3 = &a;
// *p3 = 100; // 报错
// p3 = &b; // 报错
printf("a = %d, b = %d\n", a, b); // 输出:a = 100, b = 20
return 0;
}
记忆技巧:const 靠近谁,谁就只读——const在左边,指向的值只读;const在右边,指针本身只读。
用法 3:修饰函数参数
作用:限制函数内部不能修改传入的参数值,保护实参不被意外修改,同时明确函数的设计意图(该参数仅作输入)。
代码示例:
#include <stdio.h>
#include <string.h>
// 场景1:修饰普通参数(值传递)
// 注:值传递的参数本身是副本,加const仅限制函数内修改副本,对实参无影响,主要提升可读性
void print_num(const int num)
{
// num = 100; // 报错:不能修改const参数
printf("num = %d\n", num);
}
// 场景2:修饰指针参数(地址传递,核心场景)
// 限制函数内不能修改传入的字符串内容,避免意外篡改
void str_copy(char *dest, const char *src)
{
// src[0] = 'A'; // 报错:不能修改const指针指向的值
strcpy(dest, src); // 合法:仅读取src的值
}
int main()
{
int n = 5;
print_num(n); // 输出:num = 5
char dest[20];
const char *src = "hello const";
str_copy(dest, src);
printf("dest = %s\n", dest); // 输出:dest = hello const
return 0;
}
关键说明:函数参数加const的核心价值在指针 / 引用传递场景(如字符串、数组、结构体),能有效防止函数内部意外修改实参内容。
用法 4:修饰函数返回值(进阶场景)
作用:限制函数返回值不能被直接修改,常见于返回指针的函数,防止返回的只读数据被篡改。
代码示例:
#include <stdio.h>
// 返回const指针:调用者不能修改返回的字符串内容
const char *get_version()
{
static const char version[] = "v1.0.0";
return version;
}
int main()
{
const char *ver = get_version();
printf("version = %s\n", ver); // 输出:version = v1.0.0
// ver[0] = 'V'; // 报错:不能修改const返回值
return 0;
}
三、面试高频考点(问法 + 标准答案)
基础题
问法 1:const的作用是什么?const修饰的变量是常量吗?
答:
① const的核心作用是在编译期约束被修饰对象只读,禁止代码直接修改其值,增强代码安全性和可读性;
② 不是真正的常量:const变量有内存地址,是 “只读变量”,C99 前不能用于数组长度、case 标签等编译期常量场景,而宏定义(#define)是真正的编译期常量。
问法 2:const int *p、int *const p、const int *const p的区别?
答:
① const int *p:指针指向的 int 值只读,指针本身可指向其他地址;
② int *const p:指针本身只读(不能指向其他地址),指向的 int 值可修改;
③ const int *const p:指针指向的 int 值和指针本身都只读。
【记忆技巧:const 靠近谁,谁就只读】
进阶题
问法 1:const和#define的区别?
答:

问法 2:如何绕过const的限制修改只读变量?为什么不建议这么做?
答:
① 方法:通过指针强制类型转换,如const int a=10; int p=(int)&a; *p=20;;
② 风险:这是 C 语言的 “未定义行为”—— 部分编译器(如嵌入式编译器)会将const变量存储在只读内存区(ROM),修改会导致程序崩溃;即使能修改,也违反代码设计意图,引发逻辑错误。
坑题
问法 1:以下代码是否合法?为什么?
const int n = 5;
int arr[n]; // C89标准下报错,C99标准下合法
switch(1)
{
case n: printf("ok"); break; // 所有标准都报错
}
答:
① int arr[n];:C89 要求数组长度是编译期常量,const变量不是常量,因此报错;C99 支持变长数组(VLA),因此合法;
② case n::case 标签必须是编译期常量表达式,const变量不满足,因此所有标准下都报错。
问法 2:函数参数传递时,值传递的参数加const有意义吗?
答:
有,但仅提升代码可读性—— 值传递的参数是实参的副本,函数内修改副本不会影响实参,加const只是禁止函数内修改副本,无实际功能约束,但能明确告诉阅读者:“该参数仅作输入,函数不会修改其值”。
四、常见误区 & 避坑
误区 1:认为const变量绝对不能被修改
错误认知:const变量的值永远不能改,是 “绝对常量”。
纠正:const仅在编译期限制直接修改,运行期可通过指针强制转换绕过(未定义行为);且const变量的存储位置取决于编译器 —— 若存储在只读内存区(如嵌入式 ROM),修改会崩溃;若存储在普通数据区,修改可能成功,但违反设计意图。
误区 2:混淆const修饰指针的写法
错误示例:把const int *p理解为 “指针本身只读”。
纠正:记住核心规则 ——const 在左边,值只读;const 在右边,指针只读。可通过口诀记忆:“左定值,右定址”(左边限制值,右边限制地址)。
误区 3:滥用const修饰值传递参数
错误认知:所有函数参数都加const更 “安全”。
纠正:值传递参数加const仅提升可读性,无实际功能价值;核心应在指针 / 结构体指针等地址传递场景加const,避免篡改实参。
五、总结 & 记忆口诀
核心总结
- const的核心是编译期只读约束,修饰的是 “只读变量” 而非 “常量”;
- 修饰指针的核心规则:左定值,右定址(const 在左,值只读;const 在右,指针只读);
- 核心使用场景:保护函数参数(指针)、明确只读变量、提升代码可读性。
记忆口诀
const 修饰只读量,编译检查不越界;
左定值来右定址,指针写法别搞混;
宏是常量 const 不是,参数加它更安全。
六、拓展思考
- const在 C 和 C++ 中的差异:C++ 中const变量默认是编译期常量(可用于数组长度、case 标签),且支持修饰类成员函数(表示该函数不修改类成员);C 语言中const仅为只读变量,无类相关用法。
- const的优化价值:编译器可对const变量做额外优化(如缓存到寄存器),但前提是变量值确实不会被修改(未通过指针绕过)。
更多推荐



所有评论(0)