当前位置: 首页 > news >正文

【C++】string 的使用(初步会用 string,看这一篇文章就够了)

STL 简介

标准模板库,是C++标准库的重要组成部分。主要是数据结构和算法的库。

io流 是C++库里的东西

六大组件:

string 简介

<string> - C++ Reference

string 是管理字符串的类,是管理字符数组是顺序表,现实中的复杂类型都是通过字符串来表达的

标准库的东西都放在std这个命名空间里,如果std没有展开,就要 std::string

C语言也有管理字符串:<string.h>里strxxx系列的库函数

string 的使用

注意:以下的 pos 是下标,从 0 开始!!!

构造函数 (constructor)

(1):无参的构造
(2):拷贝构造
(3):复制从字符位置 pos 开始并跨越 len 字符的 str 部分(如果 str 太短或 len 是 string::npos,则复制到 str 的末尾)
(4):用常量字符串初始化
(5):拷贝s数组的前n个进行初始化
(6):用n个字符初始化
(7):

#include <iostream>
#include <string>
using namespace std;int main()
{string s1;string s2(s1); // (const string& str)string s3("hello world"); // (const char* s)string s4("张三");string s5(10, '*'); // (size_t n, char c)cout << s1 << endl; // 在 string类 外面重载了流插入、留提取,可以直接使用// 省略打印 s2 - s5 的代码string s6(s3, 6, 5); // (const string& str, size_t pos, size_t len = npos)cout << s6 << endl;return 0;
}

为什么 string (const string& str, size_t pos, size_t len = npos); 给了缺省参数?

npos 是 string 这个类里公共的静态成员常量,给的-1是整型的最大值

	string s7(s3, 6);cout << s7 << endl; // worldstring s8(s3, 6, 100);cout << s8 << endl; // world

没给第三个参数:代表给了个很大的值(4G),长度远超后面的

析构函数 (destructor)

不管,对象出了作用域自动调用

operator= 赋值

后两个不支持也可以,没多大意义

	s1 = s4;cout << s1 << endl; // 张三s1 = "000001";cout << s1 << endl; // 000001s1 = '2';cout << s1 << endl; // 2

2. 修改操作 (Modifiers)

push_back

append 追加

(1):追加string对象
(2):追加string对象从subpos下标位置开始的sublen个字符
(3):追加常量字符串
(4):追加常量字符串的前n个
(5):追加n个字符
(6):

	// 增string s1("hello");// 尾插入一个字符s1.push_back(' ');// 尾插一个字符串s1.append("world");cout << s1 << endl; // hello world

C语言中字符串追加:strcat
缺点:效率低,每次先找到 '\0' 再追加;不能自动扩容,你先要自己开够空间,否则报错

string 只管插入,空间不够?交给对象s1,s1其实就是管理字符数组的顺序表

class string
{operator+=(char ch) // 调push_backoperator+=(const char* str) // 调appendprivate:char* _str;size_t _size;size_t _capacity;
};

operator+=

	string s1("hello");s1 += ' ';s1 += "world";cout << s1 << endl; // hello world

assign 赋值

为字符串分配一个新值,替换其当前内容。很少用

	string s1("hello world");s1.assign("ssssss");cout << s1 << endl; // ssssss

insert 插入

插入字符串。尽量少用,有效率问题

	string s1("000001");s1.insert(0, "hello");cout << s1 << endl; // hello000001s1.insert(5, "world");cout << s1 << endl; // helloworld000001s1.insert(0, 3, 'x');cout << s1 << endl; // xxxhelloworld000001s1.insert(s1.begin() + 10, 3, 'y');cout << s1 << endl; // xxxhellowoyyyrld000001

erase 删除

(1):删除从 pos 位置开始,并跨越 len 长的字符。len 给大或不给,删完
(2):擦除 p 指向的字符
(3):擦除范围 [first,last] 中的字符序列

	string s1("hello world");s1.erase(5, 1);cout << s1 << endl; // helloworlds1.erase(5);cout << s1 << endl; // hellostring s2("hello world");s2.erase(0, 1);cout << s2 << endl; // ello worlds2.erase(s2.begin());cout << s2 << endl; // llo world

