C++利剑string类(详解)

2023-12-02 21:44
文章标签 c++ 详解 string 利剑

本文主要是介绍C++利剑string类(详解),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言:大家都知道在C语言里面的有  char  类型,我接下来要讲的 string 类功能是使用 char  类型写的类,当然这个是C++官方写的,接下来我们将会学会使用它,我们会发现原来  char  这种类型是还能这么好用,授人以鱼不如授人以渔,接下来我将会讲不少干货,不仅仅是教会我们使用,还会教我们如何模拟实现一个  string  类,我也会教大家如何去读英文文档,话不多说,正文开始。

目录

一,string  类初识

1)英文文档的查找和阅读

2)string类初步使用

string 如何创建对象

string  成员函数的使用

1)size()

2)  length() 

3)  max_size() 

4)resize()

 5)  capacity()

6)    reserve() 

7)  clear() 

8)    at() 

9)  back() /front()

 10)append()

11)  push_back() 

10)    insert() 

13)erase

14)c_str()

15)find()/rfind

16)substr()

17)getline()

二,模拟实现


一,string  类初识

1)英文文档的查找和阅读

想要了解一个语言里面的一个语法,有什么比直接去它的官网看原汁原味的英文文档更加得劲呢?我现在贴出C++的官网cplusplus.com/reference/

打开之后我们会看到这个页面

因为新版本不具有搜索功能,为了我们方便使用,我们切回老版本,点击图上的这个

之后我们就能在上面的reserch进行搜索了

我们搜索  string  就会显示 string 类的提供的所有接口和功能,我们先看它对string类的描述,也就是第一大段

这上面明确说明了,string类是一串char字符,并且提供了一系列的接口,在下面是它的接口或者成员函数,让我们来看看,如何查看成员函数的功能,使用方法。

我们阅读英文文献不一定要全部明白意思,我们可以从上面的四个方面入手,就能大概理解功能和使用方法,碰到不会的单词我们可以用搜索引擎,但不建议使用翻译软件直接翻译,因为这样即不准确也不利用我们的成长,以后我们还会阅读不少的英文文献,只有自身硬才能笑到最后。

2)string类初步使用

string 如何创建对象

在使用时,我们首先可以把它定义的对象当作一个字符串,但是这个对象拥有很多C语言字符串没有的特性,比如不需要我们考虑它的空间够不够,我们可以使用运算符对它进行操作,也就是进行+,+=,=等操作,并且提供了许多接口帮助我们减少手搓的代码量

话不多说,我们先定义一个string 对象吧

string c1;      //里面只有一个\0
string c2("wzdhxhn");   //里面是"wzdxhn\0"
string c3=("wzdxhn");   //里面是"wzdxhn\0"
string c4=c3;           //里面也是"wzdxhn\0"
string c5(c4);          //里面还是"wzdxhn\0"
c1=c5+c4;              //里面可是"wzdxhnwzdxhn\0"哦
c5+=c5;                  //里面是"wzdxhnwzdxhn\0"哦
for(int i=0;i<7;i++)
c2[i]=6;                  //c2里面的内容将会全部变成6
cout<<c1;
cin>>c1;                    //支持输入输出流

没错,真的是一场酣畅淋漓的初始化和赋值,string都支持这种操作,并且拷贝都是深拷贝哦,如果在C里面我们就需要循坏进行赋值了,刚开始是不是就感受到了它的便利。编译器:最终还是我承受了一切。

string  成员函数的使用

前提知识:size_t npos = -1这个是C++库里面的,代表整形的最大值,如果它是默认参数,代表知道\0等结束标志结尾

1)size()

sizeicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/size/

 没有函数参数,这个函数可以获取string里面字符串的长度,不包括\0,然后返回

string s("hello");
cout<<s.size();      //输出s的长度5
2)  length() 

string::length - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/length/

 功能类似size,没有参数,也是返回字符串长度,不包括\0

string s("hello");
cout<<s.length();      //输出s的长度5
3)  max_size() 

 
string::max_size - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/max_size/

 没有参数,返回字符串里面ASCLL码值的最大值这个可以改变字符串的大小,

