string的使用(2)

紧接上一篇,我们继续深入探讨 string 的使用。

在上一篇中,我们已经了解了 string 的基本概念与部分常见操作。本文将在其基础上进一步展开,介绍更多实用的用法与细节,帮助你更全面地掌握 string 在实际开发中的应用。

上一篇地址:string的使用(1)

Element access

operator\[\]

以数组下标的形式访问字符串内容。

cpp 复制代码
string s1("hello world");
//利用数组下标遍历
for (size_t i = 0;i < s1.size();i++)
{
	cout << s1[i];
}
cout << endl;

编译器会根据情况选择不同的重载版本。这里我们使用数组下标访问但未对内容进行更改,因此会调用const版本。

与普通数组下标访问不同的是,string重载的operator[]会检查下标的合理性,超出范围则会报错。

cpp 复制代码
	cout << s1[100];

可以看到发生了报错。

同样是遍历字符串,其实还有一种更简便的方法,这里就不再赘述。

C++11标准:auto关键字和范围for

在 C++11 中引入了关键字 auto,它的用法是auto 变量名 = 初始值。auto会根据变量内容自动识别该变量的类型。

cpp 复制代码
auto d = 10;//识别类型为int
auto c = 3.14f;//识别类型为float
cout << d << endl;
cout << c << endl;

对于数组,我们可以用范围 for 来遍历并打印。范围 for 的使用方法如下:

cpp 复制代码
int arr[] = { 1,2,3,4,5,6,7,8,9 };
for (auto a : arr)//auto 自定义变量名 : 要迭代的对象
{
	cout << a << " ";
}
cout << endl;

这样就可以遍历数组 arr 了。

范围 for 的特点是 auto 自动识别变量类型,并且不用我们手动往后 ++(如 i++ 之类的),它会自动往后走,遍历一遍该对象。

a自动获取数组arr中的数据,auto将a的类型识别为int,并主动往后走遍历数组直到数组结束。

我们也可以用范围 for 来遍历 string 对象。

cpp 复制代码
string s2("123456");
for (auto ch : s2)
{
	cout << ch;
}
cout << endl;

那么auto将ch识别为了什么类型呢?我们可以看一下。

可以看到 ch 被识别为 char 类型,中途出现了 iterator,其实这跟范围 for 的底层实现有关,不过这里先不展开说明。

其他成员函数

at 和 operator[] 功能一样,也是根据下标访问字符串内容。至于 front 和 back,根据名字就知道功能了,这里就不再赘述。

Modifiers

operator+=

字符串追加,可以追加一个 string 对象、一个字符,也可以是一个字符串。

cpp 复制代码
string s1("123456");
s1 += ' ';
s1 += "hello";
string s2("world");
s1 += s2;
cout << s1 << endl;

push_back

用于在字符串末尾插入一个字符的函数。

cpp 复制代码
string s3("123");
s3.push_back('x');
cout << s3 << endl;

append

append 追加,这是用来追加字符串的函数,重载了多种版本,这里我们挑几个用一下。

cpp 复制代码
string s4("123456");
string s5("hello");

//追加一个字符,用空格填充
s4.append(1, ' ');
//追加一个string对象
s4.append(s5);
//追加一个字符串
s4.append("world");
cout << s4 << endl;

insert

insert 插入,可以在字符串长度范围内的任意位置插入字符或字符串,它同样重载了很多版本,这里选几个来演示一下。

cpp 复制代码
string s6("hello world");
//在开头插入字符串
s6.insert(0, "hi,");
//插入两个字符
s6.insert(0, 2,'x');
cout << s6 << endl;

erase

erase 删除,可以选择字符串中的任一位置指定要清除内容的大小,如果不传参默认全清除,效果和 clear 一样。

cpp 复制代码
string s1("hello world");
cout << s1 << endl;
s1.erase(0, 6);
cout << s1 << endl;
s1.erase();
cout << s1 << endl;

swap

用于交换两个字符串内容的函数。

cpp 复制代码
string s2("hello world");
string s3("123456");
cout << "old: s2:" << s2 << endl;
cout << "     s3:" << s3 << endl;
s2.swap(s3);
cout << "new: s2:" << s2 << endl;
cout << "     s3:" << s3 << endl;

String operations

c_str

如果我们同时使用 C 语言和 C++ 编写代码,可能会出现接口不匹配的情况,例如写文件时:

cpp 复制代码
string s1 = "test.txt";
FILE* ptr = (FILE*)fopen(s1, "w");
fputc('c',ptr);
fclose(ptr);

这里的文件名是 string 类型,而 fopen 中的第一个参数是 const char* 类型,直接传 s1 过去参数类型会不匹配,所以需要用到 c_str。