replace 替换

	// world替换成 xxxxxxxxxxstring s1("hello world hello C++");s1.replace(6, 5, "xxxxxxxxxx");cout << s1 << endl; // hello xxxxxxxxxx hello C++s1.replace(6, 10, "yyyyy");cout << s1 << endl; // hello yyyyy hello C++// 所有空格替换成20%string s2("hello world hello C++");string s3;for (auto ch : s2){if (ch != ' ')s3 += ch;elses3 += "20%";}s2 = s3;cout << s2 << endl;

3. 容量 (Capacity)

size 数据个数

 建议用 size

length 长度

	string s1("hello world");cout << s1.size() << endl;   // 11cout << s1.length() << endl; // 11

历史:最开始 string 用的很多,就在标准库里写了个 string。单有 string 肯定不够,开发了 STL,后来发现 string 应该放到 STL 里面。

 string 不属于 STL,但他们是同类;把 string 归到 STL 里也合适

C语言用的 strlen;C++ string 最开始用的是 length-长度,STL 出来以后被迫加上 size(统一性)
顺序表、链表等线性表可以叫 length-长度;树、哈希等非线性叫 size

max_size

返回字符串可以达到的最大长度

不同编译器下结果不同,没用

capacity

返回当前为字符串分配的存储空间的大小,以字节表示

不同编译器下结果不同,没用

clear 清理数据

擦除字符串的内容,该字符串将变为空字符串(长度为 0 个字符)。但不释放空间

	string s1("hello world");cout << s1.size() << endl;cout << s1.capacity() << endl;size_t old = s1.capacity();for (size_t i = 0; i < 100; i++){s1 += 'x';if (old != s1.capacity()){cout << "扩容:" << s1.capacity() << endl;old = s1.capacity();}}cout << s1.size() << endl;cout << s1.capacity() << endl;s1.clear();cout << s1.size() << endl;cout << s1.capacity() << endl;

reserve 请求更改容量

应用场景:知道要开多少空间,提前一把开好,避免慢慢扩容的代价

单纯开空间,只改变 capacity,不改变 size

n > 容量:扩,且扩的 >= n
n < 容量:执行不具约束力的请求,去缩小 string 的 capacity:容器自行优化,允许 string 的 capacity > n

	string s;s.reserve(100); // 知道string要插入100个cout << s.capacity() << endl;size_t old = s.capacity();for (size_t i = 0; i < 100; i++){s += 'x';if (old != s.capacity()){cout << "扩容:" << s.capacity() << endl;old = s.capacity();}}//s.clear();//cout << s.capacity() << endl;s.reserve(10);cout << s.capacity() << endl;

不放开屏蔽的代码:        放开屏蔽的代码:

resize 开空间 + 填值初始化

开空间 + 填值初始化

n > size:则通过在末尾插入所需字符数来扩展当前内容,以达到 n 的大小。指定 c,用 c;没指定用 '\0'
n < size:缩短为其前 n 个字符,删除第 n个字符之外的字符

缩容是有代价的,很少会缩空间(以时间换空间)

	string s1("hello world");s1.reserve(100);cout << s1.size() << endl;cout << s1.capacity() << endl;// s1.resize(200);s1.resize(200, 'x');cout << s1.size() << endl;cout << s1.capacity() << endl;s1.resize(20);cout << s1.size() << endl;cout << s1.capacity() << endl;s1.resize(0);cout << s1.size() << endl;cout << s1.capacity() << endl;

shrink_to_fit 请求缩容至合适

这个请求不具约束力:容器自行优化,允许 string 的 capacity > size

不建议缩

4. 元素访问 (Element access)

operator[ ]

返回的是第pos位置字符的引用,所以能被修改

