💗个人主页💗
⭐个人专栏——C++学习⭐
💫点击关注🤩一起学习C语言💯💫
目录
导读
1. 基本概述
2. string类对象的常见构造
3. string类对象的容量操作
4. string类对象的访问及遍历操作
5. 迭代器
6. string类对象的修改操作
6.1 基本修改操作
6.2 c_str()函数
6.3 find + npos、rfind和substr
7. 输入输出流、关系运算符以及getline
7.1输入输出流
7.2 关系运算符
7.3 getline
导读
今天我们来学习在C++中string类的常见用法,比如构造、容量操作、遍历访问以及一些修改操作。
1. 基本概述
C++中的string类是一个用于处理字符串的标准库类。它提供了一些常用的操作和函数,使得字符串的处理更加方便和高效。
-
字符串的表示:string类可以表示一个字符序列,可以包含任意长度的字符。字符串可以由字符数组或者字符串字面值初始化。
-
字符串的操作:string类提供了一系列操作函数,包括字符串的连接、复制、查找、比较等。可以通过这些操作函数对字符串进行各种操作。
-
字符串的长度:string类提供了成员函数length()和size()来获取字符串的长度,即字符的个数。
-
字符串的访问:string类的字符可以通过下标操作符[]来访问,也可以通过at()函数来访问。同时,还可以通过迭代器来遍历字符串。
-
字符串的修改:string类的字符可以通过下标操作符[]进行修改,也可以通过成员函数append()、insert()、erase()等进行修改。
-
字符串的输入输出:string类可以通过输入输出流进行字符串的输入和输出,可以参与标准的输入输出操作。
-
字符串的比较:string类提供了比较操作符==、!=、>、<、>=、<=来比较字符串的大小。
总之,string类是C++中用来处理字符串的一个非常重要的类,提供了丰富的操作函数和方法,方便了字符串的处理和操作。
2. string类对象的常见构造
函数名称 | 功能说明 |
---|---|
string() | 构造空的string类对象,即空字符串 |
string(const char* s) | 用C-string来构造string类对象 |
string(size_t n, char c) | string类对象中包含n个字符c |
string(const string&s) | 拷贝构造函数 |
void test_string1()
{
string s0; //使用默认构造函数构造一个空的string对象s0。
string s1("hello world");//使用字符串字面值构造一个string对象s1
string s2(s1);//使用s1进行拷贝构造,构造一个新的string对象s2
string s3(s1, 5, 3);//构造一个从s1的第5个字符开始的长度为3的子串,构造的string对象为s3。
string s4(s1, 5, 10);//造一个从s1的第5个字符开始的长度为10的子串,
string s5(s1, 5);//构造一个从s1的第5个字符开始的子串,直到字符串末尾,
cout << s0 << endl;
cout << s1 << endl;
cout << s2 << endl;
cout << s3 << endl;
cout << s4 << endl;
cout << s5 << endl;
string s6(10, '#');//使用重复10次的字符'#'构造一个string对象s6。
cout << s6 << endl;
s0 = s6;//将s6的值赋给s0
cout << s0 << endl;
}
int main()
{
test_string1();
return 0;
}
3. string类对象的容量操作
函数名称 | 功能说明 |
---|---|
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
empty | 检测字符串释放为空串,是返回true,否则返回false |
clear | 清空有效字符 |
reserve | 为字符串预留空间** |
resize | 将有效字符的个数该成n个,多出的空间用字符c填充 |
void capacity_operations()
{
string str = "hello world";
cout << "Size of the string: " << endl;
cout << str.size() << endl;
cout << "Length of the string: " << endl;
cout << str.length() << endl;
str.resize(5); // 修改字符串的长度为5
cout << "After resizing the string: " << endl;
cout << str << endl;
str.resize(10, 'a'); // 修改字符串的长度为10,并用字符 'a' 填充剩余部分
cout << "After resizing and filling the string: " << endl;
cout << str << endl;
str.clear(); // 清空字符串
cout << "After clearing the string: " << endl;
cout << str << endl;
cout << "Is the string empty? " << endl;
cout << (str.empty() ? "Yes" : "No") << endl;
cout << "Capacity of the string: " << endl;
cout << str.capacity() << endl;
str.reserve(20); // 设置容量为20
cout << "New capacity of the string: " << endl;
cout << str.capacity() << endl;
}
int main()
{
capacity_operations();
return 0;
}
注意:
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一 致,一般情况下基本都是用size()。
- clear()只是将string中有效字符清空,不改变底层空间大小。
- resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字 符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的 元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大 小,如果是将元素个数减少,底层空间总大小不变。
- reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于 string的底层空间总大小时,reserver不会改变容量大小。
在这里可能有小伙伴们注意到了
为什么capacity返回的容量会比我们实际的多一些?
capacity()
函数返回当前字符串的容量,即字符串在不重新分配内存的情况下可以容纳的字符数。容量包括字符串实际存储的字符数以及额外的预留空间。
预留空间是为了避免频繁地进行内存重新分配操作,当字符串的空间不足时,string 类会自动分配一块更大的内存空间,并将原来的字符拷贝到新的内存中。
需要注意的是,
capacity()
返回的容量不一定和实际分配的内存大小相等。实际分配的内存大小可以通过sizeof(string)
来获得,这个大小包括了除了存储字符之外的其他开销,比如指针、长度信息等。
4. string类对象的访问及遍历操作
函数名称 | 功能说明 |
---|---|
operator[ ] | 返回pos位置的字符,const string类对象调用 |
begin+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 |
范围for | C++11支持更简洁的范围for的新遍历方式 |
void access_string()
{
string str = "hello world";
// 使用下标访问单个字符
cout << "Using index access:";
for (size_t i = 0; i < str.size(); i++)
{
cout << str[i] << " ";
}
cout << endl;
// 使用迭代器访问单个字符
cout << "Using iterator access:";
for (auto it = str.begin(); it != str.end(); ++it)
{
cout << *it << " ";
}
cout << endl;
// 使用范围-based for循环遍历字符
cout << "Using range-based for loop:";
for (char ch : str)
{
cout << ch << " ";
}
cout << endl;
}
int main()
{
access_string();
return 0;
}
operator[]
是C++中用于访问容器或数组中元素的运算符。
使用
operator[]
访问字符串中的字符时,如果索引越界,行为是未定义的。因此,在使用operator[]
之前,应该确保索引在有效范围内。可以使用size()
函数获取字符串的长度,并将索引与长度进行比较来确保不越界。
rbegin()
和 rend()
是用于反向遍历字符串的迭代器
rbegin()
函数返回一个指向字符串最后一个字符的逆向迭代器,即反向起始迭代器,而rend()
函数返回一个指向字符串第一个字符的前一个位置的逆向迭代器,即反向结束迭代器。
范围for
循环是C++11引入的一种语法糖,用于迭代一个范围内的元素。
我们使用范围
for
循环来遍历字符串str
中的字符。在每次迭代时,当前字符被赋值给变量ch
,然后我们将其输出。范围
for
循环会自动处理迭代器的初始化和结束条件,并且会在循环内部按顺序遍历范围内的所有元素。
5. 迭代器
迭代器是一种用于访问容器(如数组、链表、字符串等)中元素的对象。它类似于指针,可以用来遍历容器中的元素,并进行读取、修改等操作。
在 C++ 中,string 类也提供了迭代器来遍历字符串中的每个字符。
string类提供了多种类型的迭代器,包括正向迭代器、反向迭代器和常量迭代器。
int main()
{
string str = "Hello, World!";
// 正向迭代器
string::iterator it;
for (it = str.begin(); it != str.end(); ++it)
{
cout << *it; // 输出当前字符
}
cout << endl;
// 反向迭代器
string::reverse_iterator rit;
for (rit = str.rbegin(); rit != str.rend(); ++rit)
{
cout << *rit; // 输出当前字符
}
cout << endl;
// 使用常量迭代器遍历字符串
string::const_iterator its;
for (its = str.begin(); its != str.end(); ++its)
{
cout << *its << " ";
}
cout << endl;
return 0;
}
使用常量迭代器可以确保在遍历字符串时不会修改字符串的内容。常量迭代器可以通过使用const_iterator
或const_reverse_iterator
类型来声明。
6. string类对象的修改操作
函数名称 | 功能说明 |
---|---|
push_back | 在字符串后尾插字符c |
append | 在字符串后追加一个字符串 |
operator+= | 在字符串后追加字符串str |
c_str | 返回C格式字符串 |
find + npos | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
6.1 基本修改操作
int main()
{
string str = "Hello";
// 使用赋值运算符修改字符串的内容
str = "Hello World";
cout << str << endl;
//使用push_back函数在字符串的末尾添加一个字符。
str.push_back('?');
cout << str << endl;
// 使用+=运算符进行字符串追加
str += "!";
cout << str << endl;
// 使用append函数进行字符串追加
str.append(" Welcome");
cout << str << endl;
// 使用insert函数在指定位置插入字符或子字符串
str.insert(6, " to");
cout << str << endl;
// 使用erase函数删除指定位置的字符或子字符串
str.erase(11, 8);
cout << str << endl;
// 使用replace函数替换指定位置的字符或子字符串
str.replace(6, 2, "everybody");
cout << str << endl;
//使用assign函数将字符序列赋值给字符串对象
str.assign(" xxxxx");
cout << str << endl;
//将字符序列的一部分赋值给字符串对象
str.assign("Hello World", 5);
cout << str << endl;
return 0;
}
insert/erase/replace能少用就要少用,因为基本都要挪动数据,效率不高。
6.2 c_str()函数
c_str()是string类的一个成员函数,用于返回一个指向string对象中字符数组的指针。一般情况下,我们使用c_str()来将string对象转换为C风格字符串。
int main()
{
string str = "Hello, World!";
const char* cstr = str.c_str();
cout << cstr << endl;
return 0;
}
6.3 find + npos、rfind和substr
find+npos:
find函数用于在字符串中查找指定子串的位置。npos是string类的静态成员常量,它的值是一个特殊的无效位置(通常为-1)。
int main()
{
string str = "Hello, World!";
string subStr = "World";
size_t found = str.find(subStr);
if (found != string::npos)
{
cout << "子字符串所在位置: " << found << endl;
}
else {
cout << "没有找到" << endl;
}
return 0;
}
需要注意的是,npos
的值是一个特殊值,可以用于与find
函数的返回值比较,以判断子串是否找到。在大多数情况下,npos
的值是一个非法的位置 。
rfind 函数:
用于在字符串中从后往前查找子串的位置。rfind
函数返回子串最后一次出现的位置,如果未找到则返回一个特殊的值npos
。
int main()
{
string str = "Hello, Hello, World!";
size_t found = str.rfind("Hello");
if (found != string::npos)
{
cout << "Last occurrence found at position: " << found << endl;
}
else
{
cout << "Substring not found." << endl;
}
return 0;
}
substr函数:
substr函数用于从一个字符串中提取子串。
它接受两个参数:开始位置和要提取的子串的长度。
int main()
{
string str = "Hello, World!";
// 提取从位置7开始的子串
string sub1 = str.substr(7);
cout << "Substring 1: " << sub1 << endl;
// 提取从位置0开始长度为5的子串
string sub2 = str.substr(0, 5);
cout << "Substring 2: " << sub2 << endl;
return 0;
}
注意:
如果提供的位置超出了字符串的长度,或者指定的长度超出了可用的子串长度,都会导致未定义行为。因此,在使用substr函数时需要确保提供的参数符合字符串的有效范围。
7. 输入输出流、关系运算符以及getline
函数 | 功能说明 |
---|---|
operator>> | 输入运算符重载 |
operator<< | 输出运算符重载 |
getline | 获取一行字符串 |
relational operators | 大小比较 |
7.1输入输出流
operator>>
和operator<<
都是C++中的重载运算符,用于对输入流和输出流进行操作。
operator>>
是输入流运算符,用于从输入流中读取数据。
istream& operator>>(istream& is, T& value);
其中,
is
是输入流对象,value
是要读取数据的变量或对象。operator>>
函数返回一个输入流对象,并将读取到的数据存储到value
中。
operator<<
是输出流运算符,用于向输出流中写入数据。
ostream& operator<<(ostream& os, const T& value);
其中,
os
是输出流对象,value
是要写入输出流中的变量或对象。operator<<
函数返回一个输出流对象。
这两个运算符可以重载为类成员函数或非成员函数。当重载为类成员函数时,第一个参数是隐式的,表示调用运算符的对象;当重载为非成员函数时,可以在函数的参数列表中指定输入/输出流对象。
class Point
{
public:
int x, y;
};
//非成员函数
ostream& operator<<(ostream& os, const Point& p)
{
os << "(" << p.x << ", " << p.y << ")";
return os;
}
//非成员函数
istream& operator>>(istream& is, Point& p)
{
is >> p.x >> p.y;
return is;
}
int main()
{
Point p;
cout << "Enter x and y coordinates: ";
cin >> p;
cout << "You entered: " << p << endl;
return 0;
}
operator<<
被重载为非成员函数,用于将Point
对象的坐标输出到输出流中;operator>>
也被重载为非成员函数,用于从输入流中读取坐标并存储到Point
对象中。在main()
函数中,程序首先提示用户输入坐标,然后使用operator>>
运算符将读取到的坐标存储到Point
对象p
中,最后使用operator<<
运算符将p
对象的值输出到屏幕上。
7.2 关系运算符
在C++中,string
类型可以使用关系运算符(relational operators)进行比较。以下是string
类型可用的关系运算符:
==
:检查两个字符串是否相等。!=
:检查两个字符串是否不相等。<
:检查第一个字符串是否小于第二个字符串(按字典顺序比较)。>
:检查第一个字符串是否大于第二个字符串(按字典顺序比较)。<=
:检查第一个字符串是否小于等于第二个字符串(按字典顺序比较)。>=
:检查第一个字符串是否大于等于第二个字符串(按字典顺序比较)。
int main()
{
string str1 = "hello";
string str2 = "world";
if (str1 == str2)
{
cout << "The strings are equal" << endl;
}
else if (str1 < str2)
{
cout << "str1 is less than str2" << endl;
}
else
{
cout << "str1 is greater than str2" << endl;
}
return 0;
}
7.3 getline
getline
函数,用于从输入流(如键盘、文件)中读取一行字符串。
getline(istream& input_stream, string& str, char delimiter);
input_stream
是输入流,可以是cin
(键盘输入)或ifstream
(文件输入)等。str
是用于存储读取的字符串的变量,它必须是string
类型的引用。delimiter
是一个可选参数,表示行结束的分隔符,默认值为换行符\n
。
int main()
{
string str;
cout << "Enter a line of text: ";
getline(cin, str);
cout << "You entered: " << str << endl;
return 0;
}