字符数组是 C 语言处理字符串的方式,本质是 char 类型的一维数组,但有一个特殊规定——末尾必须有结束标记。
6.3
字符数组是 C 语言处理字符串的方式,本质是 char 类型的一维数组,但有一个特殊规定:末尾必须有 '\0'(空字符,ASCII = 0)作为终止符,告诉程序"字符串到这里结束了"。
\0 就是用来标记"有效内容到这里为止"的哨兵,几乎所有处理字符串的函数(包括 cout)都是靠遇到 \0 才知道该在哪里停下来。| 1 | char name[8] = "abcdefg"; // 7 字符 + \0,长度必须 ≥ 8 |
| 2 | char str[] = "Hello"; // 自动推断长度为 6(5 + \0) |
| 3 | |
| 4 | // 读取单词(遇空格停止) |
| 5 | char word[20]; |
| 6 | cin >> word; // 遇空格停止 |
| 7 | |
| 8 | // 读取含空格的整行 |
| 9 | char sentence[100]; |
| 10 | cin.getline(sentence, 100); // 读取整行,包括空格 |
| 11 | |
| 12 | // 混用 cin 和 getline 时需先清空缓冲区 |
| 13 | int a; cin >> a; |
| 14 | cin.sync(); // 清空缓冲区残留的换行符 |
| 15 | cin.getline(sentence, 100); |
cin 读取整数后调用 cin.sync() 清空缓冲区,否则 getline 会直接读到残留的换行符。字符串里有些符号没办法直接打出来(比如换行、Tab键),还有些符号本身就是字符串语法的一部分(比如引号),直接写会和字符串的边界搞混。C++ 用反斜杠 \ 开头的组合来表示这些特殊字符,称为转义字符——"转义"的意思是让紧跟在 \ 后面的字符不再表示它本来的含义,而是代表一个特殊符号。
| 转义字符 | 含义 | ASCII | 使用示例 |
|---|---|---|---|
| 排版控制 | |||
| \n | 换行 | 10 | cout << "Hello\nWorld"; |
| \t | 水平制表符(Tab) | 9 | cout << "A\tB\tC"; |
| 符号本身 | |||
| \\ | 一个反斜杠 \ | 92 | cout << "C:\\Users"; |
| \" | 一个双引号 " | 34 | cout << "\"Hello\""; |
| \' | 一个单引号 ' | 39 | char c = '\''; |
| 字符串结束 | |||
| \0 | 字符串终止符(空字符) | 0 | char s[] = {'H','i','\0'}; |
" 本身是字符串的边界符号,如果字符串内容里直接出现一个 ",编译器会误以为字符串在这里就结束了。反斜杠 \ 同理——它是转义序列的开头,直接写一个 \ 会被当成某个转义字符的开始,必须写两个 \\ 才能表示"就是一个普通反斜杠"。#include <cstring>)字符数组本质上只是普通数组,并不会自带"求长度""拼接""比较"这些能力——毕竟编译器只把它当成一串字符,不知道你把它当"字符串"在用。<cstring> 头文件提供了一整套配套函数,专门用来完成这些字符串操作,使用前记得先 #include <cstring>。
| 函数 | 功能 | 示例 |
|---|---|---|
| 查询类 | ||
| strlen(s) | 返回字符串有效长度(不含 \0) | strlen("Hello") → 5 |
| strcmp(s1, s2) | 比较字符串大小(按 ASCII),相等返回 0 | strcmp("abc","abc") → 0 |
| 修改类 | ||
| strcpy(dest, src) | 将 src 复制到 dest | strcpy(b, a) |
| strcat(s1, s2) | 将 s2 拼接到 s1 末尾 | strcat(s, " World") |
| strlwr(s) | 将字符串转为全小写 | strlwr("HELLO") → "hello" |
| strupr(s) | 将字符串转为全大写 | strupr("hello") → "HELLO" |
| 转换类 | ||
| atoi(s) | 字符串转整数(非数字返回 0) | atoi("123") → 123 |
| atof(s) | 字符串转 double(非数字返回 0.0) | atof("3.14") → 3.14 |
strcpy、strcat 在写入时完全不会检查目标数组是否装得下,多出来的内容会直接溢出到相邻内存(详见 6.3.4 节的陷阱说明)。使用前先确认目标数组留够了空间。<cctype> 提供的 isalpha、isdigit、toupper、tolower 等函数即可,已在 2.2 节详细介绍过,这里不再重复。把本节内容汇总成几条最容易踩坑的规则:
\0。char s[5] = "hello" 会因为 5 个字符正好占满数组、没有位置放 \0 而出错,正确写法是 char s[6] 或直接省略大小让编译器自动推断。strcpy 不会检查目标数组够不够大,如果 dest 的空间比 src 小,多出来的内容会溢出到相邻内存,是非常危险的隐藏 bug。使用前一定确认目标数组的大小足够容纳源字符串(含 \0)。s1 == s2 比较的是两个数组的地址,而不是字符串的内容,即使两个数组内容完全一样,结果通常也是 false。判断内容是否相同必须用 strcmp(s1, s2) == 0。s[0]='H'; s[1]='i'; 这样一个个字符手动填充,最后必须手动加上 s[2]='\0';,否则数组内容"看起来对",但用 strlen、cout 等函数处理时会因为找不到结束标记而读到后面无关的垃圾数据。