C++ 字符串(string)

在 C++ 中,基础的 char 类型只能用来保存单个字符,比如 'A' 或 '8'。但在实际开发中,我们经常需要处理姓名、网址、提示语等一整串字符,也就是 “字符串”。

处理字符串最常用的是 C++ 标准库提供的 std::string 类型。你可以把它看成一个能自动伸缩的字符容器:不用提前计算文本有多长,它会自动分配和调整存储空间,用起来非常省心。

C++ string 的定义

与 int、double、char 这些内置的数据类型不同,std::string 是由 C++ 标准库提供的。因此在使用它之前,我们需要先在代码开头引入 <string> 头文件。

1. 基本定义与初始化

在 C++ 中,定义一个 std::string 变量并赋予初始文本,语法格式如下。

语法:

#include <string>

std::string 变量名 = "字符串内容";

说明:

std::string 是完整的类型名称,前面的 std:: 表示它位于标准库的命名空间 std 中,双引号里的内容就是我们要保存的字符串文本。

初学的小伙伴很容易把 char 和 std::string 的引号搞混。其实区分起来很简单:char 表示单个字符,必须使用英文单引号(');std::string 表示一串字符,必须使用英文双引号(")。

char ch = 'L';                // 单个字符用单引号
std::string site = "lvye";    // 字符串用双引号

示例 1:定义并输出字符串

#include <iostream>
#include <string>

int main() {
    std::string message = "Hello, C++!";
    std::cout << message << '\n';
    return 0;
}

运行结果如下。

Hello, C++!

分析:

std::string message = "Hello, C++!"; 表示定义了一个名为 message 的字符串变量,并把双引号里的文本保存进去。接着通过 std::cout << message 就能把整段文字打印到屏幕上。

同样地,如果想要从键盘输入一个不带空格的单词,也可以配合 std::cin 写成 std::cin >> message;。至于如何读取包含空格的一整行文本,后面在 “C++ getline 读取字符串” 一节中会展开介绍。

2. 重新赋值与空字符串

定义好 std::string 变量之后,它的值跟普通变量一样是可以随时改变的。后面只需要使用等号(=)赋上一段新文本,就能直接覆盖掉原来的内容。哪怕新文本比原来长很多,std::string 也会自动扩容。

示例 2:修改字符串的值

#include <iostream>
#include <string>

int main() {
    std::string course = "C++";
    course = "Modern C++";
    std::cout << course << '\n';
    return 0;
}

运行结果如下。

Modern C++

分析:

course 一开始保存的是 "C++",执行 course = "Modern C++"; 后,新的文本直接覆盖了原来的内容,因此屏幕上输出了更新后的课程名称。

对于 std::string 变量的声明与赋值,下面 2 种方式是等价的:

// 方式 1
std::string site;
site = "lvyenet";

// 方式 2(推荐)
std::string site = "lvyenet";

其中,方式 1 是先声明变量再赋值,而方式 2 是在声明的同时直接完成初始化。如果一开始就已经确定了要保存的文本内容,在实际开发中我们更推荐使用方式 2。

可能有些小伙伴会问:如果声明 std::string 变量时没有赋初值,它里面存的是什么呢?

跟未初始化会带有随机值的 int 局部变量不同,std::string 默认会自动初始化为一个 “空字符串”,也就是里面没有任何字符,等价于 ""。需要注意的是,空字符串 "" 和包含空格的字符串 " " 并不是一回事,下面我们通过一个例子来对比一下。

示例 3:区分空字符串与空格

#include <iostream>
#include <string>

int main() {
    std::string emptyStr;
    std::string spaceStr = " ";

    std::cout << "[" << emptyStr << "]" << '\n';
    std::cout << "[" << spaceStr << "]" << '\n';
    return 0;
}

运行结果如下。

[]
[ ]

分析:

为了看清两者的区别,我们在输出 emptyStr 和 spaceStr 的两侧加上了中括号。

emptyStr 声明时没有赋初值,里面没有任何字符,输出结果为 []。而 spaceStr 的双引号中间敲了一个空格,它实际包含一个空格字符,输出结果为 [ ]。

访问与修改字符

std::string 内部保存的是一串按顺序排列的 char 字符。跟前面学过的数组一样,字符串里的每一个字符都有对应的下标,并且下标也是从 0 开始计算的。

以字符串 std::string word = "lvye"; 为例,各个字符与下标的对应关系如下表所示。

字符与下标对应关系
字符位置 下标 对应字符 访问写法
第 1 个字符 0 'l' word[0]
第 2 个字符 1 'v' word[1]
第 3 个字符 2 'y' word[2]
第 4 个字符 3 'e' word[3]

1. 使用下标 [] 访问字符

在 C++ 中,如果我们想获取字符串中某一个位置的字符,最常用的方式是在字符串变量名后面加上中括号 [],并在里面写上下标。

语法:

字符串变量[下标]

说明:

如果字符串的长度为 n,那么有效下标的范围就是 0 ~ n - 1。其中,下标 0 对应第 1 个字符,下标 1 对应第 2 个字符,以此类推。

示例 4:通过下标 [] 访问字符

#include <iostream>
#include <string>

int main() {
    std::string word = "lvye";

    std::cout << word[0] << '\n';
    std::cout << word[1] << '\n';
    std::cout << word[3] << '\n';
    return 0;
}

运行结果如下。

l
v
e

分析:

word[0] 表示获取第 1 个字符 'l',word[1] 表示获取第 2 个字符 'v',word[3] 则对应第 4 个字符 'e'。

注意 使用中括号 [] 访问字符时,C++ 不会检查下标范围。比如 "lvye" 的有效下标是 0 ~ 3,访问 word[4] 会发生下标越界,程序可能读出乱码甚至直接崩溃。

2. 使用 at() 函数访问字符

除了使用中括号 [] 之外,我们还可以调用 std::string 自带的 at() 函数来获取指定下标的字符。

std::string 内部提供了很多现成的工具函数,在 C++ 中也叫 “成员函数”。想要调用这些函数,只需要在字符串变量名后面加上英文点号(.),再写上函数名即可,就相当于 “让这个字符串执行某项操作”。

语法:

字符串变量.at(下标)

说明:

at() 函数与中括号 [] 的作用相同,区别在于 at() 会在程序运行时自动检查下标范围。如果传入的下标超出了有效范围,程序会立即报出 std::out_of_range 越界错误并停止运行,方便我们及时排查问题。

示例 5:使用 at() 访问字符

#include <iostream>
#include <string>

int main() {
    std::string text = "Hello";

    std::cout << text.at(0) << '\n';
    std::cout << text.at(4) << '\n';
    return 0;
}

运行结果如下。

H
o

分析:

在这个例子中,text.at(0) 表示获取下标为 0 的首字符 'H',text.at(4) 表示获取下标为 4 的末尾字符 'o'。

在实际开发中,如果下标范围是已知的,或者已经在循环中控制好了边界,直接使用 text[i] 最简洁。如果下标来自外部输入、有可能超出有效范围,则可以使用 text.at(i)。

3. 修改单个字符

通过下标 [] 或 at() 定位到具体位置后,我们直接使用等号(=)赋上一个新的 char 字符,就可以修改原字符串中对应位置的字符。

语法:

字符串变量[下标] = '新字符';

说明:

等号左边通过下标指定要修改的位置,等号右边则是替换进去的新字符。

示例 6:修改单个字符

#include <iostream>
#include <string>

int main() {
    std::string word = "lvye";
    word[0] = 'L';
    std::cout << word << '\n';
    return 0;
}

运行结果如下。

Lvye

分析:

word[0] 原本是小写字母 'l',执行 word[0] = 'L'; 后,首字符被修改为大写字母 'L',整个字符串就变成了 "Lvye"。

这里小伙伴们要注意,word[0] 代表的是字符串里的单个 char 字符,因此等号右边必须使用英文单引号(')。下面这种写法就是错误的,因为 "L" 使用双引号括起来时属于字符串,不能直接赋给单个 char 位置:

std::string word = "lvye";
word[0] = "L";

C++ 遍历字符串

当我们需要从头到尾依次取出字符串里的每一个字符时,最方便的做法是直接使用上一章学过的范围 for 循环。

语法:

for (char 变量名 : 字符串变量) {
    // 依次处理每一个字符
}

说明:

每执行一次循环,程序都会自动从字符串中按顺序取出一个字符赋给循环变量,直到把整个字符串里的所有字符都取完为止。

示例 7:遍历字符串中的字符

#include <iostream>
#include <string>

int main() {
    std::string text = "C++20";

    for (char ch : text) {
        std::cout << ch << ' ';
    }
    std::cout << '\n';
    return 0;
}

运行结果如下。

C + + 2 0

分析:

在上面例子中,for (char ch : text) 会按从左往右的顺序,依次把 "C++20" 里的 5 个字符取出来赋给变量 ch,再通过 std::cout 打印出来。这种方式不需要我们手动计算字符串长度,也不用操心下标越界的问题。

这里要留意一点,在 for (char ch : text) 中,ch 只是每次复制出来的字符副本,修改 ch 并不会改变原字符串 text。如果需要结合下标修改原字符串里的字符,可以配合后面学习的 size() 函数与普通下标循环来实现。

上一篇:

下一篇:

给站长反馈

绿叶网正在不断完善中,小伙伴们如果发现任何问题,还望多多给站长反馈,谢谢!

邮箱:lvyenet@vip.qq.com

「绿叶网」服务号
绿叶网服务号放大
关注服务号,微信也能看教程。
绿叶网服务号