当前位置: 首页 > news >正文

string类介绍

STL定义

是c++标准库的重要组成部分

为什么要学习string类

c语言中字符串是以\0结尾的字符的集合,为了操作方便,c语言中提供了一些str库函数,但是这些库函数和字符串是分开的,不太符合oop的思想,而且底层空间需要用户自己维护。

string类的介绍

1 string是表示字符串的字符串类

2 该类的接口与一些常见的容器接口相同,添加了一些专门操作string的常规操作

3在使用string类的时候,必须加上#include<stdio.h>和using namespace std;

string的常见构造函数

string()

构造一个空的string对象,也就是一个空字符串

#include<iostream>
#include<string>using namespace std;
int main()
{string s1;cout<<"s1的长度:"<<s1.size()<<endl;return 0;
}

string (const char* s)

用c风格的字符串(以"\0"结尾的字符数组)来构造string对象

string s2("hello world");

string(size_t n,char c)

构造一个字符对象,其中包含n个字符c

string s4(5,'a');

string(const string& s)

用已有的string对象来构造新的string对象

string s1("hello world");
string s2(s1);

string对象的容量操作

size

返回字符串有效字符的长度,也就是字符串中所包含实际字符的个数,不包括"\0"

string s("hello");
cout<<"s的size"<<s.size()<<endl;

length()

和size()功能完全相同

capacity()

返回当前已分配的总空间大小,包括未分配的和已分配的,也就是字符串底层数组能容纳的字符个数。

empty()

判断当前字符串是否为空串,如果是空,返回true,如果不是,返回false。

clear()

清空字符当中的有效字符,使字符串变成空串,但不改变底层空间的大小。

reserve()

为字符串预留空间,如果参数小于字符串当前容量,则容量不会发生改变。

s.reserve(100);

resize()

将字符串的有效个数改成n个。如果n比原来字符串多,就将多出的部分用'c'填充(如果没有指定c则用'\0'填充),如果n比原来的字符串少,则截断。

string s="hello";
s.resize(8,'x');
s.resize(3);

string对象的访问以及遍历操作

operate[]

返回字符串pos位置的字符。对于const string类型对象调用,返回字符的常引用,不能修改;而对于非const string类对象调用,可以修改。

string s="hello";
s[0]='H';//可以修改const string s2="hi";//不能修改

begin+end

begin函数获取指向第一个字符串的迭代器,end函数获取指向最后一个字符下一个位置的迭代器,通过迭代器可以遍历字符串。

string s="hello";
for(string::iterator it=s.begin();it!=s.end();it++)
{cout<<*it;
}
cout<<end;
return 0;

rbegin+rend

rbegin函数获取指向最后一个字符串的反向迭代器,rend函数指向第一个字符前一个位置的反向迭代器,通过反向迭代器可以遍历字符串

for(string::reverse_iterator rit=s.rbegin();rit!=s.rend();rit++)
{cout<<*rit;
}

范围for

遍历容器中的数组

string s="hello";
for(char c:s)
{cout<<c;
}
cout<<endl;

string对象的修改

push_back

在字符串的末尾插入一个字符c

s.push_back('!');

append

在字符串的末尾追加一个字符串

s.append("world");

operator+=

在字符串的末尾追加字符串str

string s="hello";
s+=“world”;

c_str

返回c格式的字符串(即const char*类型的字符串),可用于与c语言的函数进行交互

string s="hello";
const char* str=s.c_str();

find+npos

从字符串的pos位置开始往后查找字符c,返回该字符在字符串中的位置,如果未找到,返回string::npos。

string s="helo world":
size_T pos=s.find('o');
if(pos!=string::npos)
{cout<<"n的位置是"<<pos<<endl;
}
else
{cout<<"未找到";
}

rfind

从字符串的pos位置,开始往前查找字符c,返回字符在字符串中的位置,如果找不到,返回string::npos。

string s="hello";
size_t pos=s.rfind('o');
if(pos!=string::npos)
{cout<<"从后往前找o的位置是"<<"pos"<<endl;
}
else
{cout<<"未找到\n"<<endl;
}

substr

从pos位置开始,截取n个字符

string s="hello";
string sub=s.substr(6,5);

注意

 在string尾部追加字符的时候,用s.push_back(),s.append(1,c),s+='c'的效果都差不多。一般情况下,string类用+=比较多,+=不仅可以连接字符,还可以连接字符串

string非成员函数

operator+

用于连接两个字符串,返回新的字符串。

注意尽量少使用,因为他是传值返回,会进行深拷贝,效率比较低。如果需要频繁进行字符串连接操作,建议使用operator+=。

string s1="hello";
string s2="world";
string s3=s1+s2;

operator<<

输入运算符重载,用于从输入流中读取字符串到string中。默认遇到空格、制表符、换行符就停止。

string s;
cout<<"请输入字符串";
cin>>s;
cout<<"你输入的字符串"<<s<<endl;

请输入字符串: hello world

你输入的字符串: hello

operator>>

输出运算符重载,用于将string对象中的字符串输出到输出流当中。

string s="hello";
cout<<"输出字符串:"<<s<<endl;

getline

获取一行字符串,包括空格,直到换行符为止

string s;
cout<<"请输入一行字符串:";
getline(cin,s);
cout<<"你输入的一行字符:"<<s<<endl;
return 0;

relational operators

用于字符串之间的比较

包括==,!=,<,>。比较是按照字符的ascii码依次进行的。

vs下string的结构

在32位平台下,vs的string总共占28个字节,其内部采用了一种较为复杂的设计结构,通过联合体(union)来管理字符串的存储空间。

联合体_Bxty的作用

联合体_Bxty用于定义string的存储空间:

