C++字符串全解析:从基础到实战(附CSP/GESP考点)

在C++编程中,字符串是高频使用的数据类型,不仅是CSP-J/S选择题的常客,更是复赛编程题(如字符串匹配、处理、转换)的核心载体,同时在GESP 3级/4级考试中也占据重要分值。本文将从字符串定义、字符数组、STL string类到输入输出,系统梳理所有核心知识点,帮你彻底掌握C++字符串操作。

一、什么是字符串?

字符串本质是零个或多个字符组成的有限序列,字符来源可以是ASCII(如英文字母、数字)、Unicode(如中文、特殊符号)等字符集,例如:

  • 可打印字符:"Hello CSP""123abc!"
  • 控制字符:换行符'\n'、制表符'\t'(虽不可见,但属于字符串组成部分)

在C/C++中,字符串有两种核心表示形式:字符数组(C风格)和STL string类(C++风格),后者是实际编程的首选。

二、C风格字符串:字符数组

字符数组是C语言遗留的字符串表示方式,核心依赖终止符'\0' 标记字符串结束,也是考试中容易出错的考点。

2.1 字符数组的定义与初始化

字符数组的初始化有多种方式,不同方式的细节差异直接影响程序正确性,对比如下:

初始化方式 代码示例 说明 注意事项
指定长度+部分赋值 char c[20] = {'c', ' ', 'p', 'r', 'o'}; 数组长度20,前5个元素赋值,剩余元素默认填充'\0' 无需手动加'\0',未赋值元素自动补全
不指定长度+全赋值 char d[] = {'c', ' ', 'p', 'r', 'o', 'g'}; 数组长度=赋值字符数(此处为6) 未手动加'\0',数组末尾无终止符,不属于合法字符串
直接赋值字符串常量 char str[30] = "hello"; 最简洁的方式,字符串常量"hello"自动在末尾加'\0' 推荐使用!数组长度需≥字符串长度+1(预留'\0'位置)
不指定长度+字符串常量 char str[] = "hello"; 数组长度自动计算为6(h e l l o + '\0' 无需计算长度,编译器自动预留'\0'位置,最推荐

2.2 易错点:字符数组的赋值禁忌

定义后不能直接用=给字符数组整体赋值!!!

这是考试高频错题!!!例如:

char str[7];
str = "abc123"; // 错误!数组名是常量地址,不能被赋值
// 正确做法:逐个元素赋值(需手动加'\0')
str[0] = 'a'; str[1] = 'b'; str[2] = 'c'; 
str[3] = '1'; str[4] = '2'; str[5] = '3';
str[6] = '\0'; // 必须手动加终止符,否则不是合法字符串

2.3 核心:字符串终止符'\0'

'\0'是ASCII码为0的空字符,不显示、无控制功能,唯一作用是标记字符串结束。C++处理字符串时,会从数组开头扫描,遇到'\0'即停止,没有'\0'会导致“内存越界”(读取到随机垃圾数据)。

案例对比:有无'\0'的区别
// 案例1:有'\0'(合法字符串)
char str1[] = "abc"; // 实际存储:a b c \0,长度4
cout << str1; // 输出:abc(遇到'\0'停止)

// 案例2:无'\0'(非法字符串)
char str2[] = {'a', 'b', 'c'}; // 存储:a b c,长度3
cout << str2; // 输出:abc????(随机垃圾数据,直到内存中遇到'\0')

考点总结:用字符数组存储字符串时,数组长度必须≥字符串实际长度+1(预留'\0'位置),例如存储"abc123"(长度6),数组长度至少为7。

三、C++风格字符串:STL string类

STL(标准模板库)的string类封装了字符串的所有操作,无需手动管理'\0'和数组长度,是C++编程的首选,也是GESP 4级和CSP复赛的核心考点。

3.1 string类的基础使用

使用string类前,必须包含头文件<string>并声明命名空间std(考试中常考头文件是否遗漏):

#include <string> // 必须包含,否则无法使用string
#include <iostream>
using namespace std; // 或使用std::string

int main() {
    string s1;          // 空字符串
    string s2 = "CSP-J";// 初始化字符串
    string s3 = s2;     // 拷贝初始化
    cout << s2 << endl; // 输出:CSP-J
    return 0;
}

3.2 string类的核心操作

string类提供了丰富的成员函数,以下是考试高频操作:

1. 计算字符串长度
  • size():返回字符串字符数(不含'\0',推荐使用)
  • length():与size()功能完全一致,兼容性接口
string a = "123456";
int len1 = a.size();   // len1 = 6
int len2 = a.length(); // len2 = 6
2. 字符串插入

insert(pos, str):在指定位置pos插入字符串strpos从0开始计数)

