c++编程(10)——string

欢迎来到博主的专栏——c++编程
博主ID:代码小豪

文章目录

    • <string>
    • string类的接口
      • 构造、析构、与赋值重载
        • 构造函数
        • 赋值重载运算符
      • 元素访问
        • operator[]
      • 容量
      • 修改器
      • 对string对象的操作
      • 迭代器

std::string是定义在c++标准的一个类,定义在标准库<string>中,其由类模板basic_string实例化而来。这一点我们可以在c++手册当中了解到。
在这里插入图片描述
不同的编译器之间对于string类的成员定义并不相同。(比如vs和g++),如果想要看看vs2022当中basic_string模板的源代码,可以在

D:\visual studio\VC\Tools\MSVC\14.35.32215\include

找到string库的源代码,博主这里是将vs安装到了D盘,如果你们安装到了其他位置,可以通过查看vs的属性找到文件位置。
在这里插入图片描述

请原谅博主能力有限,实在是看不懂string库的源代码,关于string类的成员对象有什么,我们可以在vs的调试当中看到
在这里插入图片描述
其成员可分为4个,分别是_buf、_Mysize、_Myres、_Ptr。

_buf是一个存储字符串的缓冲区,其类型是char[16],可最多存储16个字符。存储在栈区间上
_ptr是一个char*类型的指针,指向开辟在堆区的一块内存,当string类的对象存储的字符大于16个时,_buf不会再存储数据,而是改为在_ptr上存储数据
_Mysize是当前的字符个数
_Myres是最大的字符存储个数

当string对象的字符个数超过16个数,存储数据的内存会从buf改为_ptr指向的内存空间,这个空间是开辟在堆区间上的。

std::string s1("0123456789abcdef\0");

在这里插入图片描述
当_Mysize的个数超过_Myres时,string类会进行扩容,这个扩容操作不需要用户手动进行,当然,string类也提供了一个接口让用户手动的扩容,这在后边会讲到。

string类的接口

由于string类的成员对象都是私有权限(private),用户不能访问这些成员,于是c++提供了众多接口函数让用户通过接口对string类的对象进行操作。这些操作可以在c++使用手册当中看到。
c++使用手册

手册当中对string的接口(成员函数与友元函数)分为7大类,分别是:初始化和赋值、迭代器、容量、元素访问、修改器、字符操作和非成员重载函数。涉及的接口多达50几个,想要在这个博客当中这么多就不符合本专栏的目的了。博主这里简单讲解每个大类当中的常用接口。(博主打算在未来开一个新专栏,目的是精讲STL,如果大家想看请多多关注博主哦。)

构造、析构、与赋值重载

想要学会<string>和STL库。那么学习如何看懂c++使用手册是一个重要的步骤,这里我们将结合使用手册的内容对string类的接口进行讲解。

在这里插入图片描述

构造函数

在c++98的标准当中有7种重载形式,c++11新增了两种重载形式,由于c++11标准新增的两个重载不太常用,因此以c++98标准来讲解。

在这里插入图片描述

在这里插入图片描述
在后续的博客当中将不展示手册当中的参数原文,因为同名参数代表的意义基本一致

从使用手册可以看到,string类的拷贝构造函数重载七种,官方还分别给这七种构造方式进行了命名。

(1)empty constructor ——空构造
empty constructor是string的默认构造函数。其作用是构造一个空字符串。

	std::string s1;//空字符串

(4)from c-string constructor——以字符串构造
C-string指的是C语言当中常用的字符串类型,即char*类型的字符串,这类字符串都是以’\0’作为结束标志。该构造会根据传递的C-string来构造string类型的对象。

	std::string s2("hello world");//s2为"hello world";std::cout << s2 << std::endl;//打印"hello world"

(2)copy constructor——拷贝构造
在声明string类的对象时,以引用传递的形式,向拷贝构造传递一个string类的引用参数。该对象会拷贝这个引用对象。

	std::string s2("hello world");//string为"hello world";std::string s3(s2);//s2作为实参以引用传递的方式调用构造函数,s3会拷贝s2std::cout << s3 << std::endl;//打印"hello world"