1当字符串长度小于16时,使用内部固定的字符数组_Buf来存放字符串。这样的设计很高效,因为大部分的字符串长度都比较小,不需要额外从堆上分配内存,这样减少了内存分配的开销,提高了效率

2 当字符串长度大于16时,从堆上开辟空间来存储字符串,此时会使用指针_Ptr指向堆伤分配的内存

各部分所占字节

联合体部分,_Buf、_Ptr、_Alias共享同一块内存空间,_Buf 是长度为 _BUF_SIZE(这里 _BUF_SIZE 为 16)的字符数组,在 32 位平台下,字符占 1 个字节,所以这部分占 16 个字节。

size_t :在32位平台下,size_t是4个字节

一个字段size_t保留从堆上开辟开辟空间的总容量size_t,是4个字节

用于其他操作的指针:在32位平台下,占4个字节

所以总字节数是16+4+4+4=28字节

g++下string的结构

g++下的string结构采用写时拷贝优化,目的是减少不必要的内存复制

其核心是:1 读共享:多个string对象可以共享同一个堆内存

2写分离:当只有某个对象需要修改字符,才会复制一份内存

string对象总共占4个字节,内部只包含了一个指针,该指针用来指向一块堆空间,内部包含了如下字段,

1空间总大小 2字符串有效长度 3引用计数

string对象的模拟实现

c++中,当类未显示定义拷贝构造函数和赋值运算符重载的时候,编译器会自动生成默认版本,默认的拷贝构造和赋值操作是浅拷贝

错误的实现(浅拷贝)

#include<cstring>
#include<cassert>
#include<iostream>
//存在浅拷贝的String类
class String
{public:String(const char* str=" "){if(nullptr==str){assert(false);return;}_str=new char[strlen(str)+1];strcpy(_str,str);}
//析构函数:释放动态分配的内存
~String(){if(_str){ delete[] _str;_str=nullptr;}private:char* _str;
}
void test//触发浅拷贝问题
{String s1("hello");String s1(s2);//程序运行到此处s1和s2的_str指向同一块资源
//当函数结束时,s2先析构,s1再析构
//导致double free,程序崩溃}

错误原因分析:

1默认拷贝构造函数的浅拷贝:编译器生成的默认拷贝构造函数只会复制_str指针本身,导致s1._str和s2._str指向同一块堆内存

2重复释放内存:函数结束时,s2和s1依次析构,两次调用 delete[ ] _str释放同一块内存

string的正确实现

#include<cstring>
#include<cassert>
#include<iostream>
using namespace std;
class String
{public:String(const char* str=""){if(nullptr==str){assert(fasle);return;}_str=new char[strlen(str)+1];strcpy(_str,str);}
//拷贝构造函数
String(const String& s)
{_str=new str[strlen(s._str)+1];strcpy(_str,s._str);
}
//赋值运算符重载(深拷贝)
String& operator=(const String& s)
{if(this!=&s)//避免自赋值,比如s1==s2{//先分配新内容,复制内容,防止原内存释放后拷贝失败char* newStr=new char[strlen(s._str)+1];strcpy(newStr,s._str);delete[] _str;_str=newStr;//指向新内存}return *this;
}
~String()//析构函数
{if(_str){delete[] _str;_str=nullptr;}}
const char* c_str() const{return const_str;
}
private:
char* _str;
};
void test()
{String s1="hello";String s2(s1);cout<<s1.c_str()<<endl;//输出hellocout<<s2.c_str()<<endl;//输出helloString s3("world");s2=s3;cout<<s2.c_str()<<endl;//输出worldcout<<s3.c_str()<<endl;//输出world(不受s2影响)
}

修正说明:

1 显示定义拷贝构造函数:为新对象分配独立内存,并复制原对象的字符串内容,确保s1和s2的_str指向不同内存

2 显示定义运算符重载,先分配新内存复制内容,再释放旧内存,避免自赋值问题和内存泄漏

http://www.dtcms.com/a/499561.html

相关文章:

  • 深度学习物理神经网络(PINN)!
  • 青岛做公司网站的公司ppt模板下载简约
  • 网站为什么做静态广州专业网站建设后台管理便捷
  • Unity游戏基础-7(简单的水面Shader Graph,案例1)
  • 在 Mac/linux 的 VSCode 中使用Remote-SSH远程连接 Windows
  • 国内AI编程工具
  • 宝塔面板安装ecshop
  • 大型网站一般用什么语言做的建设行业信息管理系统网站
  • 西安建站软件在wordpress官网建站
  • OceanBase数据库集群升级手册
  • 深入理解与手写发布订阅模式
  • 关于企业网站建设的必要性关键洞察力
  • ubuntu系统安装记录
  • Flutter---音效模式选择器
  • 信号量 semaphore 机制可实现基于条件变量 condition variable 的管程 monitor 机制
  • 市工商局网站建设情况网页截图快捷键ctrl加什么
  • C++数据类型
  • FFmpeg 核心 API 系列:音频重采样 SwrContext 完全指南(新API版本)
  • 网站建设数据收集方法南昌网站推广¥做下拉去118cr
  • visio画网站开发类图深圳东道建设集团网站
  • 董付国老师Python小屋编程题答案161-170
  • 国外营销企业网站什么叫高端网站定制
  • Flutter---生命周期
  • 百度网址大全网站互联网家装
  • 专业的东莞网站排名WordPress多站点开启多语言
  • 微信端网站开发流程做网站什么配置够用
  • c# 泛型的详细介绍
  • OceanBase的SQL和执行计划监控视图
  • 网站原创内容优化wordpress 网站内跳转
  • 龙口市规划建设局网站南京app开发公司排名