C++中string类的使用
2023-12-13 19:29:24
目录
6.1stoi 将string里第一次遇到的数字字符转换成int
一.string类
1.1为什么学习string类?
C
语言中,字符串是以
'\0'
结尾的一些字符的集合,为了操作方便,
C
标准库中提供了一些
str
系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP
的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
在
OJ
中,有关字符串的题目基本以
string
类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本 都使用string
类,很少有人去使用
C
库中的字符串操作函数。
1.2.标准库中的string类
1. 字符串是表示字符序列的类2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。3. string 类是使用 char( 即作为它的字符类型,使用它的默认 char_traits 和分配器类型 ( 关于模板的更多信 息,请参阅basic_string) 。4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits 和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。5. 注意,这个类独立于所使用的编码来处理字节 : 如果用来处理多字节或变长字符 ( 如 UTF-8) 的序列,这个 类的所有成员( 如长度或大小 ) 以及它的迭代器,将仍然按照字节 ( 而不是实际编码的字符 ) 来操作。
总结:
1. string 是表示字符串的字符串类2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作 string 的常规操作。3. string 在底层实际是: basic_string 模板类的别名, typedef basic_string<char, char_traits, allocator> string;4. 不能操作多字节或者变长字符的序列。 在 使用string类时,必须包含#include头文件以及using namespace std;
二.string对象的元素访问
?2.1.1使用operator[]与at实现访问
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello");//构造
for (size_t i = 0; i < s.size(); i++)//读
{
cout << s[i] << " ";
}
cout << endl;
for (size_t i = 0; i < s.size(); i++)
{
cout << s.at(i) << " ";
}
cout << endl;
for (size_t i = 0; i < s.size(); i++)//写,at同理
{
cout << s[i]+=1 << " ";
}
}
operator[]与at的区别:
operator[]在元素越界访问时,采用断言,at采用抛出异常
2.1.2正向迭代器访问
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
string::iterator it = s.begin();
while (it != s.end())//读
{
cout << *it << " ";
it++;
}
cout << endl;
it = s.begin();
while (it != s.end())//写
{
*it += 1;
cout << *it << " ";
}
cout << endl;
return 0;
}
2.1.3反向迭代器访问
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
string::reverse_iterator it = s.rbegin();
while (it != s.rend())//读
{
cout << *it << " ";
it++;
}
cout << endl;
it = s.rbegin();
while (it != s.rend())//写
{
*it += 1;
cout << *it << " ";
}
cout << endl;
return 0;
}
2.1.4const正向迭代器(不能修改)
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
string::const_iterator it = s.begin();
while (it != s.end())//读
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
2.1.5const反向迭代器(不能修改)
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
string::const_reverse_iterator it = s.rbegin();
while (it != s.rend())//读
{
cout << *it << " ";
it++;
}
cout << endl;
return 0;
}
2.1.6范围for
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
for(auto ch:s)//无法修改
{
cout<<ch<<" ";
}
for(auto& ch:s)//可以修改
{
ch+=1;
cout<<ch<<" ";
}
return 0;
}
三.string类对象的常见构造
string()? ?重点 | 无参构造函数 |
string(const char* s)? 重点 | 用字符串构造对象 |
string(size_t n,char c)? 重点 | 用n个字符构造对象 |
string(const string& s) 重点 | 拷贝构造 |
string(const string& str,size_t pos,size_t len=npos) | 用str从下标(包括)之后len长度的内容,构造对象 |
string(const char* s,size_t n) | 用字符串前n个构造对象 |
template <class InputIterator first,InputIterator last> string(InputIterator first,InputIterator last) | 迭代器区间构造对象 |
注:第四个构造方法,中的npos,是string类中的一个被static修是的,类型为size_t(无符号整形),值为-1
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s1;//无参构造
string s2("abcdefg");//用字符串构造对象
string s3(5, 's');//string类对象中包含n个字符
string s4(s2);//拷贝构造
string s5(s2, 0, 3);//用str从下标(包括)之后len长度的内容,构造对象
string s6("abcdefg", 3);//用字符串前n个构造对象
string s7(s6.begin(), s6.end());//迭代器区间构造对象
cout << "s1=" << s1 << endl;
cout << "s2=" << s2 << endl;
cout << "s3=" << s3 << endl;
cout << "s4=" << s4 << endl;
cout << "s5=" << s5 << endl;
cout << "s6=" << s6 << endl;
cout << "s7=" << s7 << endl;
return 0;
}
三.?string类对象的容量操作
size (重点) | 返回字串有效字符长度 |
length | 返回字符串有效长度 |
capacity?? | 返回空间总大小 |
empty (重点) | 检测字符串是否为空串,是返回true,否则返回false |
clear (重点) | 清空有效字符 |
reserve (重点) | 为字符串预留空间 |
resize (重点) | 将有效字符个数改成n个,多出的空间用字符c填充 |
1.reverse(修改总容量)
#include<iostream>
#include<string>
using namespace std;
int main()
{
string s("hello C++");
cout << s.size() << " " << s.capacity() << endl;
s.reserve(100);
cout << s.size() << " " << s.capacity() << endl;
s.reserve(10);
cout << s.size() << " " << s.capacity() << endl;
return 0;
}
reserve用于预开空间,如果开辟的空间小于原空间,并不会改变容量
2.resize(调整size)
#include<iostream>
#include<string>
using namespace std;
int main()
{
//resize(n)
// resize(size_t n,char x)
//分三种情况
//1. n<size
//2. n>size && n<=capacity
//3. n>capacity
string s("hello world");
s.resize(10);//
cout << s.size() << " " << s.capacity() << " " << s<<endl;
s.resize(17);//将size改为17,多出来的用'\0'填充
cout << s.size() << " " << s.capacity() << " " << s<<endl;
s.resize(40, 'x');//将size改为40,多出来的位置用'x'填充
cout << s.size() << " " << s.capacity() << " " << s<<endl;
return 0;
}
resize用于调整size,当n大于容量是,会扩容,并用对于的字符填充。
当n>size && n< 容量时,用对应的字符填充多出来的
当n<size 时,会缩容放弃超过的空间。
注意:
1. size() 与 length() 方法底层实现原理完全相同,引入 size() 的原因是为了与其他容器的接口保持一致,一般情况下基本都是用 size() 。2. clear() 只是将 string 中有效字符清空,不改变底层空间大小。3. resize(size_t n) 与 resize(size_t n, char c) 都是将字符串中有效字符个数改变到 n 个,不同的是当字 符个数增多时:resize(n) 用 0 来填充多出的元素空间, resize(size_t n, char c) 用字符 c 来填充多出的 元素空间。注意:resize 在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。4. reserve(size_t res_arg=0) :为 string 预留空间,不改变有效元素个数,当 reserve 的参数小于 string的底层空间总大小时, reserver 不会改变容量大小。
四.?string类对象的修改操作
push_back
|
在字符串后尾插字符c
|
append |
在字符串后追加一个字符串
|
operator+=
(
重点)
|
在字符串后追加字符串
str
|
c_str
(
重点
)
|
返回
C
格式字符串
|
find
+
npos
(
重点
)
|
从字符串
pos
位置开始往后找字符
c
,返回该字符在字符串中的位置
|
rfind
|
从字符串
pos
位置开始往前找字符
c
,返回该字符在字符串中的位置
|
substr
|
在
str
中从
pos
位置开始,截取
n
个字符,然后将其返回
|
?find
//从pos位置开始找,str
size_t find (const string& str, size_t pos = 0) const noexcept;
//从pos位置开始找字符串第一次出现的下标,若不存在返回npos
size_t find (const char* s, size_t pos = 0) const;
//从pos位置找字符串s的前n个第一次出现的下标,不存在返回npos
size_t find (const char* s, size_t pos, size_type n) const;
size_t find (char c, size_t pos = 0) const noexcept;
通常finf与substr配合使用对找一个网址对应的协议,域名,地址
#include<iostream>
#include<string>
using namespace std;
int main()
{
//string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");
string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");
// 协议
// 域名
// 资源名
string sub1, sub2, sub3;
size_t i1 = s3.find(':');
if (i1 != string::npos)
sub1 = s3.substr(0, i1);//查找协议
else
cout << "没有找到i1" << endl;
size_t i2 = s3.find('/', i1+3);
if (i2 != string::npos)
sub2 = s3.substr(i1+3, i2-(i1+3));//查找域名
else
cout << "没有找到i2" << endl;
sub3 = s3.substr(i2 + 1);//查找地址
cout << sub1 << endl;
cout << sub2 << endl;
cout << sub3 << endl;
}
五.string类非成员函数
operator+ ?
|
尽量少用,因为传值返回,导致深拷贝效率低
|
operator>>
(重点)
|
输入运算符重载
|
operator<<
(重点)
|
输出运算符重载
|
getline
(重点)
|
获取一行字符串
|
流提取不能接受空格和换行,需要用接受带有空格的字符串时,可以用getline
getline
istream& getline(istream& in, string&str, char delim);//从流提取中提取字符串到str中,直到delim或'\n'
istream& getline(istream& in,string& str, char);//从流提取中取字符串到str
六.将string对象int互相转换
6.1stoi 将string里第一次遇到的数字字符转换成int
将一个string对象转化成int类型的数字
idx不传参为nullptr,表示不使用这个参数,反之,&idx指向string对象数字字符的后一个位置
6.2, to_string 将数字转化成string对象
七.vs和g++下string结构的说明
注意:下述结构是在
32
位平台下进行验证,
32
位平台下指针占
4
个字节
7.1vs下string的结构
string
总共占
28
个字节
,内部结构稍微复杂一点,先是
有一个联合体,联合体用来定义
string
中字
符串的存储空间
:
当字符串长度小于 16 时,使用内部固定的字符数组来存放当字符串长度大于等于 16 时,从堆上开辟空间
union _Bxty
{ // storage for small buffer or pointer to larger one
value_type _Buf[_BUF_SIZE];
pointer _Ptr;
char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;
这种设计也是有一定道理的,大多数情况下字符串的长度都小于
16
,那
string
对象创建好之后,内
部已经有了
16
个字符数组的固定空间,不需要通过堆创建,效率高。
其次:还有
一个
size_t
字段保存字符串长度,一个
size_t
字段保存从堆上开辟空间总的容量
最后:还
有一个指针
做一些其他事情。
故总共占
16+4+4+4=28
个字节。
7.2g++下string的结构 ???????
G++
下,
string
是通过写时拷贝实现的,
string
对象总共占
4
个字节,内部只包含了一个指针,该指
针将来指向一块堆空间,内部包含了如下字段:
空间总大小字符串有效长度引用计数
struct _Rep_base
{
size_type _M_length;
size_type _M_capacity;
_Atomic_word _M_refcount;
};
指向堆空间的指针,用来存储字符串。
文章来源:https://blog.csdn.net/qq_63440853/article/details/134893553
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。 如若内容造成侵权/违法违规/事实不符,请联系我的编程经验分享网邮箱:veading@qq.com进行投诉反馈,一经查实,立即删除!