目录
3.1 string类的构造函数:(constructor)
一、C++为什么要引入string类
C++引入string类是为了提供一种更高级、更方便和更安全的字符串处理方式,相比于C语言中使用字符数组和库函数来处理字符串,引入string类有以下几个主要原因:
- 方便性:用户在使用字符数组处理字符串时,需要手动处理内存分配、长度计算、字符串拷贝等操作,代码复杂且容易出错。而string类封装了这些底层细节,提供了一系列成员函数来方便地进行字符串的拼接、截取、比较等常用操作,大大简化了字符串处理的过程。
- 动态内存管理:字符数组在存储字符串时需要手动分配足够的内存空间,并且固定大小不便扩展。而string类使用动态内存分配,可以根据字符串的需要自动调整内存大小,在字符串长度变化时更加灵活。
- 安全性:字符数组没有内置的边界检查机制,容易导致缓冲区溢出和访问越界等安全问题。string类通过封装内部的动态内存管理,提供了范围检查、安全的访问操作,避免了很多常见的安全漏洞。
- 高级功能和操作:string类提供了丰富的成员函数和操作符重载,使得字符串的处理更加灵活和高效。例如,可以直接使用"+"进行字符串的拼接,使用"<"和">"进行字符串的比较,还可以使用成员函数find()、replace()等方便地进行字符串的查找和替换。
- 面向对象的设计:C语言中字符数组和库函数是分离开的,不太符合C++中面对对象的思想。string类是C++的标准库中的一个类,遵循了面向对象的设计原则,通过封装数据和操作,使得代码更加模块化、可维护性更高。同时,string类还支持运算符重载、迭代器等特性,使得字符串处理可以更加符合C++的编程习惯。
总之,引入string类使得C++中的字符串处理更加便捷、安全和高级,提供了更多的功能和操作,减少了开发者的工作量,同时也提高了代码的可读性和可维护性。因此,使用string类能够在C++中更好地处理字符串。
二、标准库中的string类
先来看一下标准库中对于string类的介绍。
总结:
- string是表示字符序列的对象。
- string类提供的接口与常规容器的接口基本相同,但是添加了一些专门用来操作string的操作。
- string在底层实际是:basic_string模板类的别名,使用char类型和默认的char_traits allocator作为模板参数。
- 不支持操作多字节或变长字符的序列。
三、string类的常用接口
3.1 string类的构造函数:(constructor)
- string();
构造空的string类对象,长度为0。- string (const string& str);
拷贝构造str- string (const string& str, size_t pos, size_t len = npos);
从pos位置拷贝str的n个字符(如果pos+len超过字符串末尾或者len为npos,就拷贝至字符串末尾结束)- string (const char* s);
用字符串s(C-string)拷贝一个string类。- string (const char* s, size_t n);
用字符串s(C-string)的前n个字符拷贝一个string类。- string (size_t n, char c);
一个string类填充n个字符c。
void Test1()
{
string s1;
string s2("abcd");
string s3(s2);
string s4(s3, 1, 5);
string s5("123456", 3);
string s6(10, 'a');
}
3.2 string类对象的容量操作
- size 返回字符串有效字符长度
size_t size() const;- length 返回字符串有效字符长度
size_t length() const;- capacity 返回空间总大小
size_t capacity() const;- empty 检测字符串释放为空串,是返回true,否则返回false
bool empty() const;- clear 清空有效字符
void clear();- reserve 为字符串预留空间
void reserve (size_t n = 0);- resize 将有效字符的个数该成n个,多出的空间用字符c填充
void resize (size_t n); void resize (size_t n, char c);
注:
- size()与length()的实现原理相同,只是size()与其他接口容器一致,更适合使用习惯。
- clear()只是将string中有效字符清空,不改变底层空间大小。
- reserve()为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是:当字符个数n大于有效字符长度时,resize(n)用 '\0' 来填充多出的元素空间,resize( n, c)用字符c来填充多出的元素空间。
- resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
- 知道需要空间大小时,reserve可以减少扩容,提高效率.
void Test2()
{
string s1("1234567");
s1.reserve(5);
s1.clear();
s1.resize(20, 'a');
}
3.3 string类对象的访问及遍历操作
- operator[] 返回pos位置的字符的引用
char& operator[] (size_t pos); const char& operator[] (size_t pos) const;- begin + end
begin 获取第一个字符的迭代器,end获取最后一个字符下一个位置的迭代器
iterator begin(); const_iterator begin() const;
iterator end(); const_iterator end() const;- rbegin + rend
rbegin 获取最后一个字符逆序的迭代器 ,rend获取第一个字符前一个位置的迭代器
reverse_iterator rbegin(); const_reverse_iterator rbegin() const;
reverse_iterator rend(); const_reverse_iterator rend() const;- 范围for C++11支持更简洁的范围for的新遍历方式
注:
- operator[] 越界,程序直接终止。string::at() 越界,程序抛异常。
- 迭代器使用时要指定类域。
- 范围for自动判断结束,自动加加。若要修改,要使用auto& ,否则只是赋值给形参。
- 范围for不支持逆序。
void Test3()
{
string s1("1234567");
for (size_t i = 0; i < s1.size(); i++)
{
cout << s1[i];
}
cout << endl;
string::iterator it = s1.begin();
while (it != s1.end())
{
cout << *it;
it++;
}
cout << endl;
string::reverse_iterator it2 = s1.rbegin();
while (it2 != s1.rend())
{
cout << *it2;
it2++;
}
cout << endl;
for (auto x : s1)
{
cout << x;
}
cout << endl;
}
3.4 string类对象的修改操作
- push_back 在字符串后尾插字符c
void push_back (char c);- append 在字符串后追加一个字符串
string& append (const string& str);
string& append (const string& str, size_t subpos, size_t sublen);
string& append (const char* s);
string& append (const char* s, size_t n);
string& append (size_t n, char c);- operator+= 在字符串后追加字符串str c_str(重点) 返回C格式字符串
string& operator+= (const string& str);
string& operator+= (const char* s);
string& operator+= (char c);- find 从字符串pos位置开始往后查找字符c/字符串,返回该字符在字符串中的位置
size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
size_t find (const char* s, size_t pos, size_t n) const;
size_t find (char c, size_t pos = 0) const;- rfind 从字符串pos位置开始往前找字符c/字符串,返回该字符在字符串中的位置
size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos, size_t n) const;
size_t rfind (char c, size_t pos = npos) const;- substr 在str中从pos位置开始,截取n个字符,然后将其返回
string substr (size_t pos = 0, size_t len = npos) const;
注:
- 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
- 如果 find() / rfind() 没有匹配到字符,则返回string::npos(size_t类型的-1 )
void Test4()
{
string s1("123");
s1.push_back('~');
s1.append("abc");
s1 += "456";
cout << s1 << endl;
cout << s1.find("~a") << endl;
cout << s1.find("xx") << endl;
cout << s1.rfind("c4") << endl;
}
3.5 string类非成员函数
- operator+ 返回一个新创建的string对象,值为lhs和rhs相加的结果。
- operator>> 输入运算符重载
- operator<< 输出运算符重载
- getline 获取一行字符串
- relational operators 大小比较
注:
- operator+ 尽量少用,因为传值返回,导致深拷贝效率低。