探索c++:string常用接口 迷雾

 

 个人主页:日刷百题

系列专栏〖C/C++小游戏〗〖Linux〗〖数据结构〗 〖C语言〗

🌎欢迎各位点赞👍+收藏⭐️+留言📝 

一、string

这里我们对string类进行一个简单的总结:

  • string是表示字符串的字符串类
  • 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
  • string在底层实际是:
//string是basic_string模板类的别名
typedef  basic_string<char, char_traits, allocator>   string;
  • 不能操作多字节或者变长字符的序列。

这里有一个需要注意的点:
在使用string类时,必须包含#include头文件以及using namespace std;

二、string类的常用接口

2.1  string对象常见构造(constructor)

(constructor)函数名称   功能说明
string()(重点)  构造空的string类对象,即空字符串
string(const char* s)(重点)用C-string来构造string类对象
string(size_t n, char c) string类对象中包含n个字符
string(const string&s)(重点) 拷贝构造函数
2.1.1  string()
  • 构造空的string对象,即空字符串
//空构造函数
#include<iostream>
using namespace std;
int main()
{string s1;cout << s1 << endl;return 0;
}
 2.1.2  string(const char* s)
  • 用C-string来构造string类对象
//常量字符串                                           
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;return 0;
}

 其实相当于将常量字符串拷贝到str中

 2.1.3  string(size_t n, char c)
  • 用n个相同的字符c去构造string类对象
//创建一个包含 5 个重复字符 'a' 的字符串
#include<iostream>
using namespace std;
int main()
{string s1(5,'a');cout << s1 << endl;return 0;
}

 2.1.4  string(const string&s) 
  • 拷贝构造(深拷贝),只有调用默认拷贝构造才是浅拷贝
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;string s2(s1);cout << s1 << endl;cout << s2 << endl;cout << &s1 << endl;cout << &s2 << endl;return 0;
}

2.1.5 string (const string& str, size_t pos, size_t len = npos)

  • 拷贝一个string类对象,读取从他的第pos个位置开始的往后的len个字符
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;string s2(s1, 6, 3);cout << s2 << endl;return 0;
}

注:

如果拷贝的字符数量大于字符串的字符个数的话,就全部打印完;如果不给值,则是缺省值npos,值为-1,也是全部打完。

 2.2  string类对象的容量操作(Capacity)

函数名称    功能说明
size(重点)返回字符串有效字符长度
length  返回字符串有效字符长度
capacity 返回空间总大小
empty (重点)检测字符串释放为空串,是返回true,否则返回false
clear (重点) 清空有效字符
reserve (重点) 为字符串预留空间**
resize (重点)将有效字符的个数该成n个,多出的空间用字符c填充
2.2.1  size和length

  • size和length其实是一样的, 都代表字符串的长度,但是早期STL还没出现的时候,strling类用的是length,但是后来STL出来后,里面大部分都是用的size,所以为了保持一致性又造了一个size出来,平时用哪个都可以的。

用法如下:

#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.length() << endl;cout << s1.size() << endl;return 0;
}

注意:这里计算出来的是有效字符个数,也就是说不包括’\0’

2.2.2  capacity

  • 表示string当前的容量,一般来说是默认不算上’\0'

用法如下:

#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.capacity() << endl;return 0;
}

注:vs用的是PJ版STL,字符串会先被存在_Bx数组中,是char[16]类型,超过之后才会去动态开辟空间,第一次开辟空间是32,然后从32开始进行1.5倍扩容。而g++是SGI版STL,直接就是从0开始,然后根据情况直接开始扩容,从0开始进行2倍扩容。

2.2.3  empty

  • 字符串为空返回1,不为空返回0

用法如下:

#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.empty() << endl;return 0;
}

2.2.4  clear

  • 清空字符串
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;s1.clear();cout << s1 << endl;return 0;
}