(3)substring constructor——子串拷贝构造
这个构造函数有三个参数,分别string引用类型的str,size_t的pos和len。其len还存在一个缺省值_npos。

其作用是复制从str当中的pos位置开始,覆盖len个长度的字符的子串。如果len的长度超过了这个str的字符串长度,那么只复制到str的末尾。

缺省_npos是一个常量,其值以为unsigned int类型的最大值,即2的32次方-1.约等于42亿。

显然一个字符串不应该有这么多的字符个数。因此这个缺省值的意义在于,拷贝从pos位置开始复制,直到str的末尾。

std::string s4("hello world");//string为"hello world";
std::string s5(s4, 0, 5);
//拷贝s4当中从0位置开始的后5个字符,为"hello"
std::string s6(s4, 5);
//利用了_npos这个常量,那么s6会拷贝s4的从第6个字符开始,直到末尾的这部分。为" world"
cout << s5 << endl;//"hello"
cout << s6 << endl;//" world"

(5)以字符数组构造

将s指向的数组的前n个字符拷贝到string类的对象当中。

char buf[] = "123456789";std::string s7(buf, 5);//拷贝buf的前五个字符即"12345"cout << s7 << endl;//"12345"

(6)填充字符构造

向string类的对象填充n个字符c。

	std::string s8(3, 'x');//向s8填充3个'x'cout << s8 << endl;//"xxx"

(7)范围构造

范围构造会用到string类的迭代器,由于还没有对迭代器进行讲解,这部分内容将会放在下文。

string类的析构函数并不需要用户手动调用——当然你可以试试,而且string类只存在一个析构函数,这个析构函数的作用是将string开辟的堆区空间进行释放。

赋值重载运算符

赋值重载的意义在于,可以让对象之间,也能用赋值操作符(=),完成对象的赋值操作。string类将赋值运算符‘=’重载了3种形式

在这里插入图片描述
(1)string对象可以可以赋值给string对象

	std::string str1("hello world");std::string str2;str2 = str1;//str2的字符串内容变成了"hello world"cout << str2 << endl;//"hello world"

(2)可以用char*类型指针指向的字符串(C-string)赋值给string对象

const char* ptr = "hello world";//C-stringstd::string str3;str3 = ptr;//ptr指向的C-string赋值给str3cout << str3 << endl;//"hello world"

(3)可以用单个字符赋值给string对象

	std::string str4("hello world");str4 = 'a';//字符'a'替换了str4中的内容,str的字符串长度也变为了1cout << str4 << endl;//'a'

元素访问

在这里插入图片描述
此类接口使用最多就是下标重载函数了(operator []),在此之间,我们简单的了解一下其余三个函数。

char& at (size_t pos);
const char& at (size_t pos) const;

at函数是返回string当中pos位置的字符的引用,注意pos不能超过字符串长度。

std::string str1("hello world");
cout << str1.at(0) << endl;//打印第一个
str1.at(5) = ',';//str1的第6个字符被修改
cout << str1 << endl;//"hello,world"

back()和front()就是取得字符串串尾和字符串串头的引用,这里就不多介绍了,感兴趣的读者可以查阅c++使用手册。

operator[]

char& operator[] (size_t pos);
const char& operator[] (size_t pos)const;

string类重载了下标访问符号([]),这使得访问string对象的字符元素像访问数组元素一样,比如:
在这里插入图片描述

	std::string str1("hello world");for (size_t i = 0; i < 11; i++){cout << str1[i] << endl;}

可以用下标的形式,遍历整个字符串

容量

容量类的接口通常都是获取string类的成员对象,或者是提供修改成员函数的函数。

在这里插入图片描述
我们挑拣常用的说明

size()

size_t size() const;

ize
size()没有参数,size的返回值是返回当前有效字符的字符串长度(不计入‘\0’),即string的成员对象(_Mysize)。

在遍历string的成员时,可以用到size()。

	std::string s1("hello world");for(size_t i=0;i<s1.size();i++){cout << s1[i];}

lenth()
在这里插入图片描述
lenth()的作用和size()是一样的。

empty()
在这里插入图片描述
empty()用来判断string对象是否是一个空字符,如果是空字符则返回true,反之返回false。

