3. char、字符串、字符串数组、二维字符数组、char[] 的区别与联系
char* 和字符串数组是 C语言中最容易“似懂非懂”的部分之一,
但它们又是你写好嵌入式、操作系统、驱动、通信协议的 入门必经之路。
我们来系统地、通俗地、一层层地讲明白:
char、字符串、字符串数组、二维字符数组、char[] 的区别与联系**
🧭 一、字符串的本质:字符数组 + 结尾符 '\0'
在 C 语言中,没有真正的“字符串类型”,
字符串只是一个以 \0 结尾的字符数组。
char str[] = {'H', 'e', 'l', 'l', 'o', '\0'};
等价于:
char str[] = "Hello";
✅ C 编译器自动在末尾补上 \0,表示字符串结束。
🧩 二、字符串的内存结构
假设我们定义:
char str[] = "Hi";
内存布局如下(每个字符占 1 字节):
地址 内容
0x1000 → H
0x1001 → i
0x1002 → \0
🧠 三、char *:字符串指针
char *p = "Hello";
📍这里的意思是:
"Hello"这个字符串常量存在 只读内存区(文字常量区);p是一个 指针变量,指向这个字符串的首地址。
printf("%c\n", *p); // H
printf("%s\n", p); // Hello
printf("%s\n", p+1); // ello
💡 注意区别:
| 定义方式 | 存储位置 | 是否可修改 | 示例 |
|---|---|---|---|
char str[] = "Hello"; | 栈内存 | ✅ 可修改 | str[0] = 'h'; |
char *p = "Hello"; | 文字常量区 | ❌ 不可修改 | p[0] = 'h'; ❌会报错 |
🧩 四、字符串数组(二维字符数组)
char list[3][10] = {"ARM", "STM32", "Linux"};
💡 含义:
- 共 3 行,每行最多能存 9 个字符(最后一个字节留给
\0)。 - 所以这是一个 二维数组。
list[0] → "ARM\0"
list[1] → "STM32\0"
list[2] → "Linux\0"
内存图(假设地址从 0x1000 开始):
0x1000: A R M \0 ? ? ? ? ? ?
0x100A: S T M 3 2 \0 ? ? ? ?
0x1014: L i n u x \0 ? ? ? ?
你可以这样访问:
printf("%s\n", list[1]); // STM32
printf("%c\n", list[2][1]); // i
🧠 五、字符串指针数组(char *list[])
char *list[] = {"ARM", "STM32", "FreeRTOS", "Linux"};
📍 这非常重要!
它与上面的二维数组完全不同:
| 项目 | 二维数组 char list[3][10] | 指针数组 char *list[] |
|---|---|---|
| 内存结构 | 所有字符串连续存在 | 每个元素是指针 |
| 是否可变 | 每行长度固定 | 可指向任意字符串 |
| 内存效率 | 占用固定空间 | 更节省空间 |
| 常用于 | 嵌入式、表驱动 | 命令行参数、菜单表 |
🧩 实例说明
char *list[] = {"ARM", "STM32", "FreeRTOS", "Linux"};
相当于:
char *list[4];
list[0] = "ARM";
list[1] = "STM32";
list[