string、vector重载了[ ],可以像数组一样使用

	string s1("hello world");cout << s1 << endl;	cout << s1.size() << endl;for (size_t i = 0; i < s1.size(); i++){s1[i]++;}s1[0]--;// 遍历stringfor (size_t i = 0; i < s1.size(); i++){cout << s1[i];}cout << endl;

string s1("hello world"):常量字符串是无法改变的。所以底层是在堆上开一个数组,最后面加\0

	char s3[] = "hello world";s3[1]++; // -> *(s3+1)s1[1]++; // s1.operator[](1);

自定义类型用这个 [ ] 运算符变成调用operator,1作为参数传过去

表达式读,读的是函数调用的返回值

5. 迭代器 (Iterators)

iterators 提供一种统一的方式 访问修改 容器的数据

iterators 是像指针的类型,不一定是指针

iterators 属于 string 这个类域

string 的底层就是指针;其他容器不一定是指针,有可能是封装的自定义类型。eg:链表

string 迭代器不好用,建议用 下标 + [ ]

begin 正向迭代器

返回开始位置

end

返回最后一个数据的下一个位置

	string s1("hello world");string::iterator it = s1.begin();while (it != s1.end()){(*it)--; // 写:迭代器可以修改++it;}cout << endl;it = s1.begin();while (it != s1.end()){cout << *it; // 读:gdkknvnqkc++it;}cout << endl;


string 不喜欢用迭代器。迭代器的 3 个意义:

1. 第三种访问 string 的方式:范围for(最爱)
        语法上:依次取 s1 的数据,赋值给 ch 变量

范围 for 底层就是迭代器;不支持迭代器,就不支持范围for栈先进先出,不支持遍历,不支持迭代器,不支持范围for)

范围for 只能正着遍历,不能倒着遍历。只有反向迭代器能倒着遍历

	string s1("hello world");// for (char ch : s1) 错:ch是每个字符的拷贝,ch的改变不影响string里的for (auto& ch : s1){ch--;}cout << endl;for (char ch : s1){cout << ch; // gdkknvnqkc}cout << endl;

2. 任何容器都支持迭代器,并且用法是类似

#include <iostream>
#include <vector>
using namespace std;int main()
{vector<int> v;v.push_back(1);v.push_back(2);v.push_back(3);v.push_back(4);vector<int>::iterator vit = v.begin();while (vit != v.end()){cout << *vit << " ";++vit;}cout << endl;return 0;
}
#include <iostream>
#include <list>
using namespace std;int main()
{list<int> lt;lt.push_back(10);lt.push_back(20);lt.push_back(30);lt.push_back(40);list<int>::iterator lit = lt.begin();while (lit != lt.end()){cout << *lit << " ";++lit;}cout << endl;return 0;
}

3. 迭代器和算法配合

算法要作用到数据上面去,数据在容器里一般被封装为私有,不能直接访问
算法可以通过迭代器,去处理容器中的数据

逆置是通用的,链表、数组……都可以逆置

一个底层是数组,一个底层是链表,但对我来说用法一样

#include <algorithm>
// 意义2的2个代码reverse(lt.begin(), lt.end()); // 要逆置链表,就传链表的迭代器区间……reverse(v.begin(), v.end());for (auto e : lt){cout << e << " ";}cout << endl;for (auto e : v){cout << e << " ";}cout << endl;

rbegin 反向迭代器

rend

	string s1("hello world");// string::reverse_iterator rit = s1.rbegin();auto rit = s1.rbegin(); // 有了迭代器,auto的价值体现出来了while (rit != s1.rend()){(*rit) += 3;cout << *rit;++rit;}cout << endl;cout << s1 << endl;

const 对象不能用普通的迭代器,要用 const 迭代器
否则报错,相当于权限放大的问题

仔细看 2、4、14、15 行