clear()
在这里插入图片描述
celar()会清除string对象的所有字符。

这一类的接口基本没有参数,其作用大多是让用户对string对象的成员_Mysize进行操作,或者是堆string对象的状态进行修改。

修改器

在这里插入图片描述

string的接口非常冗余,在修改器这一模块更加明显,比如operator+=,append,push_back的作用是重叠的,assign、insert、replace也有重叠,pop_back和erase是也是重叠的。所以学会使用c++手册学习STL比看博主的任何相关博客都要重要。

push_back()

其函数原型为:

void push_back (char c);

push_back()会在string对象的字符串末尾插入一个字符C。

std::string s1;
s1.push_back('a');
s1.push_back('b');
s1.push_back('c');
cout << s1 << endl;//"abc"

pop_back()

void pop_back();

pop_back()删除string对象的末尾字符。

std::string s2("abc");//"abc"
s2.pop_back();
cout << s2 << endl;//"ab"

swap()

void swap (string& str);

swap()会将string对象的字符串与str的字符串进行交换。注意,这个swap是string类的成员函数,在c++标准库中还存在一个swap,这是一个函数模板,不要用混咯。

std::string str1("abc");//"abc"
std::string str2("def");//"def"
str1.swap(str2);//str1是调用这个函数的对象
cout << str1 << endl;//"def"
cout << str2 << endl;//"abc"

operator +=
string将+=操作进行了重载,使得string对象可以使用+=符号进行字符或字符串的追加。

string (1)	
string& operator+= (const string& str);
c-string (2)	
string& operator+= (const char* s);
character (3)	
string& operator+= (char c);

可追加的类型有三种,分别是string类型的对象字符串,C-string,和字符。

	std::string str3("hello");std::string str4("world");str3 += str4;cout << str3 << endl;//"helloworld"str3 += "123";cout << str3 << endl;//"helloworld123"str3 += '?';cout << str3 << endl;//"helloworld123?"

用+=来追加字符串还是非常好用的,其优点在于程序可读性高,操作简单,灵活。

append()
append的操作除去和opeartor+=重叠的部分,还多了几个,这里就讲讲多出的追加操作。
在这里插入图片描述

substring(2)
string& append (const string& str, size_t subpos, size_t sublen = npos);

string类型的对象在末尾追加str的子字符串,这个子字符串是str从subpos的位置开始,向后覆盖sublen个长度的字符串(如果sublen个长度超过了str的末尾,那么只会覆盖到str的末尾)。

std::string str5("xxx");
std::string str6("0123456789");
str5.append(str6, 3, 5);
cout << str5 << endl;//"xxx34567"
buffer(4)
string& append (const char* s, size_t n);

追加字符数组s的前n个字符。要注意数组越界这个问题。

char buffer[] = "hello world";
std::string str7;
str7.append(buffer, 5);
cout << str7 << endl;//"hello"
fill (5)	
string& append (size_t n, char c);

向string对象追加n个字符c。

std::string str8("aaa");
str8.append(3, 'b');
cout << str8 << endl;//"aaabbb"

对string对象的操作

博主写到这已经很疲惫了,因为相比较于STL的其他容器,string冗余的操作是在是太多了(严格的说string不在STL当中,string库出现的比STL要早,是c++探索泛型编程的过程中出现的不成熟产物。因此在接口的设计方面存在不够简洁的问题),不仅博主写的很烦,估计读者看着也很烦了吧,所以剩余部分的内容博主只会找具有非常不相似性的接口进行说明。

在这里插入图片描述
为什么说相似性高的不再讲解呢?我们拿这个substr举例。这是substr的原型

string substr (size_t pos = 0, size_t len = npos) const;

我甚至不用打开c++手册都能才substr()这个接口的作用。因为pos和len这两个参数贯穿了整个类的成员函数。

其作用为,生成一个子字符串,这个子字符串是string对象的字符串从pos位置开始,贯穿len个长度的字符的拷贝。

这个模块当中的c_str()很值得讲讲。
在这里插入图片描述
c_str会返回一个char*类型的指针,这个指针指向的是string对象当中有效字符串的拷贝。

	std::string str1("hello world");char buf[12] = { 0 };strcpy(buf, str1.c_str());cout << buf << endl;//"hello world"