2.2.5  reverse

  • 作用是开空间,扩容
  1. 如果 n 大于当前字符串容量(capacity),则该函数会导致容器将其容量增加到 n 个字符(或更大)。 
  2. 在所有其他情况下,它被视为一个非约束性的缩减字符串容量请求:容器实现可以自由优化,保持字符串的容量大于n。
  3. 此函数对字符串长度没有影响,也无法更改其内容。(当n小于对象当前的capacity时,什么也不做)
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.capacity() << endl;cout << s1.size() << endl;//1.5倍扩容s1.reserve(30);cout << s1.capacity() << endl;cout << s1.size() << endl;return 0;
}

  • 扩容不会改变size()。 
  • vs根据1.5倍的扩容规则,至少会扩容到超过你的要求。如果是g++的话,就是2被扩容。
2.2.6  resize 

  • 改变size,减少的话就是变少(不会改变容量),如果增多的话就可能会扩容顺便帮助我们初始化,第一个版本的话初始化补\0,第二个版本的话就是初始化c字符
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.capacity() << endl;cout << s1.size() << endl;s1.resize(30);cout << s1.capacity() << endl;cout << s1.size() << endl;return 0;
}

总结:

  • **size()**与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size(),它的长度不包括\0。
  • clear()只是将string中有效字符清空,不改变底层空间大小。
  • resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
  • reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。

2.3 string类对象的访问及遍历操作(Iterators

函数名称功能说明
operator[] (重点)
返回 pos 位置的字符, const string 类对象调用
begin + end
begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器
rbegin + rend
begin 获取一个字符的迭代器 + end 获取最后一个字符下一个位置的迭 代器
范围 for
C++11 支持更简洁的范围 for 的新遍历方式

2.3.1   operater[ ]  和 at()
  • 返回该位置的字符

#include<iostream>
using namespace std;
int main()
{string const s1("hello world");for (int i = 0; i < s1.length(); i++){cout << s1[i];}cout << endl;return 0;
}

注:用[ ]越界是断言错误。

#include<iostream>
using namespace std;
int main()
{string const s1("hello world");for (int i = 0; i < s1.length(); i++){cout << s1.at(i);}cout << endl;return 0;
}

注:at()越界时候报的是非法。

2.3.2 迭代器(iterator)遍历

迭代器有两种,还有一个叫做反向迭代器,就是从尾部开始遍历,我们这里介绍正向迭代器
iterator是一个类型定义在string里面,所以它要指定类域,才能取到。
begin是开始的指针,end是指向‘\0’的指针,注意是左闭右开!! 

#include<iostream>
using namespace std;
int main()
{string s1("hello world");for (string::iterator i = s1.begin(); i != s1.end(); i++){cout << *i;}cout<<endl;return 0;
}

反向迭代器就是从后开始往前移动:
这里要引出的是 reverse_iterator 其实这里的rbegin是字符串的最后一个位置(不是\0),并且这里的指针也是++,向前移动。

#include<iostream>
using namespace std;
int main()
{string s1("hello world");for (string::reverse_iterator i = s1.rbegin(); i != s1.rend(); i++){cout << *i;}cout<<endl;return 0;
}

注:迭代器像指针,但不是指针。

2.3.3  范围for
  • 自动取容器中的数据,赋值给e,自动迭代,自动往后走,自动结束。
#include<iostream>
using namespace std;
int main()
{string s1("hello world");for (auto e:s1){cout << e;}cout<<endl;return 0;
}

注:for循环的底层实现就是迭代器!

2.4 string类对象的修改操作(Modifiers)

2.4.1  push_back
  • 在字符串尾插字符C
#include<iostream>
using namespace std;
int main()
{string s1("hello world");s1.push_back('!');cout << s1 << endl;return 0;
}

2.4.2  append
  • append尾插,可以插入字符串
#include<iostream>
using namespace std;
int main()
{string s1("hello world");s1.append(" hhhh!");cout << s1 << endl;return 0;
}

2.2.3 operator+=
  • operator+=可以实现在字符串后面追加字符或者字符串,并且函数的可读性更高,所以我们一般选择使用+=来实现对对象的追加
#include<iostream>
using namespace std;
int main()
{string s1("hello world");s1+=(" hhhh!");cout << s1 << endl;s1 += ('x');cout << s1 << endl;return 0;
}

2.2.4  assign(了解即可)
  • assign赋值,字符覆盖
void test_string9() {// 创建一个初始内容为"xxxxxxx"的字符串strstring str("xxxxxxx");// 创建一个基础字符串base,string base = "The quick brown fox jumps over a lazy dog.";// 使用assign方法将base的全部内容赋给str,替换str原来的内容str.assign(base);// 输出赋值后str的内容cout << str << '\n';// 第二种用法:使用assign方法从base的第5个字符开始截取10个字符,并将这10个字符赋给strstr.assign(base, 5, 10);// 输出截取并赋值后str的内容cout << str << '\n';
}

2.2.5   insert
  • insert都是在当前位置的前面插入
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;s1.insert(0, "abc");cout << s1 << endl;return 0;
}