c_str 就是用来给 C 语言程序提供接口的一个成员函数。

copy

将原字符串的子串拷贝到传入的字符数组中,并且不会在复制过来的子串末尾添加空字符 \0,所以需要我们手动添加,返回的是拷贝过来的子串的长度。

cpp 复制代码
string s2("123456");
char s[4];
//将s2的6个字符拷贝到s数组里
s2.copy(s, 6);
cout << s << endl;

如果该长度比字符数组大则会破坏数组附近的栈,也就是越界了。

cpp 复制代码
string s3("hello world");
char s[15];
size_t length = s3.copy(s, 5, 6);
s[length] = '\0';
cout << s << endl;

看得出来很不好用。

find

find 是用于查找某个字符或子串首次出现位置的函数,找到则返回对应下标,没有找到则返回 npos,npos 是 string 类内部的公有成员变量,也就是理论上字符串可达到的最大长度。

一般用的最多的函数版本就是最后一个,用于查找某个字符,没有指定从哪开始查找则从开头开始查找。通常和 substr(查找字符串子串)一起用。

substr

用于查找字符串子串的函数,可以指定子串的起始位置和长度。

cpp 复制代码
string s4("hello world");

size_t pos = s4.find('w');
if(pos != string::npos)
cout << s4.substr(pos) << endl;

compare

简单来说也就是比较两个 string 对象大小的函数,比较逻辑和 strcmp 一样。

Non-member function overloads

后面 operator<< 实际上一直在使用,重载为全局函数的 swap 版本功能也和成员函数的版本一样,这里就不再赘述。

operator+

operator+ 函数为什么要重载为全局函数呢?因为它有一个重载版本的第一个参数是 const char*。而我们知道如果重载为成员函数,第一个参数就默认为该类类型的 this 指针。

cpp 复制代码
string s1("hello ");
string s2("world");

string s3 = s1 + s2;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;

Relational Operators

也就是一些与字符串比较相关的函数(>、<、== 等)。

operator>>

从流中提取字符串的函数,也就是从键盘输入读取字符串。

cpp 复制代码
string s4;
cin >> s4;
cout << s4 << endl;

getline

当我们使用 cin>> 输入字符串的时候,如果有两个变量,我们通常是以 ' ' 或 '\n' 作为分隔,将不同内容分别输入到两个对象中。

cpp 复制代码
string s1, s2;
//输入到两个对象中
cin >> s1 >> s2;
cout << s1 << endl;
cout << s2 << endl;

但是如果我们想把 s1 的内容输入为 "hello world",就会出现问题,该如何修改呢?

getline 函数就可以帮我们做到,它可以修改 string 对象读取时的定界标志。

delim 就有定界、分割的意思。如果我们不传,默认是以 ' ' 和 '\n' 来分界,但我们可以修改。

cpp 复制代码
string s1;

//将s1内容的读取分界线改为'w'
getline(cin, s1, 'w');
cout << s1 << endl;
相关推荐
青少儿编程课堂1 小时前
蓝桥杯·全国青少年信息素养大赛·电子学会Python/C++考级:折半搜索优化子集枚举(Meet in the Middle)解析
c++·python·算法·bfs·信息学竞赛
wo_jack2 小时前
C++ 入门笔记(十七):list 入门 —— 为什么 list 不能 sort?
数据结构·c++·面试·stl·list
青少儿编程课堂4 小时前
蓝桥杯青少组图形化 + 全国青少年信息素养大赛 + 电子学会Scratch考级:校园连连看解析
c++·python·算法·bfs·信息学竞赛
草莓熊Lotso4 小时前
【C++ 基于微服务的即时通讯系统】文件存储子服务实战:UUID生成、文件IO封装与全接口单元测试
开发语言·网络·数据库·c++·微服务·架构·单元测试
David猪大卫1 天前
【C++修炼】map 和 set 的使用
c语言·开发语言·数据结构·c++·经验分享·笔记·学习
HPtiger1 天前
C++ 入门笔记:从 C 到 C++ 的核心过渡(命名空间、输入输出、缺省参数、重载、引用、内联)
c语言·c++·学习
努力努力再努力wz1 天前
【Lua 进阶系列】从 C++ 对象到 Lua 变量:一文理解 userdata、Lua 栈与元表绑定机制
c++·junit·lua
慧都产品智能化1 天前
Qt 表格升级攻略:复用已有编辑器,减少重复开发
c++·qt·编辑器·qt6.3
ShineWinsu1 天前
对于Qt:QTableWidget常见属性以及QTableWidgetItem类的解析
开发语言·c++·qt·gui·客户端·表格·qtablewidget