要注意,c_str并不是将string类型的对象进行了类型转换(虽然作用很类似)。string类型的对象也不支持类型转换成C-string类型(即char*,const char*)。随着string对象的使用,_str返回的指针的值可能会改变,因此不要用const char*类型的指针来接收。

在这里插入图片描述
这6个接口均是对字符串内容的索引,我们以find和find_first_of为例。

string (1) size_t find (const string& str, size_t pos = 0) const;
c-string (2) size_t find (const char* s, size_t pos = 0) const;
buffer (3) size_t find (const char* s, size_t pos, size_t n) const;
character (4) size_t find (char c, size_t pos = 0) const;

find重载了4中函数,分别是对string对象的索引,对字符指针s指向的字符串索引,对字符数组的索引,和对字符的索引。pos指的是调用此函数的对象开始查找的位置。

返回字符串中搜索由其参数指定的序列的第一此出现的位置。
当指定pos时,搜索只包括位置pos或位置pos之后的字符。

std::string str1("123456789");
std::string str2("345");str1.find(str2);//返回4
str1.find("345");//返回4
str1.find('3');//返回4
//4是str1第一次出现这个字符串或字符的位置

在这里插入图片描述

find_first_of和find的区别在于,find是严格按照传入的参数进行查找的,比如“12345”,只有string对象存在“12345”才会返回这个位置。而find_first_of()只会查找传入字符串或者字符当中匹配的一个字符,只要string对象存在符合的任意字符就会返回这个位置。

int main ()
{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';return 0;
}

这段代码会将字符串中的aeiou字符,全部替换成*。

迭代器

迭代器是c++泛型编程又一重大产物,如同它的名字,迭代器的作用是用来遍历泛型容器中的元素。

我们可以简单的认为迭代器是一个指针(至少string当中他是这样的),我们可以通过++,–让迭代器指向下一个元素。也可以让迭代器通过算术加减访问前n个或后n个元素(和指针性质一致)。甚至还能用解引用操作符(*),来读写这个元素。

在string中,我们有6个接口来获取string对象的迭代器。
在这里插入图片描述
begin()用来获取字符串的起始元素,end()用来获取字符串的末尾元素。
在这里插入图片描述
既然被称为迭代器了,那么它肯定是支持遍历整个字符串的。

	std::string str1("hello world");for (std::string::iterator it1 = str1.begin();it1 != str1.end();it1++){cout << *it1;}

string迭代器分为4中类型,分别为

(1)iterator
(2)const_iterator
(3)reverse_iterator
(4)const_recerse_iterator

iterator就是最基本的迭代器类型,string当中的迭代器我们可以认为是这种类型的

typedef char* iterator;//vs的实现不是这样!!博主只是为了方便理解

因此我们可以用const修饰迭代器,若是如此操作,那么迭代器就不能修改指向的位置。但是可以修改指向的数据。

std::string str1("hello world");
const std::string::iterator it1 = str1.begin();
it1++;//error,被const修饰的迭代器不能修改指向的位置
*it1 = 'j';//可以修改指向的位置

实际上很好理解,因为const iterator可以等价为char* const。当const修饰的是指针时,指向的位置是只读不写的,所以不能执行++操作。

如果是想让迭代器指向的数据只读不写,那就要用到const_iterator了。用const_iterator类型的迭代器,其指向地数据的权限是只读不写的。类似于const char*

	std::string str1("hello world");std::string::const_iterator it1 = str1.begin();it1++;//const_iterator类型的迭代器修改指向的位置*it1 = 'j';//error,指向的数据是只读不写的

如果想让迭代器不改变指向的位置,也不能修改数据,那么就用
const const_itearator修饰就行