2.2.6  erase

  • erase删除:表示第pos个位置开始后len个字符删除,len的默认值是npos
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;s1.erase(5, 2);cout << s1 << endl;return 0;
}

2.2.7  replace

  • replace替换:将pos位置开始的len个字符替换成字符串
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1 << endl;s1.replace(6, 1, "xx");cout << s1<< endl;return 0;
}

2.2.8  swap
  • 交换2个string类对象的指针指向
void test_string9()
{string s2("hello world hello abcd");string s3;s3.reserve(s2.size());for (auto ch : s2){if (ch != ' '){s3 += ch;}else{s3 += "20%";}}cout << s3 << endl;s2.swap(s3);cout << s2 << endl;
}

总结:

  • 在string尾部追加字符时,s.push_back / s.append() / += 三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
  • 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。

2.5 string类对象的操作(operations)

c_str(重点)
返回c格式的字符串
find 
从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置
rfind
从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置
substr
str中从pos位置开始,截取n个字符,然后将其返回
2.5.1  c_str
  • 以C语言的方式打印字符串
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.c_str() << endl;return 0;
}

注:不能通果c_str 返回的指针去修改字符串,因为它指向的是常量区域。

2.5.2  find
  • find从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置,如果没有找到会返回npos
#include<iostream>
using namespace std;
int main()
{string s1("file.cpp");size_t pos1 = s1.find('.');if (pos1 != string::npos){string suffix = s1.substr(pos1);cout << suffix << endl;}else{cout << "没找到后缀" << endl;}return 0;
}

 

2.5.3  refind
  • rfind从字符串pos位置开始向前找字符c,返回该字符在字符串中的位置,如果没有找到会返回npos
#include<iostream>
using namespace std;
int main()
{string s1("file.cpp.tar.zip");size_t pos1 = s1.rfind('.');if (pos1 != string::npos){string suffix = s1.substr(pos1);cout << suffix << endl;}else{cout << "没有后缀" << endl;}return 0;
}

 

2.5.4  substr
  • str中从pos位置开始,截取n个字符,然后将其返回
#include<iostream>
using namespace std;
int main()
{string s1("hello world");cout << s1.substr(3, 4) << endl;cout << s1.substr(3, 12) << endl;
}

如何利用上面接口,区分开网站的协议,域名,网址呢?

void test_string10()
{string url1("https://legacy.cplusplus.com/reference/string/string/substr/");string protocol, domain, uri;//协议,域名,网址size_t i1 = url1.find(':');if (i1 != string::npos){protocol = url1.substr(0, i1 - 0);cout << protocol << endl;}size_t i2 = url1.find('/',i1+3);if (i2 != string::npos){domain = url1.substr(i1+3, i2-(i1+3));cout << domain << endl;uri = url1.substr(i2+1);cout << uri << endl;}
}

2.6  string类非成员函数

其实这里用的不多,不做过多的讲解
但是这个getline函数是可以用到一些题目中来读取字符串的,他遇到换行符就会停止读取,遇到空格不会.

 2.6.1  getline

获得一个字符串(hello word!)里面最后一个单词的长度

#include<iostream>
#include<string>
using namespace std;
int main()
{string line;// 不要使用cin>>line,因为会它遇到空格就结束了// while(cin>>line)while (getline(cin, line)){size_t pos = line.rfind(' ');cout << line.size() - (pos+1) << endl;}return 0;
}

 

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

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

