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

相关文章

Java调用C++动态库超详细步骤讲解(附源码)

《Java调用C++动态库超详细步骤讲解(附源码)》C语言因其高效和接近硬件的特性,时常会被用在性能要求较高或者需要直接操作硬件的场合,:本文主要介绍Java调用C++动态库的相关资料,文中通过代... 目录一、直接调用C++库第一步:动态库生成(vs2017+qt5.12.10)第二步:Java调用C++

详解nginx 中location和 proxy_pass的匹配规则

《详解nginx中location和proxy_pass的匹配规则》location是Nginx中用来匹配客户端请求URI的指令,决定如何处理特定路径的请求,它定义了请求的路由规则,后续的配置(如... 目录location 的作用语法示例:location /www.chinasem.cntestproxy

C/C++错误信息处理的常见方法及函数

《C/C++错误信息处理的常见方法及函数》C/C++是两种广泛使用的编程语言,特别是在系统编程、嵌入式开发以及高性能计算领域,:本文主要介绍C/C++错误信息处理的常见方法及函数,文中通过代码介绍... 目录前言1. errno 和 perror()示例:2. strerror()示例:3. perror(

CSS will-change 属性示例详解

《CSSwill-change属性示例详解》will-change是一个CSS属性,用于告诉浏览器某个元素在未来可能会发生哪些变化,本文给大家介绍CSSwill-change属性详解,感... will-change 是一个 css 属性,用于告诉浏览器某个元素在未来可能会发生哪些变化。这可以帮助浏览器优化

Python基础文件操作方法超详细讲解(详解版)

《Python基础文件操作方法超详细讲解(详解版)》文件就是操作系统为用户或应用程序提供的一个读写硬盘的虚拟单位,文件的核心操作就是读和写,:本文主要介绍Python基础文件操作方法超详细讲解的相... 目录一、文件操作1. 文件打开与关闭1.1 打开文件1.2 关闭文件2. 访问模式及说明二、文件读写1.

C++变换迭代器使用方法小结

《C++变换迭代器使用方法小结》本文主要介绍了C++变换迭代器使用方法小结,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、源码2、代码解析代码解析:transform_iterator1. transform_iterat

详解C++中类的大小决定因数

《详解C++中类的大小决定因数》类的大小受多个因素影响,主要包括成员变量、对齐方式、继承关系、虚函数表等,下面就来介绍一下,具有一定的参考价值,感兴趣的可以了解一下... 目录1. 非静态数据成员示例:2. 数据对齐(Padding)示例:3. 虚函数(vtable 指针)示例:4. 继承普通继承虚继承5.

C++中std::distance使用方法示例

《C++中std::distance使用方法示例》std::distance是C++标准库中的一个函数,用于计算两个迭代器之间的距离,本文主要介绍了C++中std::distance使用方法示例,具... 目录语法使用方式解释示例输出:其他说明:总结std::distance&n编程bsp;是 C++ 标准

前端高级CSS用法示例详解

《前端高级CSS用法示例详解》在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交互和动态效果的关键技术之一,随着前端技术的不断发展,CSS的用法也日益丰富和高级,本文将深... 前端高级css用法在前端开发中,CSS(层叠样式表)不仅是用来控制网页的外观和布局,更是实现复杂交

Linux换行符的使用方法详解

《Linux换行符的使用方法详解》本文介绍了Linux中常用的换行符LF及其在文件中的表示,展示了如何使用sed命令替换换行符,并列举了与换行符处理相关的Linux命令,通过代码讲解的非常详细,需要的... 目录简介检测文件中的换行符使用 cat -A 查看换行符使用 od -c 检查字符换行符格式转换将