reverse_iterator是为了支持反向迭代而建立的(string当中反向迭代的意义不大,但是其他容器是有反向迭代的场景的)
在这里插入图片描述
在这里插入图片描述
rbegin和rend就是提供给反向迭代器的接口,rbegin指向字符串尾,rend指向字符串口。
在这里插入图片描述
有趣的是,reverse_iterator也支持++和–以及算术加减运算。但是执行的效果却是与iterator相反的。如果iterator++是指向下一个元素,那么reverse_iterator++则是指向上一个元素,这也就是为什么说,迭代器像指针,但却不完全是指针,因为指针不会出现++是指向上一个元素这种操作。

  std::string str2("hello world");for (std::string::reverse_iterator rit1 = str2.rbegin();rit1 != str2.rend();rit1++)//倒着遍历str2{cout << *rit1;}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/8019.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Unity 性能优化之图片优化(八)

提示&#xff1a;仅供参考&#xff0c;有误之处&#xff0c;麻烦大佬指出&#xff0c;不胜感激&#xff01; 文章目录 前言一、可以提前和美术商量的事1.避免内存浪费&#xff08;UI图片&#xff0c;不是贴图&#xff09;2.提升图片性能 二、图片优化1.图片Max Size修改&#x…

Momentum靶机系列Momentum2

先进行arp扫描&#xff1a; 获得渗透靶机的IP&#xff1a;192.168.13.142 扫描一下靶机的使用的端口&#xff1a; 具有tcp端口和http服务的80端口 可以扫描一下80端口的http服务&#xff1a; 可以发现一个网站&#xff1a;http://192.168.13.142 打开该网址&#xff1a; 查看…

Flink 部署模式

目录 概述 部署模式 会话模式&#xff08;Session Mode&#xff09; 单作业模式(Per-Job Mode) 应用模式(Application Mode) 运行模式&#xff08;资源管理模式&#xff09; Standalone运行模式 会话模式部署 应用模式部署 Yarn运行模式 会话模式部署 单作业模式部…

鸿蒙开发核心技术都有哪些【都是从零开始】

鸿蒙开发核心技术都有哪些&#xff1f;&#xff1a;【持续1年的时间公关鸿蒙技术】 我们能做哪些呢&#xff1f; 还是从UI业务开始吧 面试题1&#xff1a; 基于STAGE模型项目重构等问题 代理设计模式&#xff0c;业务与架构隔离 中介者模式&#xff0c;和代理设计模式的区别…

湖仓一体 - Apache Arrow的那些事

湖仓一体 - Apache Arrow的那些事 Arrow是高性能列式内存格式标准。它的优势&#xff1a;高效计算&#xff1a;所有列存的通用优势&#xff0c;CPU缓存友好、SIMD向量化计算友好等&#xff1b;零序列化/反序列化&#xff1a;arrow的任何数据结构都是一段连续的内存&#xff0c;…

uniapp使用iconfont

1、把这两个文件在项目的静态资源目录下 2、修改iconfont.css文件 3、最后在app.vue中引入

AI换脸免费软件Rope中文汉化蓝宝石版本全新UI界面,修复部分已知错误【附下载地址与详细使用教程】

rope蓝宝石版&#xff1a;点击下载 注意&#xff1a;此版本支持N卡、A卡、CPU&#xff0c;且建议使用中高端显卡&#xff0c;系统要求win10及以上。 Rope-蓝宝石 更新内容&#xff1a; 0214版更新&#xff1a; ①&#xff08;已修复&#xff09;恢复到以前的模型荷载参数。有…

Python中GDAL批量将多个遥感影像各波段数值缩小10000倍的方法

本文介绍基于Python中的gdal模块&#xff0c;批量读取大量多波段遥感影像文件&#xff0c;分别对各波段数据加以数值处理&#xff0c;并将所得处理后数据保存为新的遥感影像文件的方法。 首先&#xff0c;看一下本文的具体需求。我们现有一个文件夹&#xff0c;其中含有大量.ti…

OceanBase 如何实现多层面的资源隔离

OceanBase的资源隔离涵盖了多个方面&#xff0c;如物理机器间的隔离、不同租户之间的隔离、同一租户内的隔离&#xff0c;以及针对大型查询请求的隔离等。在实际应用OceanBase的过程中&#xff0c;我们经常会遇到这些操作场景或产生相关需求。这篇文章针对这些内容进行了简要的…

软件测试--接口测试

接口测试&#xff1a;直接对后端服务的测试&#xff0c;是服务端性能测试的基础 接口&#xff1a;系统之间数据交互的通道 接口测试&#xff1a;校验接口响应数据与预期数据是否一致

