C++初阶——string类
一、什么是string类
string类是C++标准库中的一个类,它提供对字符串的管理和操作功能。以下是string类的一些关键特性:
-
动态数组:string类是一个动态数组,可以存储字符序列,并且可以自动调整大小以适应存储的字符数量。
-
构造函数:string类提供了多种构造函数,允许从C风格字符串、另一个string对象、字符数组等创建字符串对象。
-
赋值和初始化:string类支持赋值运算符=,用于将一个字符串的内容复制给另一个字符串对象。
-
大小和容量:string类提供了.size()、.length()、.empty()、.capacity()等方法来获取字符串的大小和容量。
-
访问和修改:string类提供了下标运算符[]和.at()方法来访问和修改字符串中的字符。
-
迭代器:string类支持迭代器,允许使用.begin()和.end()方法遍历字符串。
-
连接和插入:string类提供了+和+=运算符来连接字符串,以及.insert()方法在指定位置插入字符或字符串。
-
删除和替换:string类提供了.erase()方法来删除字符串中的字符或子字符串,以及.replace()方法来替换字符串中的字符或子字符串。
-
比较:string类提供了比较运算(==、!=、>、<、>=、<=)来比较两个字符串。
-
查找和搜索:string类提供了.find()、.refind()、.find_first_of()、.find_last_of()方法来在字符串中查找字符或子字符串。
-
子字符串:string类提供了.substr()方法来获取字符串的子字符串。
-
C风格字符串:string类提供了.c_str()方法来获取C风格字符串。
string类有大约100个接口,这里的学习遵循二八原则即可,会用常用的,知道其它的。
二、string类对象的常见构造
函数名称 | 功能 |
string() | 构造空的string类对象,即空字符串 |
string(const char*s) | 用C-string类构造string类对象 |
strinf(size_t n, char c) | string类对象中包含n个字符c |
string(const string&s) | 拷贝构造函数 |
#include<iostream>
#include<string>
using namespace std;int main()
{string s1; //构造空的string类对象s1string s2("hello world!");//用c风格字符串构造类对象s2string s3(10, 'a');//构造类对象s3,用10个a初始化它string s4(s2);//拷贝构造s4s1 = s3;//用=给s1赋值,将s3的值赋给s1cout << s2 << endl;cout << s3 << endl;cout << s4 << endl;return 0;
}
三、string类对象的容量操作
函数名称 | 功能说明 |
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capactiy | 返回空间总大小 |
empty | 检查字符串是否为空串,若是返回ture,否则返回false |
clear | 清空有效字符 |
reserve | 为字符串预留空间 |
resize | 将有效字符的个数改为n个,多出的空间用字符c填充 |
3.1size函数和length函数
size_t size() const noexcept;
size_t length() const noexcept;
在C++的string类中,size()和length()函数都用于返回字符串的长度,即字符串中字符的数量,这两个函数在功能上是等价的,返回一个size_t类型的值。返回的字符数量不包括结尾的空字符。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;string s2("hello world!");string s3(10, 'a');cout << s3.size() << endl;cout << s3.length() << endl;
}
C++是兼容C与语言的,所以沿用了C语言对字符串的处理风格,考虑到语言的兼容性,采用length函数来获取字符串的长度。后来在设计STL的时候,为了遵循容器接口的规范,使用size函数来获取字符串的长度。它们在功能上是等价的,开发者可根据个人偏好和团队要求选择使用。
3.2capacity函数
size_t capacity() const noexcept;
使用capacity函数获取已分配给字符串的空间能够容纳的字符数量,包括已经存储的字符和还未使用的空间,这个值至少与size函数的返回值一样大,但通常会更大,因为会预分配更多的空间以提高效率。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;string s2("hello world!");string s3(10, 'a');cout << s3.size() << endl;cout << s3.capacity() << endl;
}
3.3empty函数
bool empty() const noexcept;
empty函数用于检测字符串是否为空,如果字符串是个空串返回true,否则返回false。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;string s2("hello world!");string s3(10, 'a');cout << s1.empty() << endl;cout << s3.empty() << endl;
}
3.4clear函数
void clear() noexcept;
clear函数用于清空字符串的内容,将其变为一个空字符串,但是分配给字符串的空间仍然保留。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;string s2("hello world!");string s3(10, 'a');s3.clear();cout << s3.size() << endl;cout << s3.capacity() << endl;
}
3.5reserve函数
void reserve (size_t n = 0);
reserve函数用于预留足够的内存以存储指定数量的字符。这个函数会接收一个参数,即你希望字符串能够容纳的字符数。如果当前容量小于给定的参数,会涉及到动态内存分配,以确保有足够的空间来存储指定数量的字符。如果当前的容量已经大于或等于指定的值,则不会进行任何操作。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;cout << s1.capacity() << endl;s1.reserve(100);cout << s1.capacity() << endl;
}
3.6resize函数
void resize (size_t n);
void resize (size_t n, char c);
resize函数用于改变字符串的长度。这个函数可以接受两个参数,一个是你希望字符串达到的新长度,另一个是用于填充空位置的字符,默认为'\0'。
#include<iostream>
#include<string>
using namespace std;int main()
{string s1;string s2("hello world!");string s3(10, 'a');s2.resize(20, 'a');cout << s2 << endl;s2.resize(3);cout << s2 << endl;
}
注意:resize函数在改变元素个数时,如果元素个数增多可能改变底层容量。如果是将元素减少,底层总空间不变。
四、string类对象的访问及遍历操作
函数名称 | 功能说明 |
operator[] | 返回给定下标位置的字符 |
begin+end | begin获取第一个字符的迭代器+end获取最后一个字符的下一个位置迭代器。 |
rbegin + rend | 与begin+end相反 |
范围for | C++提供了更简洁的范围for的遍历方式 |
4.1operator[]
char& operator[] (size_t pos);
const char& operator[] (size_t pos) const;
string类重载了[],允许通过下标访问字符串中的字符。这个操作是常数时间的,但不会检查边界,因此可能会导致越界错误。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");for (int i = 0; i < s2.size(); ++i){cout << s2[i]) << " ";}
}
4.2at函数
char& at (size_t pos);
const char& at (size_t pos) const;
at函数与operator[]是一样的,但是它会检查边界,在越界的时候抛出out_of_range异常。它安全方面更优,但是性能稍差。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");for (int i = 0; i < s2.size(); ++i){cout << s2.at(i) << " ";}
}
4.3迭代器
iterator begin() noexcept;
const_iterator begin() const noexcept;iterator end() noexcept;
const_iterator end() const noexcept;reverse_iterator rbegin() noexcept;
const_reverse_iterator rbegin() const noexcept;reverse_iterator rend() noexcept;
const_reverse_iterator rend() const noexcept;
迭代器是STL中的核心概念,它是一种抽象的方法用来访问容器中的元素,迭代器可以被视为一种泛化的指针,它指向容器中的一个元素,并提供一种方式来访问和操作该元素。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");for (auto i = s2.begin(); i != s2.end(); ++i)cout << *i << " ";cout << endl;for (auto i = s2.rbegin(); i != s2.rend(); ++i)cout << *i << " ";
}
4.4范围for
基于范围for,C++提供了一种简洁的方式来遍历容器中的元素。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");for (auto s : s2)cout << s << " ";
}
五、string类对象的修改操作
函数名称 | 功能说明 |
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= | 在字符串后追加字符串str |
c_str | 返回C格式字符串 |
find | 从字符串pos开始往后找字符c返回该字符在字符串中的位置 |
rfind | 从字符串pos开始往前找字符c返回该字符在字符串中的位置 |
substr | 在str中pos位置开始,截取n个字符,然后将其返回 |
5.1 push_back
void push_back (char c);
push_back函数用于在字符串的末尾添加一个字符。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");s2.push_back('m');s2.push_back('y');s2.push_back('f');s2.push_back('r');s2.push_back('i');s2.push_back('e');s2.push_back('n');s2.push_back('d');cout << s2;
}
注意:
- 这个操作会改变字符串的内容,增加一个字符的长度,并且可能增加字符串的容量。
- push_back是一个就地操作,它会改变字符串的状态,而不是创建一个新的字符串。
- 可能会导致字符串重新分配内存,尤其是当添加的字符超过当前容量时。这可能会导致性能开销,因为需要复制现有字符到新的内存位置。
- 如果预计会频繁向字符串添加字符,可以先使用reserve预留足够的空间,以减少重新分配的次数。
5.2append函数和operator+=
在string类中,append函数和operator+=都是用来连接字符串的成员函数,但它们使用的行为和场景有所不同。
- append
-
string (1) string& append (const string& str); substring (2) string& append (const string& str, size_t subpos, size_t sublen); c-string (3) string& append (const char* s); buffer (4) string& append (const char* s, size_t n); fill (5) string& append (size_t n, char c); range (6) template <class InputIterator>string& append (InputIterator first, InputIterator last); initializer list(7) string& append (initializer_list<char> il);
- append可以接收一个string类对象、C风格字符串或者一个字符。
- append不返回任何值。
#include<iostream> #include<string> using namespace std;int main() {string s2("hello world!");s2.append("my friend");cout << s2; }
-
- operator+=
-
string (1) string& operator+= (const string& str); c-string (2) string& operator+= (const char* s); character (3) string& operator+= (char c); initializer list (4) string& operator+= (initializer_list<char> il);
- operator+=接收一个string类对象作为参数。
- 会将传入的字符串整体添加到当前字符串的末尾。
- 返回对当前字符串对象的引用,这允许链式操作。
#include<iostream> #include<string> using namespace std;int main() {string s2("hello world!");string s3("my friend");s2 += s3;cout << s2; }
-
5.3c_str
const char* c_str() const noexcept;
在C++中,string类的c_str函数用于获取一个指向以空字符('\0')结尾的字符数组的指针,这个字符数组与string对象中的内容相同。这个函数通常用于与需要C风格字符串的旧式C函数或C++库函数进行交互。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");const char* str = s2.c_str();cout << *str;
}
注意:
- c_str函数的指针只在原对象的生命周期内有效。如果象被销毁,返回的指针就会变成野指针,指向的内存区域可能不再有效。
- c_str返回的是const char*类型,这意味着你不能通过这个指针修改字符串的内容。
5.4find和rfind
string (1) size_t find (const string& str, size_t pos = 0) const noexcept;
c-string (2) size_t find (const char* s, size_t pos = 0) const;
buffer (3) size_t find (const char* s, size_t pos, size_type n) const;
character (4) size_t find (char c, size_t pos = 0) const noexcept;
find函数是一个非常有用的成员函数,用于在字符串中从前往后搜索指定的子串或字符,并返回它出现第一次出现的位置。如果找不到就返回npos,这是一个表示不存在的特殊值。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");size_t pos1 = s2.find('w');//查找单个字符cout << pos1 << endl;size_t pos2 = s2.find("wor");//查找字符串cout << pos2 << endl;size_t pos3 = s2.find("lk");//查找不存在的字符cout << pos3 << endl;
}
rfind函数用于从后往前遍历,查找最后一次出现的位置。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");size_t pos1 = s2.rfind('w');//查找单个字符cout << pos1 << endl;size_t pos2 = s2.rfind("wor");//查找字符串cout << pos2 << endl;size_t pos3 = s2.rfind("lk");//查找不存在的字符cout << pos3 << endl;
}
注意:
- 这两个函数对大小写是敏感的,这意味着需要区分大写字母和小写字母。
- 它们的效率取决于字符串的长度和要查找的子串或字符。在最坏的情况下,它可能需要检查字符串中的每个字符,这可能导致性能问题。
5.5substr
string substr (size_t pos = 0, size_t len = npos) const;
类的一个成员函数,它用于从字符串中提取一个子串。这个函数接受两个参数:子串的起始位置和子串的长度。如果省略第二个参数,substr将从起始位置开始提取到原字符串的末尾。
#include<iostream>
#include<string>
using namespace std;int main()
{string s2("hello world!");string s3 = s2.substr(5, 7);cout << s3;
}
注意:
- 如果第一个参数超过字符的长度会抛出out_of_range异常。
- 如果pos+len超过字符长度,则只会提取到字符串的末尾,而不是抛出异常。