相关文章

矩阵间关系的建立

参考文献 2-D Compressive Sensing-Based Visually Secure Multilevel Image Encryption Scheme 加密整体流程如下: 我们关注左上角这一部分: 如何在两个图像之间构建关系,当然是借助第3个矩阵。 A. Establish Relationships Between Different Images 简单说明如下: …

R语言 | 上下双向柱状图

1. 效果图 2. 代码 # 生成测试数据 difdata.frame(labelspaste0("pathway", 1:3),upc(30,15,1),downc(10,20,40) ) rownames(dif)dif$labels dif#变形 difreshape2::melt(dif) dif# 绘图 ggplot(dif, aes(xlabels, yifelse(variable"up", value, -value), …

react 面试题(2024 最新版)

1. 对 React 的理解、特性 React 是靠数据驱动视图改变的一种框架&#xff0c;它的核心驱动方法就是用其提供的 setState 方法设置 state 中的数据从而驱动存放在内存中的虚拟 DOM 树的更新 更新方法就是通过 React 的 Diff 算法比较旧虚拟 DOM 树和新虚拟 DOM 树之间的 Chan…

单例设计模式(3)

单例模式&#xff08;3&#xff09; 实现集群环境下的分布式单例类 如何理解单例模式中的唯一性&#xff1f; 单例模式创建的对象是进程唯一的。以springboot应用程序为例&#xff0c;他是一个进程&#xff0c;可能包含多个线程&#xff0c;单例代表在这个进程的某个类是唯一…

ROS 2边学边练(6)-- 何为参数(parameters)

概念 这一知识点&#xff0c;应该很好理解&#xff0c;参数就是节点的属性&#xff0c;比如猫科动物&#xff0c;它所拥有的属性&#xff08;参数&#xff09;有胡子、能伸缩的爪子、随光线缩放自如的瞳孔、夜视能力、优秀的弹跳力、萌等等。ROS节点中参数支持的数据类型有整型…

Springboot中的三层架构

我们在进行前后端交互的时候&#xff0c;会分为数据访问&#xff0c;业务逻辑&#xff0c;接受请求并响应数据三个操作&#xff0c;这三部分其实是可以拆分的&#xff0c;让他们解耦&#xff0c;否则代码复用性差并且不易维护&#xff0c;所以诞生了三层架构——1.Dao(数据访问…

VuePress基于 Vite 和 Vue 构建优秀框架

VitePress 是一个静态站点生成器 (SSG)&#xff0c;专为构建快速、以内容为中心的站点而设计。简而言之&#xff0c;VitePress 获取用 Markdown 编写的内容&#xff0c;对其应用主题&#xff0c;并生成可以轻松部署到任何地方的静态 HTML 页面。 VitePress 附带一个用于技术文档…

Redis 常见数据结构及命令

目录 一.Redis常见的数据结构 二.Redis数据结构对应的命令 1.String类型 2.Hash类型 3.List类型 4.Set类型 5.Sorted Set类型 一.Redis常见的数据结构 Redis支持多种数据结构&#xff0c;包括字符串&#xff08;string&#xff09;、哈希&#xff08;hash&#xff09;、…

【Linux】认识线程池 AND 手撕线程池(正常版)

文章目录 0.回顾进程池1.计算机层面的池化技术2.线程池预备知识2.1介绍线程池2.2设计线程池的意义是什么&#xff1f;2.3其他知识 3.回顾C类与对象3.1cpp什么情况下成员函数必须是静态的&#xff1f;3.1可变参数列表3.2格式化输出函数3.3预定义符号 4.图解线程池运作原理4.0完整…

Java_22 蓝桥杯真题——拼数

问题描述 给定几 个正整数 a1,a2....,an&#xff0c;你可以将它们任意排序, 现要将这 几 个数字连接成一排&#xff0c;即令相邻数字收尾相接&#xff0c;组成一个数。 问&#xff0c;这个数最大可以是多少。 输入格式 第一行输入个正整数 n(l < n< 20)。 第二行输入几 个…

二维码门楼牌管理应用平台建设:一扫即知,智慧生活新篇章