// void Func(string s) 会调用拷贝构造(深拷贝,代价极大)。如果不改变,最好加 const
void Func(const string& s)
{string::const_iterator it = s.begin();while (it != s.end()){// *it += 2; 报错,*it是常量cout << *it << " "; // h e l l o   w o r l d ++it;}cout << endl; //string::const_reverse_iterator rit = s.rbegin();auto rit = s.rbegin();while (rit != s.rend()){// (*rit) += 3; 报错cout << *rit << " "; // d l r o w   o l l e h  ++rit;}
}int main()
{string s1("hello world");Func(s1);return 0;
}

6. 字符串操作 (String operations)

c_str

获取底层的 C 字符串。返回 C 形式指向字符数组(包函 \0)的指针

意义:和 C 的一些接口函数配合

class string
{
private:char* _str;size_t _size;size_t _capacity;
};
    string s1("hello world");cout << s1 << endl; // 调string的流插入cout << s1.c_str() << endl; // 识别成 char*
    string filename = "test.cpp";filename += ".zip";// FILE* fout = fopen(filename, "r"); 报错// FILE *fopen(const char *,const char *)”: // 无法将参数 1 从“std::string”转换为“const char *”FILE* fout = fopen(filename.c_str(), "r");

substr

把子字符串复制给另一对象

find

搜索由参数指定的序列第一次出现的位置

找到了返回:第一个匹配的第一个字符的位置;没找到返回:string::npos

(1):要搜索的 string 中,从 pos 位开始搜索 str
(2):……从 pos 位开始搜索字符数组。到第一个 '\0' 还没找到,结束搜索
(3):……从 pos 位开始搜索字符数组。到第一个 '\0' 或 搜索 n 个字符后,还没找到,结束搜索
(4):……从 pos 位开始搜索字符c
若 pos > size,永远找不到

#include <iostream>
#include <string>
using namespace std;int main()
{string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg";// string url = "http://www.baidu.com/?tn=65081411_1_oem_dg"// string url = "https://legacy.cplusplus.com/reference/string/string/";// 协议  域名  资源名size_t pos1 = url.find("://");string protocol;if (pos1 != string::npos){protocol = url.substr(0, pos1);}cout << protocol << endl;string domain;string uri;size_t pos2 = url.find('/', pos1 + 3);if (pos2 != string::npos){domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));uri = url.substr(pos2 + 1);}cout << domain << endl;cout << uri << endl;return 0;
}

rfind

在字符串中搜索 由参数指定的序列最后一次出现的位置

查找最后一个单词的长度;查找一个文件的后缀:test.cpp.zip

find_first_of

在字符串中搜索 由其参数指定的序列中任一字符匹配的第一个字符

	std::string str("Please, replace the vowels in this sentence by asterisks.");std::size_t found = str.find_first_of("aeiou"); // 给元音字母都改成 *while (found != std::string::npos){str[found] = '*';found = str.find_first_of("aeiou", found + 1);}std::cout << str << '\n';// Pl**s*, r*pl*c* th* v*w*ls *n th*s s*nt*nc* by *st*r*sks.

find_last_of

在字符串中搜索 由其参数指定的序列中任一字符匹配的最后一个字符

find_first_not_of

在字符串中搜索 由其参数指定的序列中任一字符都不匹配的第一个字符

find_last_not_of

在字符串中搜索 由其参数指定的序列中任一字符都不匹配的最后一个字符

7. 非成员函数

getline

从 is 中提取字符并将它们存储到 str 中,直到找到分隔符 delim 或 换行

scanf / cin 有时要求连续输入多值,不论什么类型,多值之间规定 空格 / 换行 表示间隔
遇见 空格 / 换行 就认为当前读值结束。无法读有空格的字符串

	string name;// cin >> str; 无法读有空格的字符串cout << "Please, enter your full name: ";getline(cin, name);cout << "Hello, " << name << "!\n";

8. 字符串相互转换


为什么要写成模板?要兼容其他字符类型字符串的管理

string 是被 typedef 了,只是它里面传的是 <char>1字节
string 的本源类是 basic_string
除了 string ,还有 wstring:<wchar_t>2字节、us16string:<char16_t>2字节、us32string:<char32_t>4字节

和编码有关。
编码表也叫映射表,值和符号的一一对应关系表

例如ASCII表:英文1字节(8比特位)2^8=256,足够表示所有符号了;
ASCII不能显示中文。中国自己有 gbk;国际上有 unicode 万国码

一般1个中文2字节(16比特位)2^16=65536

本篇的分享就到这里了,感谢观看,如果对你有帮助,别忘了点赞+收藏+关注
小编会以自己学习过程中遇到的问题为素材,持续为您推送文章


文章转载自:

http://o1plwd4a.hhLkn.cn
http://MN4o9MYo.hhLkn.cn
http://gMOQK3Q2.hhLkn.cn
http://7nh1RIvc.hhLkn.cn
http://QbrDAQoT.hhLkn.cn
http://DpZ8A3NX.hhLkn.cn
http://39rVmKUq.hhLkn.cn
http://HcbxI04W.hhLkn.cn
http://nzXSshv2.hhLkn.cn
http://ltBiVkAD.hhLkn.cn
http://6vlVG2Vk.hhLkn.cn
http://HoluctyD.hhLkn.cn
http://hf0NX10t.hhLkn.cn
http://73L4fbAM.hhLkn.cn
http://PP1URK1P.hhLkn.cn
http://FPZgRYsF.hhLkn.cn
http://Rnh1t2qw.hhLkn.cn
http://mRrZin61.hhLkn.cn
http://x6uPfDeM.hhLkn.cn
http://SXMDVp1n.hhLkn.cn
http://BXzIPFYj.hhLkn.cn
http://vUUgz0YI.hhLkn.cn
http://tfU2Q2QN.hhLkn.cn
http://F4MtrWKL.hhLkn.cn
http://VTLnQrK2.hhLkn.cn
http://mdtyUazW.hhLkn.cn
http://wAfeu1zX.hhLkn.cn
http://W4fDzC64.hhLkn.cn
http://aHZjCzYv.hhLkn.cn
http://gbN4mnku.hhLkn.cn
http://www.dtcms.com/a/376556.html

相关文章:

  • 基于 lua_shared_dict 的本地内存限流实现
  • 基于场景的自动驾驶汽车技术安全需求制定方法
  • 【lucene】pointDimensionCount` vs `pointIndexDimensionCount`:
  • 大语言模型入门指南:从原理到实践应用
  • 旧设备新智慧:耐达讯自动化RS232转Profibus连接流量泵工业4.0通关秘籍
  • 扭蛋机小程序有哪些好玩的创新功能?
  • 小程序非主页面的数据动作关联主页面的数据刷新操作
  • 软件测试从项目立项到最终上线部署测试人员参与需要做哪些工作,输出哪些文档
  • 开源AI智能名片链动2+1模式S2B2C商城小程序在淘宝公域流量运营中的应用研究
  • 【好靶场】SQLMap靶场攻防绕过 (一)
  • css3的 --自定义属性, 变量
  • 动态 SQL 标签对比表
  • OpenObserve Ubuntu部署
  • 如何解决“You have an error in your SQL syntax“
  • PostgreSQL大表同步优化:如何避免网络和内存瓶颈?
  • vue3 的痛点
  • 在 Ubuntu 22.04 系统(CUDA 12.9)中,通过本地DEB 包安装 cuDNN 9.13.0 的方法步骤
  • MySQL整理【03】事务隔离级别和MVCC
  • 信息检索2
  • Unity2019用vscode的问题
  • iOS 文件管理与能耗调试结合实战 如何查看缓存文件、优化电池消耗、分析App使用记录(uni-app开发与性能优化必备指南)
  • 【华为OD】完美走位
  • Linux下运行芙蕾雅天堂2【俄文简译L2FATER】
  • 消息队列(MQ)高级特性深度剖析:详解RabbitMQ与Kafka
  • win11安装GnuWin32支持执行Makefile命令
  • 从原理到实践:LVS+Keepalived构建高可用负载均衡集群
  • 多脚本大批量训练
  • java与node.js对比
  • tailwindcss 究竟比 unocss 快多少?
  • 排序---希尔排序(Shell Sort)