4)resize()

string::resize - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/resize/

 只有一个参数就是字符串调整后的大小(以\0为标注),没有返回值,可以扩大和缩小字符串长度,扩大可以指定一个参数填充,也可以选择不指定,这个参数有默认参数,但要注意这个如果指定大小小于字符串的大小则会将数据覆盖

string s("hello");
cout<<s.resize(10,'6');    //输出:hello66666
cout<<s.resize(2);         //输出:he
 5)  capacity()

string::capacity - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/capacity/

没有参数,返回一个无符号整形,代表调整后储存字符串空间的大小,这个会返回string类的字符串空间的容量,要注意的是,字符串空间的容量不等于长度,可能有一些空间存在,但是我们没使用,相当于多开了空间

6)    reserve() 

string::reserve - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/reserve/一个参数没有返回值,这个可以重新定义容量,但是要注意只能扩大,不能缩小容量,因为编译器会做判断,如果重定义的容量小于之前的字符串空间的容量就不会进行任何操作,也不会报错。只有一个参数,就是你再次定义的容量大小

7)  clear() 

string::clear - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/clear/没有参数,没有返回值,顾名思义,清理数据,大小和长度。,但是不会改变开的空间大小,也就是字符串空间大小

8)    at() 

string::at - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/at/这个相当于下标访问,只有一个参数就是你要访问的字符串位置 ,最后返回你要的下标元素的引用

string s("hello");
s.at(2);    //等价于s[2]
9)  back() /front()

 string::back - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/back/

 没有参数,返回最后一个字符,front()则是返回第一个字符

string s("hello");
cout<<s.back();       //输出:o
 10)append()

 string::append - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/append/

 这个有两个函数参数,一个是插入的字符串或者字符,第二个参数有默认参数0,代表插入的位置,返回类型是插入后的string类

string s("hello");
s.append(" world");
cout<<s;      //输出:hello world
11)  push_back() 

string::push_back - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/push_back/这个成员函数有一个参数,没有返回值,是要注意插入的只能是字符,或者ASCLL码值而且是尾插,插入字符串请使用append

string s("nihao");
s.push_back('h');  
cout<<s;         //输出:nihaoh
10)    insert() 

string::insert - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/insert/

这个函数支持的参数很多

从图什么我们能知道,返回类型是插入后的string类或者迭代器,这个insert功能强大,不仅支持插入字符,也支持字符串,支持各种各样的插入方式,即带来了遍历也变得复杂了

13)erase

string::erase - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/erase/

这个函数功能很明确了,就是删除字符串,没有参数,返回值是删除后的string类或者迭代器,因此不做举例了

14)c_str()

string::c_str - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/c_str/这个会将string类型 转化为C语言的char* 类型,返回类型是  const char*   ,但要注意返回类型是const类型,只读不写

15)find()/rfind

string::find - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/find/

这个函数的作用就是查找字符或者字符串里面的字符,返回它在字符串里面的位置,注意找字符串的时候不是找子字符串而是找属于这个子串里面的字符

 find()是从前往后找,rfind()则是从后往前找,参数差不多

string s("hello,world");
cout<<s.find('l',5);  结果是:10,返回为world里面的l,因为的从5 o开始查找的
16)substr()

string::substr - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/substr/这个函数的作用就是返回原字符串中的一个子字符串,返回参数为char* ,参数很简单,应该是子字符串的位置,一个是长度,如果不指定长度,默认到\0

string s("hello world");
cout<<s.substr(0,5);  //输出:hello
17)getline()

getline (string) - C++ Referenceicon-default.png?t=N7T8https://legacy.cplusplus.com/reference/string/string/getline/这个函数的作用就是cin的一个拓展,没有参数和没有返回值,众所周知,cin输入字符串碰到空白会暂停,但是getline要碰到\0才会停止

string s;
cin>>s;     //输入:jascsahjas jscasjbsnc,但最后只有jascsahjas成功输出了
s.getline(); //输入:jascsahjas jscasjbsnc    s里面是:jascsahjas jscasjbsnc