docker私有仓库部署与管理

一、搭建本地公有仓库 1.1 首先下载registry镜像 docker pull registry 1.2 在daemon.json文件中添加私有镜像仓库地址并重新启动docker服务 vim /etc/docker/daemon.json 1.3 运行registry容器 docker run -itd -v /data/registry:/var/lib/registry -p 5000:5000 --restartal…

04_SpringCloud

文章目录 单体架构与微服务架构的介绍单体架构微服务架构 微服务的实现服务之间的调用服务注册中心Eureka 注册中心Eureka的自我保护机制Nacos注册中心 单体架构与微服务架构的介绍 单体架构 单体架构 所有的代码最终打包成一个文件(jar包)&#xff0c;整个系统的所有功能单元…

(三十六)第 6 章 树和二叉树(二叉树的顺序存储表示实现)

1. 背景说明 2. 示例代码 1) errorRecord.h // 记录错误宏定义头文件#ifndef ERROR_RECORD_H #define ERROR_RECORD_H#include <stdio.h> #include <string.h> #include <stdint.h>// 从文件路径中提取文件名 #define FILE_NAME(X) strrchr(X, \\) ?…

[Kubernetes] Rancher 2.7.5 部署 k8s

server: 192.168.66.100 master: 192.168.66.101 node1: 192.168.66.102 文章目录 1.rancher server 安装docker2.部署k8s3.kubeconfig 1.rancher server 安装docker 所有主机开通ipv4 vi /etc/sysctl.conf#加入 net.ipv4.ip_forward 1#配置生效 sysctl -prancher-server开通…

鸿蒙准备1

鸿蒙心路 感慨索性&#xff0c; 看看鸿蒙吧。打开官网相关介绍 新建工程目录结构 感慨 最近面试Android应用开发&#xff0c;动不动就问framework的知识&#xff0c;什么touch事件的触发源是啥&#xff08;eventHub&#xff09;&#xff0c;gc流程是啥&#xff0c;图形框架是什…

美国纽扣电池UL4200A及16CFR1262标准亚马逊要求

2023年9月21日&#xff0c;美国消费品安全委员会CPSC(Consumer Product Safety Commission) 决定采用UL 4200A-2023&#xff08;包含纽扣电池或硬币电池的产品安全标准&#xff09;作为包含纽扣电池或硬币电池的消费品的强制性消费品安全规则&#xff0c;相关要求同时被编入到1…

JMeter - 如何测试REST API / 微服务

概述&#xff1a; 有许多方法和工具可用于测试REST API。 当我需要测试REST API时&#xff0c;在查看了各种工具和选项之后&#xff0c;由于以下原因&#xff0c;我选择了JMeter。 JMeter是免费和开源的。 JMeter可以从CSV文件中直接读取您的测试数据。参数化非常简单。 可以…

SparkSQL与Hive整合 、SparkSQL函数操作

SparkSQL与Hive整合 SparkSQL和Hive的整合&#xff0c;是一种比较常见的关联处理方式&#xff0c;SparkSQL加载Hive中的数据进行业务处理&#xff0c;同时将计算结果落地回Hive中。 整合需要注意的地方 1)需要引入hive的hive-site.xml&#xff0c;添加classpath目录下面即可…

【web网页制作】html+css旅游家乡河南开封主题网页制作(4页面)【附源码】

HTMLCSS家乡河南主题网页目录 &#x1f354;涉及知识&#x1f964;写在前面&#x1f367;一、网页主题&#x1f333;二、页面效果Page1 首页Page2 开封游玩Page 3 开封美食Page4 留言 &#x1f308; 三、网页架构与技术3.1 脑海构思3.2 整体布局3.3 技术说明书 &#x1f40b;四…

springboot lua检查redis库存

需求 最近需求需要实现检查多个马戏场次下的座位等席对应库存渠道的库存余量&#xff0c;考虑到性能&#xff0c;决定采用Lua脚本实现库存检查。 数据结构 库存层级结构 redis库存hash类型结构 实现 lua脚本 --- 字符串分割为数组 local function split(str, char)local…