【C++】深入理解string类

一、熟悉string类

1.1 string类的由来:

        C语音中的字符串需要我们自己管理底层空间,容易内存泄露。而C++是面向对象语音,所以它把字符串封装成一个string类。

        C++中对于string的定义为:typedef basic_string string; 也就是说C++中的string类是一个泛型类,由模板而实例化的一个标准类,本质上不是一个标准数据类型。

至于我们为什么不直接用String标准数据类型而用类是因为一个叫做编码的东西

        我们每个国家的语言不同 比如说英语使用26个英文字母基本就能表述所有的单词 但是对于中文的字符呢?是不是就要用其他编码方式啊(比如说UTF-8或者GB2312)

1.2  string类的函数接口:


二、string类的写入:

2.1  string类的构造函数:

 我们一般都是用无参的构造,拷贝构造和有参数的构造。

string s1;

string s2(s1);

string s3("hello C++");

string s4="hello C++";//s3 s4都是会把"hello C++"字符数组隐式转换成const char*类型,然后再调用这个构造函数,对s4进行构造

不需要担心空间不够问题,这些构造函数内部都会实现自动扩容的操作。

2.2  string类的数据读取:

方法一:string类里面对运算符[ ] 进行了重载,可以像使用数组一样使用。

for(int i=0;i<s1.size(),i++)
{cout<<s1[i]<<" ";
}

这里的s1.size()是统计字符串长度(不包括\0)。如hello world的size是11 

方法二:调用at函数

for(int i=0;i<s1.size(),i++)
{cout<<s1.at(i)<<" ";
}

operator[ ]和at两种方法的区别:

    下标访问报断言错误 at访问报异常

方法三:迭代器的方法。

迭代器的写法:首先写个string类名 后面跟上iterator(迭代器) 再后面加上一个it变量(可以是其他名字)

只时候就体现了auto的好处了  auto it = s1.begin(); //自动转换类型

string::iterator it=s1.begin();
while(it!=s1.end)
{cout<<*it<<" ";it++;
}

 注意点:1.   begin是指向开始位置,而end是指向\0位置---->左闭右开

                2.不要写成it<s1.end,因为物理空间中不一定begin的就比end的小,如链表,树等是靠指针指向下一个节点。(而且底层不一定就是指针,这个后面讲)

                3.为啥需要迭代器?统一操作,关心效果,不关心底层原理(C++面向对象思维)

这个代码的意思是,it指向字符串的第一个元素

      (目前阶段可以理解为it就是一个指针)

      (s1.begin()就是指向字符串第一个字符的指针)

在循环当中,如果it不等于最后一个字符所在的位置,就打印并且it++; 

 迭代器包括正向迭代器和反向迭代器,还有有无const修饰的迭代器

这里简单介绍一下 反向迭代器 const修饰的反向迭代器

string::reverse_iterator it = s1.rbegin();
while(it!=s1.rend)
{cout<<*it<<' ';it++;
}

顾名思义,就是反向的,it++时是从后往前走的。 


 const修饰的反向迭代器

string::const_reverse_iterator it = s1.rbegin();
while (it != s1.rend())
{cout << *it << " ";it++;
}

方法四:范围for(底层原理是迭代器)

for(auto u:s1)
{cout<<u<<" ";
}

auto 是实现自动识别类型,    如  char ch = ‘a’;      auto i = ch;   则i的类型是char

 这个代码的意思是   依次把s1中的字符串变量中的字符拷贝给u变量,然后打印u变量

如果想要对里面的值进行修改,就需要用引用传参。 

for(auto& u:s1)
{u++;cout<<u<<" ";
}

其他:还有两个成员函数back和front,分别访问最后一个字符和第一个字符。 

cout<<s1.back();

cout<<s1.front();


 三、string类的容量接口:

3.1 size  和  length
s1="hello world";
cout<<s1.size()<<endl;
cout<<s1.length()<<endl;

两者没有区别,一开始是length先出来的,然后为了和后面的STL中的其他容器保持一致,就多了一个size函数。我们一般用size

3.2 capacity

capacity返回的容量不包括\0,就是本来开了16的空间,但是前人认为\0不能算有效容量,就会返回15

3.3 empty
string s1;
string s2="hello world";
cout<<s1<<endl;
cout<<s2<<endl;

 