二,模拟实现

备注:博主想偷懒了,答应大家的模拟实现不能再给大家做详细的解释了,但我会贴出源码供大家参考,里面只有一点点的注释,如果大家有不懂的,可以评论区@我,我会给大家一一解答,大家记得先看下面的私有成员,不要直接从头看到尾哦

namespace bit     //使用命名空间,防止于库的string类型冲突{class string{public:typedef char* iterator;      //string类的迭代器可以使用这个代替public:string(const char* str = "") //当无参数时,默认只有一个\0{_size = strlen(str);_capacity = _size;_str = new char[_capacity+1];strcpy(_str, str);}string(const string& s): _str(nullptr), _size(0), _capacity(0) //初始化列表{string tmp(s._str);this->swap(tmp);}string& operator=(const string &s){if(this != &s){string temp(s);this->swap(temp);}return *this;}~string(){if (_str){delete[] _str;_str = nullptr;}}//// iteratoriterator begin(){return _str;      //通过地址可以判断迭代器的位置}iterator end(){return _str + _size;}/// modifyvoid push_back(char c){if (_size == _capacity)reserve(_capacity*2);_str[_size++] = c;_str[_size] = '\0';}string& operator+=(char c){push_back(c);            //嘻嘻,复用已有的功能,偷懒return *this;}void append(const char* str);string& operator+=(const char* str);void clear()    //清除数据,但空间不变,尽量减少开空间的频率{_size = 0;_str[_size] = '\0';}void swap(string& s){std::swap(_str, s._str);  //官方库的swap函数,又是一个偷懒小技巧std::swap(_size, s._size);std::swap(_capacity, s._capacity);}const char* C_Str()const     //哈哈,是不是很简单{return _str;}/// capacitysize_t size()const   //有手就行{return _size;}size_t capacity()const{return _capacity;}bool empty()const{return _size == 0;}void resize(size_t newSize, char c = '\0'){if (newSize > _size){// 如果newSize大于底层空间大小,则需要重新开辟空间if (newSize > _capacity){reserve(newSize);}memset(_str + _size, c, newSize - _size); //调用C官方库,初始化,不懂,参考我以前的博客}_size = newSize;_str[newSize] = '\0';}void reserve(size_t newCapacity){// 如果新容量大于旧容量,则开辟空间if (newCapacity > _capacity){char* str = new char[newCapacity + 1];strcpy(str, _str);// 释放原来旧空间,然后使用新空间delete[] _str;_str = str;_capacity = newCapacity;}}/// accesschar& operator[](size_t index)//很容易实现吧{assert(index < _size);return _str[index];}const char& operator[](size_t index)const  //要记住const类型要单独处理{assert(index < _size);return _str[index];}///relational operatorsbool operator<(const string& s)const{int res = strcmp(_str, s._str); //C官方库,以前博客有这种函数的模拟实现和讲解if(res < 0)return true;return false;}bool operator<=(const string& s)const{return !(*this > s);}bool operator>(const string& s)const{int res = strcmp(_str, s._str);if(res > 0)return true;return false;}bool operator>=(const string& s)const{return !(*this < s);}bool operator==(const string& s)const{int res = strcmp(_str, s._str);if(res == 0)return true;return false;}bool operator!=(const string& s)const{return !(*this == s);}// 返回c在string中第一次出现的位置size_t find (char c, size_t pos = 0) const   //只读不改,最好const,同时支持非const类型{for (size_t i = pos; i < _size; ++i){if (_str[i] == c)return i;//找到,返回下标}return -1;//未找到}// 返回子串s在string中第一次出现的位置size_t find (const char* s, size_t pos = 0) const{assert(s);          //断言,如果条件为假就报错,结束程序并报错assert(pos < _size);const char* src = _str + pos;while (*src){const char* match = s;//如果不匹配,返回子串起始处重新查找const char *cur = src;while (*match && *match==*cur)//结束条件{++match;++cur;}if (*match == '\0')//找到子串{return src - _str;//返回下标}else{++src;}}return -1;//未找到}// 在pos位置上插入字符c/字符串str,并返回该字符的位置string& insert(size_t pos, char c){assert(pos <= _size);if (_size > _capacity){//扩容char *newstr = new char[_capacity * 2 + 1];//开空间strcpy(newstr, _str);delete[] _str;_str = newstr;_capacity *= 2;//Expand(_capacity * 2);}//移数据for (int i = _size; i >= (int)pos; --i){_str[i + 1] = _str[i];}_str[pos] = c;_size++;return *this;}string& insert(size_t pos, const char* str){size_t len = strlen(str);if (_size + len > _capacity)//扩容{//扩容char *newstr = new char[_capacity * 2 + 1];//开空间strcpy(newstr, _str);delete[] _str;_str = newstr;_capacity *= 2;//Expand(_size + len);}//后移数据for (int i = _size; i >= (int)pos; --i){_str[len + i] = _str[i];}//拷贝字符串while (*str != '\0'){_str[pos++] = *str++;}_size += len;return *this;}// 删除pos位置上的元素,并返回该元素的下一个位置string& erase(size_t pos, size_t len){assert(pos < _size);if (pos + len >= _size)//pos位置之后全为0{_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}return *this;}private:friend ostream& operator<<(ostream& _cout, const bit::string& s);friend istream& operator>>(istream& _cin, bit::string& s);private:char* _str;size_t _capacity;size_t _size;};};//输入流重载istream& bit::operator>>(istream& _cin, bit::string& s){//预分配100个空间char *str = (char *)malloc(sizeof(char)*100);char *buf = str;        //buf可以防止频繁开空间int i = 1;//预处理:跳过流里面的所有空格和回车while ((*buf = getchar()) == ' ' || (*buf == '\n'));for ( ; ; ++i){if (*buf == '\n') //回车跳出{*buf = '\0';break;}else if (*buf == ' ') //空格跳出{*buf = '\0';break;}else if (i % 100 == 0) //空间不足{i += 100; //追加100个空间str = (char *)realloc(str,i);}else  //每次getchar()一个值{buf = (str+i);//为了避免realloc返回首地址改变,不使用++buf,而是用str加上偏移.//每次读取一个字符*buf = getchar();}}//输入完成,更新ss._str = str;s._capacity = s._size = i;return _cin;}//输出流重载ostream& bit::operator<<(ostream& _cout, const bit::string& s){for (size_t i = 0; i < s.size(); ++i){_cout << s[i];}return _cout;}