文章目录 前言一、二维码门楼牌管理的创新之处二、二维码门楼牌管理应用平台的实际应用三、二维码门楼牌管理应用平台的未来展望 前言 随着信息技术的飞速发展&#xff0c;二维码门楼牌管理应用平台应运而生&#xff0c;为城市管理和居民生活带来了极大的便利。只需轻轻一扫&a…

JVM 八股(一)

JVM 1.类装载的执行过程 加载&#xff1a; 元空间存储构造函数&#xff0c;方法&#xff0c;字段等 验证 准备 解析 初始化 使用 2.垃圾回收 什么是垃圾回收&#xff1f;怎样找到这些垃圾&#xff1f;找到垃圾后是怎么清除的&#xff08;垃圾回收算法&#xff09;&#x…

减少样式计算的范围和复杂度

本文翻译自 Reduce the scope and complexity of style calculations&#xff0c;作者&#xff1a;Jeremy Wagner&#xff0c; 略有删改。 JavaScript通常用来改变页面的视觉效果。比如通过改变style样式或者通过计算后改变页面布局&#xff0c;比如搜索或排序数据。长时间运行…

.NET 开发支持技术路线 .Net 7 将停止支持

.NET 开发技术路线图 微软方面强调&#xff0c;使用 .NET 7 的应用程序将在支持结束后继续运行&#xff0c;但用户可能无法获得 .NET 7 应用程序的技术支持。他们不会继续为 .NET 7 发布新的安全更新&#xff0c;用户可能会面临安全漏洞问题。 开发人员必须使用 .NET 8 SDK 构建…

蓝桥杯第七届大学B组详解

目录 1.煤球数量&#xff1b; 2.生日蜡烛&#xff1b; 3.凑算式 4.方格填数 5.四平方和 6.交换瓶子 7.最大比例 1.煤球数量 题目解析&#xff1a;可以根据题目的意思&#xff0c;找到规律。 1 *- 1个 2 *** 3个 3 ****** 6个 4 ********** 10个 不难发现 第…

安科瑞路灯安全用电云平台解决方案【电不起火、电不伤人】

背景介绍 近年来 &#xff0c;随着城市规模的不断扩大 &#xff0c;路灯事业蓬勃发展。但有的地方因为观念、技术、管理等方面不完善 &#xff0c;由此引发了一系列安全问题。路灯点多面广 &#xff0c;一旦漏电就极容易造成严重的人身安全事故。不仅给受害者家庭带来痛苦 &am…

计算方法实验3:反幂法求按模最小特征值及特征向量

Task Algorithm LU-Doolittle分解 A L U \mathbf{A}\mathbf{L}\mathbf{U} ALU 其中 L \mathbf{L} L为单位下三角阵, U \mathbf{U} U为上三角阵. 则 A x b \mathbf{A}\mathbf{x}\mathbf{b} Axb可化为 L U x L y b \mathbf{L}\mathbf{U}\mathbf{x}\mathbf{L}\mathbf{y}\math…

STM32的简介

内存 一般MCU包含的存储空间有FLASH和RAM,&#xff08;RAM和flash又有片上和片外的区别&#xff0c;片上表示mcu自带的&#xff0c;已经封装在MCU内部的&#xff0c;片外表示外挂的&#xff0c;当项目中需要做一些复杂的应用&#xff0c;会存在资源不足的情况&#xff0c;这时…

JavaScript基础语法–变量

文章目录 认识JavaScript变量程序中变量的数据&#xff08;记录&#xff09;–变量变量的命名格式在Java script中变量定义包含两部分1. 变量声明&#xff08;高级JS引擎接下来定义一个变量&#xff09;2. 其他的写法 变量命名的规范&#xff08;遵守&#xff09;变量的练习a. …

【微信】公众号开发

文章目录 概述与微信交互环境准备开发者工具 注册公众号服务器基本配置存取access_token示例代码来源 概述 不同类型公众号主要区别 与微信交互 实际上我们在公众号里的所有操作&#xff0c;都会发送到微信的服务器上&#xff0c;微信服务器将这些动作的具体含义按照一定的…