C 字符串字面量
更新时间:2026-08-26。本文是
languages/c/主题入门层第 32 篇,字符串专题收官。"hello"这种代码里直接写的字符串叫字符串字面量——它有几个容易被忽略的性质:只读、自动拼接、和转义。搞懂它们,字符串专题就真正完结了。
本文要回答的问题
- 字符串字面量存在内存的哪个位置?能修改吗?
- 相邻的
"a" "b"会自动拼成"ab"? - 字面量里的转义序列怎么用?
一、字面量存在哪:只读数据段
c
const char *s = "hello";"hello" 这 6 个字节(含 \0)被编译器放进可执行文件的只读数据段(.rodata),程序加载后这块内存只读。因此:
- 通过字面量指针修改内容 → 段错误(字符数组与字符串讲过的坑 4);
- 相同内容的字面量可能共享同一份存储(编译器优化),
"hello" == "hello"是否成立是实现相关的,别拿字面量地址比较。
写代码的姿势:
c
const char *s1 = "hello"; // 指向只读区:加 const 明确意图
char s2[] = "hello"; // 栈上复制一份:可以修改规则:"..." 当作 const char[] 看待,要改就复制到数组。
二、相邻字面量自动拼接
c
printf("hello"
" world\n"); // 相邻两行自动拼成 "hello world\n"C 编译器会把相邻的字符串字面量合并成一个。用途:
- 长文本分行写,代码更整齐(日志模板常用);
- 条件编译拼接(宏展开不同部分)。
c
printf("第一行\n"
"第二行\n"
"第三行\n");注意:只对"字面量相邻"生效,中间夹了变量就不行(那需要运行时拼接,用 strcat/snprintf)。
三、转义序列:特殊字符进字符串
\ 开头的是转义序列,让特殊字符"写"进字符串:
c
printf("a\tb\n"); // a<制表符>b 换行
printf("他说:\"你好\"\n"); // 双引号要转义,否则提前结束字符串
printf("路径:C:\\dir\\file\n"); // 反斜杠本身要写成 \\| 转义 | 含义 |
|---|---|
\n \t \r | 换行 / 制表 / 回车 |
\\ | 反斜杠本身 |
\" \' | 双引号 / 单引号 |
\0 | 空字符(字符串结束) |
\xHH | 十六进制字节(\x41 = 'A') |
\ooo | 八进制字节 |
两个经典坑:
- 转义过了头:
"C:\users"里的\u会被当成 Unicode 转义(C11 起),行为诡异——路径记得写\\; \x后跟太多十六进制:"\x41B"会被解析成一个十六进制数 0x41B,不是 'A' 加 'B'。
四、宽字符与 Unicode(了解即可)
C11 支持 Unicode 前缀:
c
const char *s = "你好"; // UTF-8 多字节编码
const char16_t *w = u"你好"; // UTF-16
const char32_t *u32 = U"你好"; // UTF-32日常 Linux 文本处理用 UTF-8(char*),源文件保存为 UTF-8 就能直接写中文。注意:strlen("你好") 是 6 不是 2(每个汉字 UTF-8 占 3 字节),遍历/截断要按字节处理——这是中文 C 程序常踩的坑。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| 修改字面量 | 段错误 | 复制到数组 |
用 == 比较字面量地址 | 结果不确定 | 用 strcmp |
\u \x 转义误用 | 字符不对 | 按需转义,路径写 \\ |
中文按 strlen 算长度 | 数量不对 | 按 UTF-8 字节处理 |
| 想拼接字面量和变量 | 编译错/不生效 | 运行时用 snprintf |
六、与本站主线衔接
- 只读数据段在 ELF 里的位置(
.rodata),见专家层内存布局与 ABI; - 字符串的存储与比较优化(字符串驻留),见字符串函数实现与性能;
- 字符编码与 UTF-8 完整讲解,见 languages/charset 主题(如有)。
一句话总结
字符串字面量存在只读段,改它=段错误,所以想改就复制到数组;相邻字面量自动拼接适合分行写长文本;转义序列注意 \\ 和 \x 的边界;UTF-8 下中文按字节计数——字面量四连记住,字符串主题完整收官。