这篇关于C++利剑string类(详解)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/446943

相关文章

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

OpenHarmony鸿蒙开发( Beta5.0)无感配网详解

1、简介 无感配网是指在设备联网过程中无需输入热点相关账号信息,即可快速实现设备配网,是一种兼顾高效性、可靠性和安全性的配网方式。 2、配网原理 2.1 通信原理 手机和智能设备之间的信息传递,利用特有的NAN协议实现。利用手机和智能设备之间的WiFi 感知订阅、发布能力,实现了数字管家应用和设备之间的发现。在完成设备间的认证和响应后,即可发送相关配网数据。同时还支持与常规Sof

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

【C++高阶】C++类型转换全攻略:深入理解并高效应用

📝个人主页🌹:Eternity._ ⏩收录专栏⏪:C++ “ 登神长阶 ” 🤡往期回顾🤡:C++ 智能指针 🌹🌹期待您的关注 🌹🌹 ❀C++的类型转换 📒1. C语言中的类型转换📚2. C++强制类型转换⛰️static_cast🌞reinterpret_cast⭐const_cast🍁dynamic_cast 📜3. C++强制类型转换的原因📝

K8S(Kubernetes)开源的容器编排平台安装步骤详解

K8S(Kubernetes)是一个开源的容器编排平台,用于自动化部署、扩展和管理容器化应用程序。以下是K8S容器编排平台的安装步骤、使用方式及特点的概述: 安装步骤: 安装Docker:K8S需要基于Docker来运行容器化应用程序。首先要在所有节点上安装Docker引擎。 安装Kubernetes Master:在集群中选择一台主机作为Master节点,安装K8S的控制平面组件,如AP