CC++ & Algorithm

字符数组与C风格字符串:电梯里的号码牌

中等12
语言版本:C++
概述:字符数组可以存放一串字符,C风格字符串以特殊字符'\0'表示结束,就像电梯里的号码牌最后有一个“空地”。

文字也能存进数组?——字符数组与C风格字符串的“电梯号码牌”比喻

每天我们都要处理文字:你的名字、同学的外号、游戏里的角色名……在C++里,文字是怎么存储的呢?答案就是字符数组。字符数组像一个专门放字母的小柜子,每个格子刚好能塞一个字符。但C语言风格的字符串(简称C风格字符串)还有一个隐藏的规矩:必须在所有字符的最后,放一个看不见的“终止符” '\0'(读作“反斜杠零”),告诉程序“字符串到这儿就结束了!”——就像电梯里的楼层号码牌,每一层有一块牌子,最后一块牌子上写着“END”,提醒乘客后面没有楼层了。


1. 字符数组 vs 普通数组——都是柜子,装的货不同

普通数组(比如 int a[5])的每个格子存整数,字符数组(char c[10])的每个格子存字符。字符用单引号括起来,比如 'A''!',每个字符只占一个格子。

char grades[5] = {'A', 'B', 'C', 'D', 'F'}; // 五个格子,每个格子一个字母

想象一下你的铅笔盒:普通数组装的是橡皮、尺子(数字),字符数组装的是铅笔、钢笔(字母)。但如果你想在盒子里放一句话,比如“Hello”,就需要五个格子:H、e、l、l、o。

2. C风格字符串的秘密——最后必须有一块“END”牌子

C风格字符串其实就是字符数组,但多了一个要求:末尾必须有一个 '\0' 字符。这个字符的ASCII码是0,在屏幕上不显示任何东西,但它像一个哨兵,告诉程序“到这里就没了”。如果不放 '\0',程序就会傻乎乎地一直往后读,直到在内存里碰巧遇到0才停下(这可能导致乱码甚至程序崩溃)。

比喻:电梯里有楼层牌:1楼、2楼、3楼……最后一块牌子写"END"。如果忘记放"END",乘客(程序)就会一直往上走,走到楼顶掉下来。

例子

  • "Hello" 这个字符串在内存中实际是:'H','e','l','l','o','\0'(共6个字符)。
  • 如果你只写了 char word[5] = {'H','e','l','l','o'};,末尾没有 '\0',那就只是一个字符数组,不是字符串。用 cout 输出它时,程序会打印完5个字符后,继续读取内存中邻接的未知内容,直到遇到一个 '\0' 为止——这很危险!

3. 怎么定义字符数组并存放字符串?