3.4 clear

将size变为0,相当于清理数据,下一次是从size==0的位置开始插入数据。 

string s2="hello world";
s2.clear();
s2 = "C++";
cout << s2;

 

3.5  reserve 预留空间   和    resize  调整size的大小,其间用\0来填充
string s1="hello world";
string s2="hello world";
s2.reserve(100);
cout<<s2.size()<<" "<<s2.capacity() << endl;s1.resize(100);
cout << s1.size() <<" "<< s1.capacity() << endl;

这样子的结果是如果是resize出来的,那么前面的11--100的空间都被\0填充,我们只能从100号位置开始填充,中间的空间都浪费掉了。

而reserve出来的没有改变size的大小,就扩容。(这个函数就很nice,当你提前知道你想要开多大的空间,就可以使用这个函数。

看resize函数的代码

string s1="hello world";
s1.resize(15);
s1 += "hi";
cout << endl;
cout << s1 << endl;
cout << s1.size() <<" "<< s1.capacity() << endl;

\0是不打印出来的,所以最后的结果是

world和hi中间是没有空格的

四、String类对象修改接口

 4.1 这里就operator+=这个函数重要

可以实现尾插字符,也可以实现尾插字符串

第四个是C++11之后添加的(我还不知道是什么,等我学了再谈) 现在我们就用前三种。

string s1 = "hello world";
s1 += ' ';
s1 += "hello C++";
cout << s1;

4.2  insert和earse

都是需要挪动数据,所以时间复杂度高,少用。

string s1 = "hello world";
s1.insert(5,"         ");
cout << s1;

 从下标为5位置开始插入

string s1 = "hello world";
s1.insert(5,"         ");
s1.erase(0,5);
cout << s1;

 从下标为0的位置,开始删除5个元素

string类里面的erase函数是有缺省值的。

       当不传参的时候是从0号位置开始删除到末尾。

         传一个参数是指从n号位置开始一直删除到末尾。

4.3 replace

函数的参数分别是替换的起始位置,删除的数据大小,替换的字符串(不能是字符)

 

把含有a b c的字符都替换成 字符 *

其他   reverse(这个不是string类里面的,而是迭代器中的)

逆置字符串,参数是迭代器s1.begin()和s1.end()

s1="hello world";
reverse(s1.begin(),s1.end());
cout<<s1;

就可以把s1中的字符串逆转,当然,也适用于其他的迭代器。 

五、 String对象字符串运算相关接口

5.1 c_str 

 两者的类型不同。

一个是string对象

一个是字符指针(也就是字符串)

5.2 find

第一种:

        string s1 = "hello world";
        string s2 = "world";
        size_t posn=s1.find(s2, 1);   
        cout << posn;

// 从s1这个对象中查找s2这个对象,从下标为1这个位置查找(默认从0开始查找)

返回  匹配的第一个字符的下标

第二种:

        string s1 = "hello world";
        string s2 = "world";
        size_t posn = s1.find("hello");     //第一个参数是输入字符串       第二个参数默认为0
        cout << posn;

第三种:

 参数1、查找的字符串   参数2、从第几个位置开始查找   参数3、要匹配的字符序列的长度。

 string str("There are two needles in this haystack with needles.");found = str.find("needles are small", 15, 6);if (found != std::string::npos)cout << "second 'needle' found at: " << found << '\n';

 

从下标为15的位置开始查找,找到needle这个字符串(查找这个字符串的前6个字符)

第四种:

查找字符

    string str("There are two needles in this haystack with needles.");found = str.find('.');if (found != std::string::npos)cout << "Period found at: " << found << '\n';

5.3 rfind   

        就是倒着找,从后往前找 

        同样是四个重载 

5.4 substr

 从第pos位置开始截取len长度的字符串。参数2没有时,取到结尾。

#include <iostream>       // std::cout
#include <string>         // std::stringint main()
{std::string str = "We think in generalities, but we live in details.";// (quoting Alfred N. Whitehead)std::string str2 = str.substr(3, 5);     // "think"std::size_t pos = str.find("live");      // position of "live" in strstd::string str3 = str.substr(pos);     // get from "live" to the endstd::cout << str2 << std::endl << str3 << '\n';return 0;
}

5.5 getline(string)

两种重载,第一种需要自己手动设置结束符    第二种是以\n为结束符

//第一种
int main()
{std::string name;std::cout << "Please, enter your full name: ";std::getline(std::cin, name,'a');std::cout << name;return 0;
}

 以‘a’字符为结束标志


//第二种
#include <iostream>
#include <string>
int main()
{std::string name;std::cout << "Please, enter your full name: ";std::getline(std::cin, name);std::cout << name;return 0;
}


好了,到这里本篇文章就结束了,如果有什么错误的地方,还请各位大佬指明,相互学习。

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

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

相关文章

java面试(微服务)

SpringCloud五大组件 Nacos&#xff1a;注册中心Ribbon&#xff1a;负载均衡Feign&#xff1a;远程调用sentinel&#xff1a;服务熔断Gateway&#xff1a;网关 注册中心 Eureka Nacos 负载均衡 Ribbon负载均衡流程 Ribbon的负载均衡策略 RoundRobinRule&#xff1a;简单的…

C++中把Lambda 表达式作为参数传递给模板函数。

例子&#xff1a; template<class fun> void mytest(fun f) {_string s1 "abc";_string s2 "abc";if (f(s1, s2)){std::cout << "相等。\n";}}int main() {mytest([](const _string s1, const _string& s2) { return s1 s2; …

python学习笔记----异常、模块与包(九)

一、异常 1.1 什么是异常 在Python中&#xff0c;异常是程序执行时发生的错误。当Python检测到一个错误时&#xff0c;它会引发一个异常&#xff0c;这可能是由于多种原因&#xff0c;如尝试除以零、访问不存在的文件&#xff0c;或者尝试从列表中获取不存在的索引等。异常处…

数组的拷贝

数组的拷贝 文章目录 数组的拷贝浅拷贝内存分析 深拷贝内存分析 浅拷贝 概念&#xff1a;数组的浅拷贝是指新数组保存的是原数组的内存地址&#xff0c;并没有拷贝真正的值&#xff0c;如果原数组的内容发生改变那么新数组的内容也会发生相应改变。 代码实现&#xff1a; pu…

C语言/数据结构——每日一题(合并两个有序链表)

一.前言 嗨嗨嗨&#xff0c;大家好久不见&#xff01;今天我在LeetCode看到了一道单链表题&#xff1a;https://leetcode.cn/problems/merge-two-sorted-lists想着和大家分享一下&#xff0c;废话不多说&#xff0c;让我们开始今天的题目分享吧。 二.正文 1.1题目描述 1.2题…

phpstudy 搭建 upload-labs 文件上传靶场

phpstudy 搭建靶场&#xff1a;下载安装好phpstudy后&#xff0c;下载靶场源码&#xff1a; upload-labs下载地址&#xff1a; https://github.com/c0ny1/upload-labs 下载完压缩文件&#xff0c;解压文件&#xff0c;解压后的文件夹命名为upload--labs 将解压后到文件夹放…

docker如何生成springboot镜像

1、在springboot的jar包所在的目录下创建Dockerfile文件&#xff0c;此案例的目录为/usr/java Dockerfile的文件内容如下&#xff1a; FROM openjdk:8 LABEL author"zengyanhui" LABEL email"1181159889qq.com" WORKDIR /usr/java/springbootdemo COPY s…

负债56亿,购买理财产品遭违约,操纵虚假粉丝,流量在下滑,客户数量减少,汽车之家面临大量风险(六)

本文由猛兽财经历时5个多月完成。猛兽财经将通过以下二十二个章节、8万字以上的内容来全面、深度的分析汽车之家这家公司。 由于篇幅限制&#xff0c;全文分为&#xff08;一&#xff09;到&#xff08;十&#xff09;篇发布。 本文为全文的第十四章、第十五章、第十六章。 目…

机器人系统ros2-开发实践04-ROS 2 启动文件管理大型项目的最佳实践

机器人上的大型应用通常涉及多个互连的节点&#xff0c;每个节点可以有许多参数。海龟模拟器中模拟多只海龟就是一个很好的例子。海龟模拟由多个海龟节点、世界配置以及 TF 广播器和监听器节点组成。在所有节点之间&#xff0c;存在大量影响这些节点的行为和外观的 ROS 参数。 …

《与 Apollo 共创生态——Apollo7周年大会干货分享》

&#x1f308;个人主页: Aileen_0v0 &#x1f525;热门专栏: 华为鸿蒙系统学习|计算机网络|数据结构与算法 ​&#x1f4ab;个人格言:“没有罗马,那就自己创造罗马~” 文章目录 阿波罗X企业自动驾驶解决方案自动驾驶技术提升与挑战自动驾驶系统功能与性能的详细解析<td alig…

python可视化学习笔记折线图问题-起始点问题

问题描述&#xff1a; 起始点的位置不对 from pyecharts.charts import Line import pyecharts.options as opts # 示例数据 x_data [1,2,3,4,5] y_data [1, 2, 3, 4, 5] # 创建 Line 图表 line Line() line.add_xaxis(x_data) line.add_yaxis("test", y_data) li…

数字阅览室的优势

近年来&#xff0c;随着我国社会经济的快速发展&#xff0c;信息技术的发展也得到了广泛的应用&#xff0c;我国高校图书馆和图书管理系统进入了快速发展的快车道。在这种环境下&#xff0c;数字化阅览室在校园中非常流行。数字阅览室是一套真正意义上的面向中小学图书管理、浏…

Golang | Leetcode Golang题解之第58题最后一个单词的长度

题目&#xff1a; 题解&#xff1a; func lengthOfLastWord(s string) (ans int) {index : len(s) - 1for s[index] {index--}for index > 0 && s[index] ! {ansindex--}return }

python基础语法--函数

一、函数概述 函数就是执行特定任务完成特定功能的一段代码。可以在程序中将某一段代码定义成函数&#xff0c;并指定一个函数名和接收的输入&#xff08;参数&#xff09;&#xff0c;这样就可以在程序的其他地方通过函数名多次调用并执行该段代码了。 每次调用执行后&#…

【华为】路由综合实验(基础)

【华为】路由综合实验 实验需求拓扑配置AR1AR2AR3AR4AR5PC1PC2 查看通信OSPF邻居OSPF路由表 BGPBGP邻居BGP 路由表 配置文档 实验需求 ① 自行规划IP地址 ② 在区域1里面 启用OSPF ③ 在区域1和区域2 启用BGP&#xff0c;使AR4和AR3成为eBGP&#xff0c;AR4和AR5成为iBGP对等体…

AI 图像无损放大器:多平台支持,轻松上手 | 开源日报 No.241

upscayl/upscayl Stars: 25.5k License: AGPL-3.0 upscayl 是一个免费开源的 AI 图像放大器&#xff0c;支持 Linux、MacOS 和 Windows 平台&#xff0c;并且秉承着“Linux 优先”理念构建。 使用先进的 AI 算法对低分辨率图像进行放大和增强在不损失质量的情况下放大图像&am…

ubuntu开启message文件

环境&#xff1a;ubuntu 20.04 1、首先需要修改 /etc/rsyslog.d/50-default.conf 文件&#xff1b;源文件中message被注释&#xff0c;如下图&#xff1a; 2、打开注释&#xff1a; 3、重启服务 systemctl restart rsyslog.service 如此即可&#xff01;

嵌入式学习59-ARM7(自动设备号和混杂设备)

知识零碎&#xff1a; 头文件查找&#xff1a; /arm/路径下的头文件 linux驱动程序的编写&#xff0c;编译&#xff0c;运行过程 -------------------------------------------------------------------------------------------------------------------------------- 1.…

java-函数式编程-函数对象

定义 什么是合格的函数&#xff1f;无论多少次执行函数&#xff0c;只要输入一样&#xff0c;输出就不会改变 对象方法的简写 其实在类中&#xff0c;我们很多参数中都有一个this&#xff0c;被隐藏传入了 函数也可以作为对象传递&#xff0c;lambda就是很好的例子 函数式接口中…

常用的时间序列分析方法总结和代码示例

时间序列是最流行的数据类型之一。视频&#xff0c;图像&#xff0c;像素&#xff0c;信号&#xff0c;任何有时间成分的东西都可以转化为时间序列。 在本文中将在分析时间序列时使用的常见的处理方法。这些方法可以帮助你获得有关数据本身的见解&#xff0c;为建模做好准备并…