跳转至

一维

字符串可以用 string 表示,也可以用一维字符数组表示。

前者是 C++ 风格的字符串,后者是 C 风格的字符串。

用 string 表示字符串

在标准模板库 STL 中,建立了有关字符串操作的 string 类。

定义

string s;

初始化

string s; // 默认是空串,即"", 一个双引号,中间什么都没有,空串
string s = "zq";

输入输出

int main() {
    string s;
    cin >> s;

    cout << s;

    return 0;
}

访问

s[0] 访问第0位字符
s[i] 访问第i位字符

遍历

// s.size() 在标准 string 中是 O(1),直接写 i < s.size() 也不会因此超时。
// 注意 s.size() 返回无符号类型;这里保存长度是为了让循环写法更直观。
for (int i = 0, len = s.size(); i < len; i++) 
    cout << s[i];
// 这是C++11的写法,auto 表示自动识别变量类型
for (auto c : s) cout << c;

用 string 的基础操作

赋值

s1 = s; 

拼接

// 拼接字符串
s += "def";       
// 拼接字符
s += 'g';   

判断相等

// 判断是否相等
if (s == "zq")        
// 按字典序比大小关系
if (s < "ab") 

截取子串

// 从下标为1那个位置,截取长度为2的子串
cout << s.substr(1, 2);  
// 从下标为1那个位置,截取右边的所有内容
cout << s.substr(1);  

插入子串

// 插入子串
s.insert(1, "xxx");      // 在下标为1那个位置,插入一个字符串"xxx" 

替换子串

// 替换子串
s.replace(1, 2, "xxx");  // 将从下标1开始,长度为2的子串,替换为"xxx"

删除子串

// 删除某个位置开始的若干字符
string s = "abcdef";
s.erase(2, 3); // 从下标2开始,删除3个字符
// 删除某个位置之后的所有字符
string s = "abcdef";
s.erase(3);

翻转字符串

// 翻转字符串
reverse(s.begin(), s.end());

.find() 查找函数

// 查找子串、查找字符,返回第一次出现的位置,不存在返回 string::npos
// 常用于判断一个字符串是否为另一个字符串的子串

// 查找子串zq第一次出现的位置
s.find("zq");    
// 查找字符q第一次出现的位置
s.find('q');     
// 如果没找到
if (s.find("zq") == string::npos) cout << "Not find"; 
// 从下标p那个位置往后找"zq"第一次出现的位置
s.find("zq", p); 

.find() 函数,向后找一个,替换一个

// 这个操作通常用来向右,找到一个替换一个,循环迭代向右替换
// 直到都替换完了,结束
string s = "zqoizqoizqoizqoizqoizqoizqoi";
int p = 0;
while (s.find("zq", p) != string::npos) {
    p = s.find("zq", p);
    s.replace(p, 2, "NB");
}
cout << s;

??? string的长度和占用存储空间的问题(先不看)

从下面三个实例中,我们可以得到这样的结论:

`.size()` 表示字符串当前包含的字符数。`sizeof(s)` 是 `string` 对象本身的大小,由标准库实现决定,不保证是 32 字节,也不包括可能动态分配的字符缓冲区。

<img src="https://zqiceberg-picgo.oss-cn-beijing.aliyuncs.com/img/202509121606149.png" alt="image-202509121606161 23" style="zoom:70%;" />

<img src="https://zqiceberg-picgo.oss-cn-beijing.aliyuncs.com/img/202509121606200.png" alt="image-20250912160637175" style="zoom:60%;" />

<img src="https://zqiceberg-picgo.oss-cn-beijing.aliyuncs.com/img/202509121607919.png" alt="image-20250912160755894" style="zoom:63%;" />

用一维字符数组表示字符串

定义

char s[110]; 

初始化

char s[110] = {'z', 'q'};
char s[110] = "zq";

对于这里长度为 110 的数组,两种初始化都会得到 'z''q''\0' 以及后续的 0。

下面是数组中的存储内容

s[0] = 'z'
s[1] = 'q'
s[2] = '\0'

C 风格字符串必须以 '\0' 作为结束标记。字符串字面量初始化和成功的 cin >> sscanf("%s", s) 会写入这个结束符;逐个手动赋值时则需要自己保证末尾有 '\0'

'\0' 对应的 ASCII 码为 0。

输入输出

使用 cin, cout

char s[110];

int main() {
    cin >> s;
    cout << s;

    return 0;
}

使用 scanf(), printf()

char s[110];

int main() {
    scanf("%s", s);
    printf("%s", s);

    return 0;
}

访问

s[0] 访问第0位字符
s[i] 访问第i位字符

遍历

for (int i = 0, len = strlen(s); i < len; i++) 
    cout << s[i];

用一维字符数组的基本操作(先不看)

长度

int len = strlen(s); // 获取字符串的长度

判断相等

int p = strcmp(s1, s2); // 判断 s1, s2 是否相等。相等是 0,小于是负数,大于是正数

拼接

strcat(s1, s2); // s1 后面拼接上 s2

复制

strcpy(s1, s2); // s2 复制给 s1,s1 存的东西变成和 s2 一样
memcpy(s1, s2, strlen(s2) + 1); // 连同结尾 '\0' 一起复制;s1 必须有足够空间

??? strcpy与memcpy的区别(先不看)

`strcpy` 是“拷贝字符串”用的,`memcpy` 是“拷贝内存块”用的。

`strcpy`:

- 必须依赖 `'\0'`
- 遇到 `'\0'` 才停止

`memcpy`:

- 完全不依赖 `'\0'`
- 你让它拷多少字节,它就拷多少字节

关于以 '\0' 结尾的讨论

从下面两个计算机实验中,我们可以得到这样的结论:

\0 不占字符串的长度,但占用字符串的存储空间。

image-20250912154541600

image-20250912154629178