方法一:直接初始化(自动加 '\0'

char name[20] = "Alice"; // 数组有20个格子,但只用了前6个(A,l,i,c,e,\0)
char city[] = "Beijing"; // 不写大小,编译器自动算出大小:8(包含 \0)

双引号括起来的字符串字面量会自动在末尾加 '\0',所以 "Alice" 实际上有6个字符(最后一个看不见)。

方法二:一个一个字符赋值(必须手动加 '\0'

char word[5] = {'H', 'e', 'l', 'l', 'o'};      // 没有结尾符,不是字符串
char word2[6] = {'H', 'e', 'l', 'l', 'o', '\0'}; // 这才是一个正确的C风格字符串

很多新手会犯的错误:数组大小写成5,明明要存5个字母,但忘了给 '\0' 预留位置。正确的做法是数组大小至少是“字符数 + 1”。


4. 如何输入输出C风格字符串?

最简单的输入输出用 cincout

#include <iostream>
using namespace std;
int main() {
    char greeting[100];          // 准备一个足够大的字符数组
    cout << "请输入一句问候语(不含空格):";
    cin >> greeting;             // 注意:cin遇到空格或回车会停止
    cout << "你输入的是:" << greeting << endl;
    return 0;
}

但是cin >> 会把空格、制表符、换行符当作分割符,输入 "Hello World" 时只会读入 "Hello"。如果希望读入一整行(包括空格),可以用 cin.getline()

char sentence[200];            // 存放一句含空格的文字
cout << "请输入一句话(可含空格):";
cin.getline(sentence, 200);    // 最多读199个字符,最后一个放\0
cout << "你输入的是:" << sentence << endl;

cin.getline(数组名, 最大长度) 会读取包括空格在内的整行,直到遇到回车,并且自动在末尾加 '\0'


5. 新手最容易犯的“坑”

  • 忘记留 '\0' 的位置:比如要存 "Hello"(5个字母),数组大小写成5,结果放不下 '\0'。用 cin 输入 Hello 时,程序会写入6个字符导致数组越界,可能覆盖其他变量或闪退。
  • cin >> 输入含空格的字符串:输入 "Li Ming",只会读到 "Li""Ming" 留在缓冲区。下次再用 cin 时会直接读取到 "Ming"
  • 输出未以 '\0' 结尾的字符数组:程序会一直打印下去,直到在内存中碰到0,结果出现乱码。
  • 数组大小定义太小:比如 char name[5] 想存 "Alice",但 "Alice" 加上 '\0' 需要6个格子,编译器不会报错,运行时可能出错。

6. 完整示例:输入你的姓名,输出问候语

下面的程序先输入名字(不含空格),再输入一整句自我介绍(可含空格),然后分别输出:

#include <iostream>
using namespace std;

int main() {
    char first_name[30];           // 存放名字,假设不超过29个字符
    char intro[200];               // 存放自我介绍,含空格
    
    cout << "请输入你的名字(不含空格):";
    cin >> first_name;             // 直接读入,自动加 \0
    
    cin.ignore();                  // 忽略掉前面cin留下的回车符,否则下一条getline直接读到空
    cout << "请用一句话介绍你自己(可含空格):";
    cin.getline(intro, 200);       // 读一整行,包括空格
    
    cout << "你好," << first_name << "!" << endl;
    cout << "你的自我介绍是:" << intro << endl;
    
    return 0;
}

运行示例:

请输入你的名字(不含空格):XiaoMing
请用一句话介绍你自己(可含空格):我是一个喜欢编程的10岁学生。
你好,XiaoMing!
你的自我介绍是:我是一个喜欢编程的10岁学生。

7. 相关指引:学了字符数组之后可以学什么?

  • C++的 string:更安全、更方便,不用操心 '\0',还能直接用 + 拼接字符串。建议学完字符数组后马上学 string
  • 字符串处理函数strlen(求长度,不包括\0)、strcpy(复制字符串)、strcmp(比较字符串),这些函数都依赖于 '\0' 的存在。
  • 二维字符数组:存放多个姓名或句子,比如全班同学的名册。
  • 字符数组与指针:用指针遍历字符数组,手动判断 '\0'

字符数组虽然简单,但它是C++处理文字的基础,理解了 '\0' 这个“看不见的终点”,以后学更高级的文字处理就像坐电梯直达顶层一样轻松!

例题精讲

1单选题

电梯里显示楼层的号码牌使用字符数组存储,例如 char floor[] = "10"; 那么该字符数组的实际长度(包含'\0')是多少?

A2
B3
C4
D不确定
2判断题

在C++中,使用字符数组存储电梯楼层号时,如果楼层号是两位数,字符数组的大小必须至少为3才能正确存储(包括结束符)。

3填空题
以下代码用于将电梯当前楼层号"15"复制到另一个字符数组中,请填空:
char current[] = "15";
char display[3];
___;
cout << display;
4单选题

电梯的楼层号码牌用字符数组表示,若定义 char level[5] = "B1"; 则输出 strlen(level) 的结果是?

A1
B2
C3
D5
5填空题
以下代码用于判断电梯当前显示楼层是否为"10",请填空:
char current[3] = "10";
char target[3] = "10";
if (___ == 0) cout << "相同";
else cout << "不同";