C++string类
- 1. 初步认识string类的由来
- 2. string常用接口
- 2.1 string的构造
- 2.2 String::operator =
- 2.3 string::operator +=
- 2.4 string::operator[]\string::size
- 2.5 string::iterator 迭代器
- 2.6 string::reverse_iterator 反向迭代器
- 2.9 string::clear(清楚字符)
- 2.8 string::reserve空间扩容
- 2.9 string::resize空间扩容加初始化
- 3.0 string::at 和string::operator[]的区别
- 3.1 string::insert(插入)
- 3.2 string::erase(擦除字符)
- 3.3 string::replace(替换)
- 3.4 string::find(查找元素)
- 3.5 string::find_first_of(查找所有包含的元素)
- 3.6 string::getline 和 string::rfind(字符串输入和查找最后一次出现的字符)
- 3.7std::to_string(将数字转换为字符串)
- 3.8 std::stoi(将字符串转换为整型)
1. 初步认识string类的由来
C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问,所以C++中提出了string类
- string是表示字符串的字符串类
- 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
- string在底层实际是:basic_string模板类的别名,typedefbasic_string<char, char_traits, allocator> string;
- 不能操作多字节或者变长字符的序列。在使用string类时,必须包含#include头文件以及using namespace std;
2. string常用接口
2.1 string的构造
string的构造一共有七种,但是我们常用的只有四种
string类对象常见的构造
函数名称 | 功能说明 |
---|---|
string() | 构造空的string类对象 ,即空字符串 |
string(const char* s) | 用C-string来构造string类对象 |
string(size_t n,char c) | string类对象中包含n个字符c |
string(const string&ss) | 拷贝构造函数 |
int main()
{
string s1;
string s2("厉害了张三");
string s3(10, '*');
string s4(s2);
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4<< endl;
return 0;
}
string(const string & str, size_t pos, size_t len = npos)
int main()
{
string s2("厉害了张三");
cout << s2 << endl;
//string(const string & str, size_t pos, size_t len = npos);
//在C中一个汉字占两个字符大小
string s5(s2, 6, 4);
cout << s5 << endl;
return 0;
}
意思为:复制str中从字符位置pos开始并跨越len个字符的部分(如果str太短或len为string::npos,则复制到str的末尾)。
但是如果跨越的长度过长或者过短怎么办
注意这时不要忽略string形参的size_t len = npos
Npos是一个静态成员常量值,它包含一个元素或类型size-t的最大可能值。
当在string的成员函数中作为len(或sublen)参数的值时,该值表示“直到字符串结束”。
作为返回值,它通常用于表示没有匹配。
该常量定义为值为1,由于size_t是无符号整型,因此它是该类型可能表示的最大值。
int main()
{
string s2("厉害了张三");
cout << s2 << endl;
//string(const string & str, size_t pos, size_t len = npos);
//在C中一个汉字占两个字符大小
string s5(s2, 6, 4);
cout << s5 << endl;
string s6(s2, 6);
cout << s6 << endl;
string s7(s2, 6, 99);
cout << s6 << endl;
return 0;
}
2.2 String::operator =
int main()
{
string s1;
string s2("厉害了张三");
cout << s2 << endl;
//拷贝构造
//string& operator= (const string& str);
s1 = s2;
cout << s1 << endl;
cout << s2 << endl;
//字符串传值
//string& operator= (const char* s);
s1 = "zhangdashi";
cout << s1 << endl;
//也可以传字符
//tring& operator= (char c);
s1 = 's';
cout << s1 << endl;
return 0;
}
2.3 string::operator +=
int main()
{
string s1;
string s2("厉害了张三");
cout << s2 << endl;
s1 += s2;
cout << s1 << endl;
s1 += "奥里给";
cout << s1 << endl;
s1 += '6';
cout << s1 << endl;
return 0;
}
2.4 string::operator[]\string::size
int main()
{
string s1("hello tong");
char s2[] = "hello tong";
cout << s1.size() << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";// s1.operator[](1);
s1[i]++;
}
cout << endl;
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i] << " ";// s1.operator[](1);
}
cout << endl;
cout << sizeof(s2) << endl;
for (size_t i = 0; i < sizeof(s2)-1; i++)
{
cout << s2[i] << " ";// -> *(s3+1)
s2[i]++;
}
cout << endl;
for (size_t i = 0; i < sizeof(s2)-1; i++)
{
cout << s2[i] << " ";// -> *(s3+1)
}
return 0;
}
2.5 string::iterator 迭代器
string::iterator 可改变变量
string::const_iterator 不可改变变量
int main()
{
string s1("hello tong");
string::iterator it = s1.begin();
while (it!= s1.end())
{
cout << *it ;
++it;
}
cout << endl;
return 0;
}
int main()
{
string s1("hello tong");
string::iterator it = s1.begin();
while (it != s1.end())
{
(*it)++;
cout << *it;
++it;
}
cout << endl;
return 0;
}
2.5.1 范围for(迭代器)
//范围for
//底层替换为迭代器
int main()
{
string s1("hello tong");
for (char ch : s1)
{
cout << ch;
}
cout << endl;
//因为ch是s1依次字符的拷贝,所以ch++并不会影响s1
for (char ch : s1)
{
ch++;
}
cout << endl;
for (char ch : s1)
{
cout << ch;
}
cout << endl;
//要想改变ch就需要把ch设置成引用
for (char& ch : s1)
{
ch++;
}
cout << endl;
for (char ch : s1)
{
cout << ch;
}
cout << endl;
return 0;
}
我们可以从汇编代码看出范围for底层调用的也是迭代器
iterator 是像指针一样的类型
有可能是指针,有可能不是指针,但是用法是差不多的
iterator提供一种统一的方式访问和修改容器的数据,算法可以通过迭代器,去处理容器中的数据
//任何容器都支持迭代器,并且用法是类似的
#include <algorithm>
int main()
{
//迭代器跟算法进行配合
string s1("4455336622");
reverse(s1.begin(), s1.end());
cout << s1 << endl;
sort(s1.begin(), s1.end());
cout << s1 << endl;
}
2.6 string::reverse_iterator 反向迭代器
string::reverse_iterator
可改变变量
string::const_reverse_iterator
不可改变变量
auto可以在声明变量的时候根据变量初始值的类型自动为此变量选择匹配的类型。
反向迭代器,可修改变量(读写)
int main()
{
string s1("hello world");
//string::reverse_iterator rit = s1.rbegin();
//auto可以在声明变量的时候根据变量初始值的类型
//自动为此变量选择匹配的类型。
auto rit = s1.rbegin();
cout << s1 << endl;
while (rit != s1.rend())
{
(*rit) += 3;
cout << *rit << " ";
rit++;
}
cout << endl;
cout << s1 << endl;
}
反向迭代器,不可修改变量(读)
//反向迭代器,不可修改
void Func(const string& s)
{
//可以对比出auto的高效性
//string::const_iterator it = s.begin();
auto it = s.begin();
while (it != s.end())
{
(*it) += 3;//这里是不可以修改的,因为是const类型
cout << *it << " ";
++it;
}
cout << endl;
//可以对比出auto的高效性
//string::const_reverse_iterator rit = s.rbegin();
auto rit = s.rbegin();
while (rit != s.rend())
{
//(*rit) += 3;//这里是不可以修改的,因为是const类型
cout << *rit << " ";
++rit;
}
cout << endl;
}
2.9 string::clear(清楚字符)
擦除字符串的内容,使其成为空字符串(长度为0个字符)。
2.8 string::reserve空间扩容
void reserve (size_t n = 0);
reserve有扩容的作用,也有容器缩小的作用(缩小的前提需要进行clear,如果不进行clear缩小空间也是无用的)
- 如果n大于当前字符串容量,则该函数使容器将其容量增加到n个字符(或更大)。
int main()
{
string s;
s.reserve(100);
size_t sz = s.capacity();
cout << s.size() << endl;
s.push_back('c');
cout << s.size() << endl;
cout << sz << endl;
}
我们要求扩容的大小为100,而这时显示的我们扩容了111,这是因为编译器的优化,每个编译器的优化程度都不一样,优化后绝不会比自己申请的小
- 在所有其他情况下,请求收缩字符串容量被视为非绑定请求:容器实现是否则可以自由优化,并使字符串的容量大于n。
int main()
{
string s;
s.reserve(100);
size_t sz = s.capacity();
cout << s.size() << endl;
s.push_back('c');
cout << s.size() << endl;
cout << sz << endl;
s.clear();
cout << sz << endl;
s.reserve(15);
sz = s.capacity();
cout << sz << endl;
}
由编译器定义,有的编译器即使你clear清除了也不会缩小内存,小心使用,但是肯定的是如果你没有clear是肯定不会缩小内存的
2.9 string::resize空间扩容加初始化
void resize (size_t n);
void resize (size_t n, char c);
翻译为:如果n小于当前字符串长度,则将当前值缩短到前n个字符,删除第n个字符以外的字符。
如果n大于当前字符串长度,则通过在末尾插入任意\0
字符来扩展当前内容,以达到n的大小。如果指定了c,则新元素被初始化为c,否则,它们是值初始化的字符为\0
。
reserve
和resize
的区别在于前者是开空间,只会改变capacity
,而resize
是开空间加初始化,它不仅改变capacity
还会将其涉及到的空间范围没有值的区域赋'\0'
void resize (size_t n);
int main()
{
string s("laotiegeili");
//开空间
s.reserve(100);
cout << s.size() << endl;
cout << s.capacity() << endl;
//开空间加初始化
s.resize(100);
cout << s.size() << endl;
cout << s.capacity() << endl;
return 0;
}
void resize (size_t n, char c);
int main()
{
string s("laotiegeili");
cout << s << endl;
cout << s.size() << endl;
cout << s.capacity() << endl;
s.resize(20,'x');
cout << s << endl;
cout << s.size() << endl;
cout << s.capacity() << endl;
return 0;
}
3.0 string::at 和string::operator[]的区别
==string::at ==
char& at (size_t pos);
const char& at (size_t pos) const;
意思是:字符串中的第一个字符用值0表示(而不是1)。如果它不是字符的位置,则抛出out_of_range异常。
int main()
{
try {
string s("hello world");
s.at(0) = 'x';
s[1] = 'y';
s[15];//暴力处理
//s.at(15);//温和的错误处理
}
catch (const exception& e)
{
cout << e.what() << endl;
}
return 0;
}
string::operator[]
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
意思为:字符串中的第一个字符用值0表示(而不是1)。如果它不是字符的位置,则会进行断言。
3.1 string::insert(插入)
int main()
{
string s = "hello world";
string s2 = "** ** ";
//1 string& insert (size_t pos, const string& str);
s.insert(7, "ur ");
cout << s << endl;
//2 string& insert(size_t pos, const string & str, size_t subpos, size_t sublen);
s.insert(0, "nvli jiayou", 0, 5);
cout << s << endl;
//3 string& insert (size_t pos, const char* s);
s.insert(0, s2);
cout << s << endl;
//4 string& insert (size_t pos, const char* s, size_t n);
s.insert(0, s2, 3);
cout << s << endl;
//5 string& insert (size_t pos, size_t n, char c);
s.insert(0, 5, 'x');
cout << s << endl;
//5 void insert(iterator p, size_t n, char c);
s.insert(s.begin(), 5, 'y');
cout << s << endl;
//6 iterator insert (iterator p, char c);
s.insert(s.end(),'w');
cout << s << endl;
return 0;
}
3.2 string::erase(擦除字符)
int main()
{
string s = "hello world";
//1 string& erase (size_t pos = 0, size_t len = npos);
s.erase(5, 1);
cout << s << endl;
//2 iterator erase (iterator p);
s.erase(s.begin());
cout << s << endl;
//3 iterator erase (iterator first, iterator last);
s.erase(s.begin(),s.begin()+4);
cout << s << endl;
return 0;
}
3.3 string::replace(替换)
int main()
{
string s = "hello world";
//1 string& replace (size_t pos, size_t len, const string& str);
//从下标为6的位置后的五个字符替换为laotie
s.replace(6, 5, "laotie");
cout << s << endl;
string s2 = "hello world hello world";
string s3;
for (auto ch : s2)
{
if (ch != ' ')
{
s3 += ch;
}
else
{
s3 += "%20";
}
}
s2 = s3;
cout << s2 << endl;
//c_str()转换为c的类型输出
cout << s2.c_str() << endl;
return 0;
}
3.4 string::find(查找元素)
3.4.1 string::substr(字符提取)
int main()
{
string url = "https://legacy.cplusplus.com/reference/string/string/";
//协议 域名 资源名
size_t pos1 = url.find("://");
string protocol;
//if (pos1 != string::npos)
//{
protocol = url.substr(0, pos1);
//}
cout << protocol << endl;
string domain;
string uri;
size_t pos2 = url.find('/',pos1+3);
//if (pos2 != string::npos)
//{
domain = url.substr(pos1 + 3, pos2 - (pos1 + 3));
uri = url.substr(pos2 + 1);
//}
cout << domain << endl;
cout << uri << endl;
}
3.5 string::find_first_of(查找所有包含的元素)
int main()
{
string str("Please, replace the vowels in this sentence by asterisks.");
size_t found = str.find_first_of("abc");
while (found != string :: npos)
{
str[found] = '*';
found = str.find_first_of("abc",found + 1);
}
std::cout << str << endl;
return 0;
}
它和find的区别就是find查找的是所有对应的字符串,或者字符,而string::find_first_of查找的是对应字符串中的一个字符,或者整体,伸缩性比较强,而find的目的性就比较单一。
3.6 string::getline 和 string::rfind(字符串输入和查找最后一次出现的字符)
int main() {
string str;
getline(cin,str);
int pos = str.rfind(' ')+1;
int sum = str.size() - pos;
cout << sum << endl;
return 0;
}
输入:hello nowcoder
输出:8
最后一个单词为nowcoder,长度为8
3.7std::to_string(将数字转换为字符串)
void ToString_test()
{
int ival;
double dval;
cin >> ival >> dval;
cout << "整型数据为:" << ival << " 双精度浮点型数据为:" << dval << endl;
string istr = to_string(ival);
string dstr = to_string(dval);
cout << istr << endl;
cout << dstr << endl;
}
int main()
{
ToString_test();
return 0;
}
3.8 std::stoi(将字符串转换为整型)
stoi(字符串,起始位置,n进制),将 n 进制的字符串转化为十进制
void Stoi_test()
{
int ival;
double dval;
string istr;
string dstr;
istr = "-101";
dstr = "999.99";
ival = stoi(istr, nullptr, 2);
dval = stod(dstr);
cout << ival << endl;
cout << dval << endl;
}
int main()
{
Stoi_test();
return 0;
}
已此类推,stof、stod、stol等