#include <iostream>
#include <string>
using namespace std;

int main() {
    string str = "Hello, World!";
    string insertion = "beautiful "; 
    str.insert(7, insertion); // 在第7个位置插入("Hello, "后)
    cout << str << endl; // 输出:Hello, beautiful World!
    return 0;
}
3. 字符串遍历

遍历是编程题的基础操作,string支持两种常用遍历方式:

方式1:下标访问(类似数组,简单直观)
string str = "Hello, World!";
for (int i = 0; i < str.size(); i++) {
    cout << str[i] << " "; // 输出:H e l l o ,   W o r l d !
}
方式2:迭代器(STL标准方式,适用于所有容器)
string str = "Hello, World!";
// string::iterator 是string的迭代器类型
for (string::iterator it = str.begin(); it != str.end(); it++) {
    cout << *it << " "; // *it 访问迭代器指向的字符
}

四、字符串的输入与输出

输入输出是考试高频考点,尤其是含空格的字符串处理不同输入方式的区别,直接影响程序正确性。

4.1 输入方式对比(C++风格 vs C风格)

不同输入方式对“空格”和“换行符”的处理差异巨大,下表整理了所有考点:

输入方式 适用类型 核心特点 优缺点 代码示例
cin >> str string/字符数组 遇到空格/换行/制表符停止 优点:简单;缺点:无法读取含空格的字符串 string s; cin >> s;(输入"I love CSP",只读取"I"
getline(cin, str) string 读取一整行(含空格),直到换行符停止(换行符不存入字符串) 优点:支持空格;缺点:仅限string类型 string s; getline(cin, s);(输入"I love CSP",读取完整字符串)
cin.get(arr, len) 字符数组 读取最多len-1个字符(留'\0'),遇到换行符停止(换行符留在输入缓冲区) 优点:控制长度;缺点:需手动处理换行符 char arr[100]; cin.get(arr, 100);
cin.getline(arr, len) 字符数组 读取最多len-1个字符,遇到换行符停止(换行符从缓冲区清除) 优点:支持空格+自动清换行符;缺点:固定长度可能溢出 char arr[100]; cin.getline(arr, 100);
scanf("%s", arr) 字符数组 遇到空格/换行停止,需指定%ns限制长度(n为最大字符数) 优点:兼容C;缺点:不支持空格,需手动防溢出 char arr[100]; scanf("%99s", arr);(最多读99个字符)
fgets(arr, len, stdin) 字符数组 读取一整行(含空格),最多len-1个字符,换行符存入字符串 优点:安全支持空格;缺点:需手动去除换行符 char arr[100]; fgets(arr, 100, stdin);
易错点:cingetline的冲突

如果先使用cin >> str,输入缓冲区会残留换行符,后续getline会直接读取空字符串,解决方案是用cin.ignore()清除换行符:

string s1, s2;
cin >> s1; // 输入:CSP
cin.ignore(); // 清除缓冲区残留的换行符
getline(cin, s2); // 此时可正常读取含空格的字符串,如:"2024 Contest"

4.2 输出方式对比

输出方式 适用类型 特点 代码示例
cout << str string/字符数组 简单直接,无需手动加换行 cout << s << endl;
printf("%s", arr) 字符数组 需用%s格式符,不自动换行 printf("str: %s\n", arr);
puts(arr) 字符数组 自动在末尾加换行,无需\n puts(arr);(输出后自动换行)

五、考点总结与实战建议

  1. '\0'是C风格字符串的灵魂:字符数组初始化时,必须确保末尾有'\0',否则会导致内存越界。
  2. string类优先使用:实际编程和考试中,string类的size()insert()等函数更高效,无需管理内存。
  3. 输入方式按需选择
    • 无空格字符串:cin >> str(简单)
    • 含空格字符串:getline(cin, str)(string)或fgets(字符数组)
  4. CSP/GESP高频考点
    • 字符数组与'\0'的关系
    • cingetline的冲突解决
    • string类的遍历与长度计算

通过本文的梳理,相信你已经掌握了C++字符串的核心知识点。建议结合编程题实战(如字符串反转、替换、匹配)巩固理解,祝大家在CSP和GESP考试中取得好成绩!

更多推荐