string类的使用与实现

devtools/2024/9/20 1:28:54/ 标签: c++, 算法, 数据结构

标准库中的string类


string类(了解)

string类的文档介绍

注意:在使用string类时,必须包含#include头文件以及using namespace std;

auto和范围for

在了解string的用法前在学习一个知识;


auto关键字

  • auto是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期推导而得。
  • 用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
  • auto不能作为函数的参数,可以做返回值,但是建议谨慎使用(尽量不要使用,只要套娃,就很难使用。)
  • auto不能直’接用来声明数组
  • 在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。

相关解释与代码

代码内容:
void Test3()
{int a = 10;auto b = a;auto c = 'a';auto d = func1();// 编译报错:rror C3531: “e”: 类型包含“auto”的符号必须具有初始值设定项// 这点与引用 十分相似//auto e;cout << typeid(b).name() << endl;cout << typeid(c).name() << endl;cout << typeid(d).name() << endl;int x = 10;auto y = &x;auto* z = &x;auto& m = x;cout << typeid(x).name() << endl;cout << typeid(y).name() << endl;cout << typeid(z).name() << endl;auto aa = 1, bb = 2;// 编译报错:error C3538: 在声明符列表中,“auto”必须始终推导为同一类型//auto cc = 3, dd = 4.0;// 编译报错:error C3318: “auto []”: 数组不能具有其中包含“auto”的元素类型//auto array[] = { 4, 5, 6 };}
分析解释

“auto”的符号必须具有初始值设定项

因为,auto本来就是 编译器通过对相关变量的推导,才能得到类型。没有初始化,怎么推导;

为什么不能做参数 但能做返回值

这是就祖师爷设计的问题,一些遐思。而且做返回值若遇到那种 函数套函数的,在用变量接收时就难以辨认,这个变量到底是什么类型

auto text1()
{double a = 2.0;return a;
}auto text2()
{return text1();
}auto text3()
{return text2() + 3;
}

 范围for

  • 对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此C++11中引入了基于范围的for循环。for循环后的括号由冒号“ :”分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
  • 范围for可以作用到数组和容器对象上进行遍历
  • 范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

 底层

 相关解释与代码

代码内容:
void Test9()
{string s2("hello world");string::iterator it = s2.begin();while (it != s2.end()){*it += 2;cout << *it << " ";++it;}cout << endl;//for (auto e : s2)//{//	e -= 2;//	cout << e << " ";//}//cout << endl;for (auto& e : s2){e -= 2;cout << e << " ";}cout << endl;
}

分析解释 

Auto  与模板相似 不一样地方也有;(相同的地方,都是由编译器推导)

范围for的注意点;

Auto name :    返回的是值 相当于浅拷贝    

  &     则是返回引用 就能改变

一般来说 只对于非常大的对象 用引用才能增大效率

小的 影响十分小

string类的常用接口说明 

这里只简绍几种常见的,具体的可以去string类的文档自行查找哦。


string类对象的常见构造

点击观看全部内容

第一次接触看这里库里的内容,第一步就是猜测,猜这个函数应该怎么应用;然后看具体是什么在敲代码验证;

相关解释与代码

代码内容: 
void Test4()
{string s0("abcdefg");//default (1)string();string s1;//from c - string(4)string(const char* s);string s4("aaaaaaaaa");//substring (3)	string(const string & str, size_t pos, size_t len = npos);string s3(s0, 0, 1);//copy (2)	string(const string & str);string s2(s0);//from sequence(5) string(const char* s, size_t n);string s5("aaaa", 2);//fill(6) string(size_t n, char c);string s6('a', 6);//range(7) template <class InputIterator>//     string(InputIterator first, InputIterator last);string s7(++s0.begin(), s0.end()--);
}

分析解释

可以在main() 函数里打印,验证猜想 

         s7是迭代器的用法,如果这里看不懂可以看完下面的” string类对象的访问及遍历操作(iterator)“ 再来看,会有更加深刻的理解哦;

operator会在后面的深浅拷贝里仔细分析哦;

string类对象的容量操作(capacity)

相关解释与代码 

代码内容: 
void Test5()
{string s1("abcdefg");string s2(s1);cout << s1.size() << endl;cout << s1.length() << endl;cout << s1.capacity() << endl << endl;cout << s1.empty() << endl;s1.clear();cout << s1.empty() << endl;cout << s1.size() << endl;cout << s1.capacity() << endl << endl;string s3;//reserve 的好处  提前开好空间  在插入时不用在扩容  提升了效率s2.reserve(sizeof(s2));//operator = 重载  后面深浅拷贝会说s3 = s2;s2.resize(20, 'v');cout << s2 << endl;cout << s2.size() << endl;cout << s2.capacity() << endl;std::string str(100, 'x');std::cout << "1. capacity of str: " << str.capacity() << '\n';str.resize(10);std::cout << "2. capacity of str: " << str.capacity() << '\n';str.shrink_to_fit();std::cout << "3. capacity of str: " << str.capacity() << '\n';
}

分析解释

打印结果

 注意点1:

size 和length 的用法是一摸一样的;但为什么名字不一样呢?

因为c++ 的历史太过久远,原本是用length的  但是后来为了与其他容器 保证一至;所以都用了size; 这一点就体现的面对程序的封装;

注意点2:

为啥capacity 不一样呢?从库里的解释(如下图)可知,capacity 的话题等于 或 大于 字符长度的;这完全取决于编译器,c++没有严格的要求;

这里就可以看看VS2019中 string 是怎么开辟空间的

可以看出来,就第一次改变 是大概两倍,后面都接近 1.5倍。(不精确的原因主要是容器内容 不算字符串最后的’/0‘  ,但会为它开辟空间;

还有就是

VS2019 中string 的实现 由两个组成,_Buf   _Ptr,

原理大概就是:

先在栈上开辟 buf 大小为 16 字节;若大小超过,就删除移到 堆上建立ptr(双倍的buf),然后后面再扩容就是 1.5倍

注意点3:

reverse

代码及其打印


string类对象的访问及遍历操作(iterator)

先说,迭代器是类似与指针的一个东西,虽然有的容器迭代器底层就是指针实现的,但是并不是全部。

相关解释与代码

代码内容:
void Test8()
{//string s1("hello worldxxxxxxxxxxxxx");//auto it = s1.begin();//cout << typeid(s1).name() << endl;string s2("hello world");string::iterator it = s2.begin();while (it != s2.end()){*it += 2;cout << *it << " ";++it;}cout << endl;string::reverse_iterator rit = s2.rbegin();while (rit != s2.rend()){cout << *rit << " ";++rit;}cout << endl;const string s3("hello world");//同时体现了 auto的方便性;//string::const_iterator cit = s3.begin();auto cit = s3.begin();while (cit != s3.end()){//*cit += 2;cout << *cit << " ";++cit;}cout << endl;//string::const_reverse_iterator rcit = s3.rbegin();auto rcit = s3.rbegin();while (rcit != s3.rend()){// *rcit += 2;cout << *rcit << " ";++rcit;}cout << endl;
}
分析解释 

总结

迭代器有四种: 普通迭代器   const迭代器

                       普通反向迭代器    const 反向迭代器

 string类对象的读取

string 的底层地址是连续的 因此能源【】来读;像list就不行

 

一个可读可写的接口

一个 只读接口  看看权限大小用合适的  string 有很多类型都是这样

相关解释与代码

代码内容: 
void Test11()
{string s1("hello world");s1.back() = '!';cout << s1 << endl;//s1.front() = 'aaaa';//front 的返回类型是 char  这种写法虽然能过 但只取第一个  最好不写这种s1.front() = 'a';cout << s1 << endl;for (unsigned i = 0; i < s1.size(); ++i){std::cout << s1.at(i);}cout << endl;for (unsigned i = 0; i < s1.size(); ++i){std::cout << s1[i];}cout << endl;
}

         

分析解释

三种遍历方式

  1. 下标+[]   2. 迭代器  3. 范围for    (虽然at能遍历,但是不常用且和【】差不多,这里就不列举了)

  string类对象的修改操作

 这里要提醒的点就是,这里的参数类型很多,要注意不能弄错了;

相关解释与代码

   

代码内容:

string类非成员函数

相关代码和参考 

代码内容:

分析解释

这里主要提一下 getline,其他的基本在实现其他的时候也用到过,都知道怎么使用;

getline 就是 改变 插入 流出的方式;

举一个列子 编译器默认 cin 时,输入‘ ’ (空格)是要记录到下一个数据上的;但如果用getline重定义cin,就可以自己定输入那个符号时,接下来的会插入下一个数据中 

string类和对象的操作函数

这些函数各有各的优缺点,虽然string的操作接口很多,但也不是都有用,很恶心

标红的是自我感觉比较常用的,其他也了解了解更好;

参考代码及打印 

void SplitFilename(const string& s1)
{cout << "split" << s1 << endl;size_t found = s1.find_last_of("\\/");cout << "path:" << s1.substr(0, found) << endl;cout << "name:" << s1.substr(found + 1) << endl;
}void Test15()
{string s2("asdfg");cout << s2.data() << endl;string s("test.cpp.zip.zzp");size_t pos = s.find('.');//返回的还是stringstring suffix = s.substr(pos);cout << suffix << endl;pos = s.rfind('.');suffix = s.substr(pos);cout << suffix << endl;std::string str("Please, replace the vowels in this sentence by asterisks.");std::cout << str << '\n';std::size_t found = str.find_first_of("abc");while (found != std::string::npos){str[found] = '*';found = str.find_first_of("abc", found + 1);}std::cout << str << '\n' << '\n';std::string st1("Please, replace the vowels in this sentence by asterisks.");std::size_t found1 = st1.find_first_not_of("abc");while (found1 != std::string::npos){st1[found1] = '*';found1 = st1.find_first_not_of("abc", found1 + 1);}std::cout << st1 << '\n';//在流输入过程中,单独的\ 会被编译器当作操作符,若要使用需要 在\前加 \  ;std::string ss1("/usr/bin/man");std::string ss2("D:\\qq\\QQMusic\\AssGenerator");//如此应用,可以很容易找到所在文件架//应用的一种 文件名 与路径分离SplitFilename(ss1);SplitFilename(ss2);
}

参考打印结果 

总结

这里解释一下这里的find

  • find:  从pos位置向后找到第一个字符  并返回对应下标
  • rfind: 从pos位置向后找到最后一个字符  并返回对应下标
  • find_frist_of:从pos位置向后找所给字符串里的任意字符后  并返回对应下标
  • find_last_of:从pos位置向前找所给字符串里的任意字符后  并返回对应下标
  • find_frist_not_of:从pos位置向后找所给字符串里的任意没有的字符后  并返回对应下标
  • find_last_not_of :从pos位置向前找所给字符串里的任意字符后  并返回对应下标

这个是any of  是任意一个 字符(“abcd”)找到中任意一个字符 就返回Find(“a”) 只有一个

 


http://www.ppmy.cn/devtools/100610.html

相关文章

反转链表 II 简单链表问题

给你单链表的头指针 head 和两个整数 left 和 right &#xff0c;其中 left < right 。请你反转从位置 left 到位置 right 的链表节点&#xff0c;返回 反转后的链表 。 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5], left 2, right 4 输出&#xff1a;[1,4,3,2…

OpenAI 将向企业开放 GPT-4o 模型定制版

OpenAI 最近发布了一项新功能&#xff0c;使企业客户可以通过微调技术定制 GPT-4o 模型&#xff0c;从而应对日益激烈的人工智能竞争&#xff0c;并展示其投资回报。这一新功能的推出使得企业能够使用自己的数据对 GPT-4o 模型进行个性化调整&#xff0c;以满足他们的特定需求和…

Linux云计算 |【第二阶段】SECURITY-DAY4

主要内容&#xff1a; Kali系统、扫描与抓包、Nginx安全加固、Linux基本防护 补充&#xff1a;使用Curl命令查看网页头部信息和页面内容 不加选项&#xff0c;默认查看网页的内容&#xff1b; [ -I ] 选项&#xff1a;访问服务器页面时&#xff0c;显示HTTP的头部信息&#xf…

git提交项目,报403无权限

这个在公司内网git上提交项目时&#xff0c;使用的是刚分配到的账号和密码。创建完组和项目后一切准备完毕了&#xff0c;但是在提交时缺出了乌龙&#xff0c;报403&#xff0c;上面一堆英文&#xff0c;大致的意思是说我没有上传本项目的权限&#xff0c;报错信息如下图所示&a…

盘古信息IMS MCM制造协同管理系统:为中小企业数字化转型量身打造的数字化方案

近年来&#xff0c;全球经济的不稳定性&#xff0c;给中小企业的经营和发展带来了巨大的挑战。为提升企业竞争力&#xff0c;中小企业纷纷谋求数字化转型路径&#xff0c;优化生产流程、提高运营效率、降低生产成本&#xff0c;以应对变幻莫测的市场环境。IMS MCM是盘古信息为广…

浅谈Java Spring Boot

一、基本介绍 Spring Boot是由Pivotal团队提供的全新框架&#xff0c;其设计目的是用来简化新Spring应用的初始搭建以及开发过程。该框架使用了特定的方式来进行配置&#xff0c;从而使开发人员不再需要定义样板化的配置。通过这种方式&#xff0c;Spring Boot致力于在蓬勃发展…

45+用户占比近30%,网文产业如何赋能IP长链?

网文市场加速发展&#xff0c;巨头抢占中老年用户 作者&#xff5c;吕娆炜 排版&#xff5c;张思琪 干货抢先看 1. 我国网文产业市场规模突破3000亿元&#xff0c;在用户方面&#xff0c;截至2023年底&#xff0c;我国网文用户数量达5.37亿&#xff0c;同比增长9%&#xff0c…

系统架构师学习笔记 (一)

学习目标 了解系统架构的基本概念。掌握系统架构设计的原则。学习如何评估和选择合适的技术栈。了解云服务的基础知识及其在架构中的应用。 系统架构的基本概念 定义&#xff1a;系统架构是指一个系统的设计蓝图&#xff0c;它定义了系统的各个组成部分及其相互之间的关系。…

java知识点:包装类

包装类&#xff1a; 基本概述&#xff1a; java是面向对象的&#xff0c;但是java的基本数据类型却不能创建对象&#xff0c;不是面向对象的&#xff0c;为了解决这个问题&#xff0c;在设计类的时候为每个基本数据类型设计了一个对应的类&#xff0c;称为包装类 包装类把基本…

正则表达式简记

正则表达式简记 一、查找开头子串与结尾子串二、分组匹配替换字符串三、查找嵌套字符串 一、查找开头子串与结尾子串 正则表达式中以^字符表示待查找子串位于字符串开头位置&#xff0c;以$字符表示待查找子串位于字符串结尾位置&#xff0c;示例代码如下&#xff1a; import…

25版王道数据结构课后习题详细分析 第五章 树与二叉树 5.3 二叉树的遍历和线索二叉树 选择题部分

一、单项选择题 ———————————————————— ———————————————————— 解析&#xff1a;二叉树中序遍历的最后一个结点一定是从根开始沿右子女指针链走到底的结点,设用p指示。若结点p不是叶结点(其左子树非空)&#xff0c;则前序遍历的最后一…

TCP/UCP

Loop本地回环 定义&#xff1a;Loop本地回环通常指的是以127开头的IP地址段&#xff08;127.0.0.1 – 127.255.255.254&#xff09;&#xff0c;其中127.0.0.1是最常用的地址&#xff0c;被称为本地回环地址&#xff08;Loop back address&#xff09;。特点&#xff1a;不属于…

RAG 技术原理

目录 RAG 技术原理背景和概念实现步骤1. ChatGPT/GLM 等大语言模型的调用2. 读取知识库数据3. 文本索引与答案检索4. 文本嵌入与向量检索5. 文本多路召回与重排序6. 文本问答Promopt优化 原创链接 RAG 技术原理 背景和概念 在自然语言处理领域&#xff0c;大型语言模型&#x…

Ubuntu 20.04安装中文输入法

本文旨在详细介绍在Ubuntu 20.04操作系统中安装中文输入法的步骤和方法。我们将从选择适合的中文输入法软件、下载与安装过程、配置输入法设置以及解决可能遇到的问题等方面展开讲解&#xff0c;帮助用户轻松实现在Ubuntu 20.04系统下流畅输入中文的需求。无论你是Ubuntu的新手…

MyBatis框架学习

系列文章目录 第一章 基础知识、数据类型学习 第二章 万年历项目 第三章 代码逻辑训练习题 第四章 方法、数组学习 第五章 图书管理系统项目 第六章 面向对象编程&#xff1a;封装、继承、多态学习 第七章 封装继承多态习题 第八章 常用类、包装类、异常处理机制学习 第九章 集…

sqlilabs less16-20关手工注入

第16关 一.判断闭合方式 闭合方式点“&#xff09; admin")and11# 二.判断数据库长度 admin") and if(length(database())>7, 0, sleep(5))# 页面无延迟 admin") and if(length(database())>8, 0, sleep(5))# 页面有延迟说明数据库长度为8 三.判断数…

Azure OpenAI citations with message correlation

题意&#xff1a;“Azure OpenAI 引用与消息关联” 问题背景&#xff1a; I am trying out Azure OpenAI with my own data. The data is uploaded to Azure Blob Storage and indexed for use with Azure AI search “我正在尝试使用自己的数据进行 Azure OpenAI。数据已上传…

MFC隐藏tabCtrl控件的页面

问题&#xff1a;在使用MFC里面的tabCrtl控件时&#xff0c;有时需要将其中的某些个页面隐藏起来。 解决&#xff1a;首先&#xff0c;隐藏是不可能隐藏的&#xff0c;MFC里面没有可以隐藏tab页的接口&#xff0c;只能通过删除Item&#xff0c;重新添加的方式来完成隐藏。 比如…

Cobalt Strike 4.8 用户指南-第二节-用户界面

2.1、概述 Cobalt Strike用户界面分为两部分。界面顶部显示会话或目标的可视化。界面底部显示与你交互的每个 Cobalt Strike 功能或会话的选项卡。可以单击这两个部分之间的区域并根据自己的喜好调整它们的大小。 # 2.2、工具栏 顶部的工具栏提供对常见 Cobalt Strike功能的快…

基于SpringBoot+Vue的家教管理系统

文章目录 前言1.项目类型2.技术栈介绍1.客户端技术栈介绍2.服务端技术栈介绍 3.功能介绍1.客户端功能2.服务单功能 4.项目亮点5.适用场景6.项目展示1.客户端展示2.服务端展示 7.诚邀参与 前言 大家好&#xff0c;我是执手天涯&#xff0c;今天非常荣幸地向大家介绍一款基于Spr…