【C++】string类(1)

起名字真南 2024-10-23 12:35:01 阅读 81

🤖个人主页: 起名字真南

🤖个人专栏:【数据结构初阶】 【C语言】 【C++】

请添加图片描述

目录

引言1 string类的基础知识1.1 什么是string类1.2 string和STL

2 范围for2.1 范围for的语法

3 string类的主要功能和操作3.1 string类的构造3.2 string类对象空间容量操作3.3 string类对象的访问和遍历操作3.4 string类对象的修改操作3.5 string类对象的非成员函数

引言

在C++中,string类是标准库中的一个重要工具,用于处理字符串。与传统的C风格字符串(char数组)相比,C++的string类提供了更高的灵活性和安全性,并且能够自动处理内存管理。因此,掌握string类的使用对于编写高效、安全的C++代码至关重要。本文将从string类的基础知识入手,逐步深入探讨它的常用操作、底层实现及高级技巧,帮助你更好地理解并应用这一强大的工具。

1 string类的基础知识

1.1 什么是string类

C++的string类其实是标准库std的一部分,并且定义在了< string >头文件中,封装了字符数组并且提供了很多便捷的方法

1.2 string和STL

在C++中std::string与STL有着密切的关系(Standard Template Library,标准模板库)有着密切的联系。std::string类实际上是基于STL设计原则构建的一的特殊模板类,用于处理字符串这种常见的数据类型。

1 std::string是STL容器的特例 :

容器是组成STL的六大组件之一,它包含了 std::vector std::list 等等一些容器,而std::string本质上是专门处理字符串的一个容器,和vector< char >有很多相似的地方

自动分配内存:std::string会自动管理储存的字符串内存,在对字符串进行增删查改等内容时会自动分配内存,不需要手动管理迭代器:std::string可以使用STL标准模板库中的迭代器进行遍历整个容器,可以使用begin() end() 用来遍历字符。

例如下面的代码 :

<code>#include<iostream>

#include<string>

using namespace std;

int main()

{

string str = "hello world";

for (auto it : str)

{

cout << it;

}

return 0;

}

这里的for循环时范围for因为后续学习STL的过程中都少不了他的存在所以接下来为大家介绍一下

2 范围for

其实范围for的本质上还是使用了STL中的六大组件之一的迭代器,通过调用begin() end()两个函数来返回string容器中的开头和结尾的迭代器。

2.1 范围for的语法

for(auto it : 容器)

{

cout<< it ;

}

这里的it是一个迭代器而不是指针,但是你可以理解为他是一个智能指针,因为它提供了像(*解引用,++递增)的一些用法,但是并不一定是指向实际内存的地址。而且不同的容器迭代器的类型也不同,例如vector的迭代器就是普通类型,但是list迭代器的类型可能是一个复杂的对象。

指针:则是指向内存的地址,是指向内存中某个位置的变量,并且只能用于数组中还有连续内存中的对象。

如果看不懂的话范围for的写法也可以是这样:

auto begin = str.begin();

auto end = str.end();

for(auto it = begin; it != end; it++)

{

char currentChar = *it;

cout<< currentChar;

}

这里是定义了三个迭代器 分别是begin(用于记录str容器的开头位置)end(用于记录str的结尾位置) 还有it(作为循环变量),在for的循环体中我们定义了一个currentChar的变量用于记录当前字符,然后通过对it进行解引用来获取当前字符,最后输出当前字符然后it++,知道it == end的时候循环结束完整的输出整个字符串。

3 string类的主要功能和操作

在这里给大家提供一个可以作为参考的网址:

链接: C++string参考资料

3.1 string类的构造

函数名称 功能说明
string() (重点) 构造空字符串作为string类的对象
string(const char * s) (重点) 字符串作为string类的对象
string(size_t n, char c) n个字符c来构造string类的对象
string(const string& str) (重点) 用一个string类型来初始化另一个string类型的对象
string (const string& str, size_t pos, size_t len = npos) 使用字符串str的pos位置向后len个长度来构建string类的对象)

代码演示:

int main()

int main()

{

//string()

string s1;

//string(const char* s)

string s2("hello world");

//string(const string& str)

string s3(s2);

//string(siez_t, char c)

string s4(10, 'a');

//string(const string& str, size_t pos, size_t len);

string s5(s3, 6, 5); //区间是左闭右开

cout << "s1 :" << s1 << "\ns2: " << s2 << "\ns3: " << s3 << endl;

cout << "s4: " << s4 << endl;

cout << "s5: " << s5 << endl;

return 0;

}

输出结果:

在这里插入图片描述

<code>由于string的功能太多所以只对主要内容进行讲解。我们在写构造函数的时候需要注意在构造s1 的时候后面不能加()如果加了括号编译器会认为是一个函数声明并且不需要传参,不加括号编译器则会自动调用string的构造函数当我们在使用示例s5构造函数的时候要注意打印的区间是左开右闭,代码示例中是从第六个位置开始打印包括第六个位置后的五个字符

3.2 string类对象空间容量操作

函数名称 功能说明
size() (重点) 返回字符串有效字符长度
length() 返回字符串有效字符长度
capacity() 返回空间总大小
empty() (重点) 检测字符串是否为空,是返回 true,否则返回 false
clear() (重点) 清空有效字符串
reserve(size_t n) (重点) 为字符开辟n个空间
resize(size_t n, char c) (重点) 将字符串的个数改成 n 个,多出的空间用字符 c填充

代码演示:

int main()

{

string s1("hello world");

cout << "s1.size() :" << s1.size() << endl;

cout << "s1.length() :" << s1.length() << endl;

cout << "s1.capacity() :" << s1.capacity() << endl;

if (!s1.empty())

{

cout << "s1.empty() :" << "true" << endl;

}

s1.reserve(40);

cout << "s1.reserve(40) :" << s1.capacity() << endl;

s1.resize(20, 'p');

cout <<"s1.resize(20, 'p'):" << s1 << endl;

s1.clear();

cout<< "s1.clear(): " << s1 << endl;

return 0;

}

输出结果:

在这里插入图片描述

<code>在我们reserve(40)之后为什么编译器开辟的空间是47?是因为编译器的内存管理策略,目的是提高性能并减少未来重新分配,一般开辟的空间只会比我们输入的更大不会更小

3.3 string类对象的访问和遍历操作

函数名称 功能说明
operator[] (pos) (重点) 返回 pos 位置的字符const string 类对象调用
begin() + end() begin() 获取第一个字符的迭代器 + end() 获取最后一个字符下一个位置的迭代器
rbegin() + rend() rbegin() 获取反向迭代的第一个字符的迭代器 + rend() 获取最后一个字符前一个位置的反向迭代器
范围 for (for (auto& item : container)) C++11 支持更简洁的范围 for 的新遍历方式

代码演示:

int main()

{

string s1("hello world");

for (int i = 0; i < s1.size(); i++)

{

cout << s1[i];

}

cout << endl;

auto begin = s1.begin();

auto end = s1.end();

for (auto it = begin; it != end; it++)

{

cout << *it;

}

cout << endl;

for (auto i : s1)

{

cout << i;

}

cout << endl;

auto rbegin = s1.rbegin();

auto rend = s1.rend();

for (auto it = rbegin; it != rend; it++)

{

cout << *it;

}

return 0;

}

输出结果:

在这里插入图片描述

<code>需要注意一种情况就是在调用rbegin 和 rend的时候最后循环条件改变的方式依旧是++,而不是--。

3.4 string类对象的修改操作

函数名称 功能说明
push_back (char c) 字符串后尾插字符 c
append (const char * ch) 在字符串后追加一个字符串 ch
operator+= (const char * ch) (重点) 在字符串后追加字符串 ch
c_str() (重点) 返回 C 格式字符串
find (const char * s, size_t pos = 0) + npos (重点) 从字符串 pos 位置开始往后查找字符串 s,返回字符串中的位置
rfind (const char * s, size_t pos = npos) 从字符串 pos 位置开始往前查找字符串 s,返回字符串中的位置
substr (size_t pos = 0, size_t len = npos) 在字符串中从 pos 位置开始,截取 len 个字符,然后将其返回

代码演示:

int main()

{

string s1;

s1.push_back('a');

s1.push_back('a');

s1.push_back('a');

s1.push_back('a');

cout << s1 << endl;

s1.append("bxvxcvb");

cout << s1 << endl;

s1 += "xzviuynq";

cout << s1 << endl;

size_t c = s1.find('c', 0);

cout << "c第一次出现的坐标大小 :" << c << endl;

size_t rc = s1.rfind('c',-1);

cout << "c最后一次出现的坐标大小 :" << rc << endl;

string s2;

s2 = s1.substr(0, 9); //左闭右开所以返回的是下标从0-8的字符

cout << s2 << endl;

if (strcmp(s1.c_str(), s2.c_str()) > 0)

{

cout << "s1 > s2" << endl;

}

else if (strcmp(s1.c_str(), s2.c_str()) < 0)

{

cout << "s1 < s2" << endl;

}

else

{

cout << "s1 == s2" << endl;

}

return 0;

}

输出结果:

在这里插入图片描述

<code>注意这里的find 和refind 的返回值都是字符c的坐标,我们调用c_str的原因是我们没有重载< 和 >操作符所以不能对string类直接进行比较,所以我们需要使用c_str来将他们转换成字符型来进行比较。

3.5 string类对象的非成员函数

函数名称 功能说明
operator+ 将两个字符串拼接并返回一个新字符串
relational operators (==, !=, <, >, <=, >=) 用于比较两个字符串的大小或相等性
swap (string& str) 交换两个字符串的内容
operator>> (istream& in, string& str) 从输入流读取字符串
operator<< (ostream& out, const string& str) 将字符串输出到输出流
getline (istream& in, string& str) 从输入流中读取一行字符串,直到遇到换行符

代码演示:

int main()

{

string s1("hello ");

string s2("world");

string s3 = s1 + s2;

cout << s3 << endl;

string foo = "alpha";

string bar = "beta";

if (foo == bar) cout << "foo and bar are equal\n";

if (foo != bar) cout << "foo and bar are not equal\n";

if (foo < bar) cout << "foo is less than bar\n";

if (foo > bar) cout << "foo is greater than bar\n";

if (foo <= bar) cout << "foo is less than or equal to bar\n";

if (foo >= bar) cout << "foo is greater than or equal to bar\n";

string s4;

cout << "s4 = ";

cin >> s4;

cout << s4 << endl;

cin.ignore();

string s5;

cout << "输入一串文字 :";

getline(cin, s5);

cout << s5 <<endl;

return 0;

}

输出结果:

在这里插入图片描述

<code>注意当我们在使用cin和getline的时候需要注意一种情况就是cin只会读取到空格而在你输出的完之后按下的空格cin不会读取而是会存到缓冲区里,当我们使用getline的时候会直接读取缓冲区的\n从而导致程序出错直接结束不会再读取你输入的内容。,

解决的办法有两种:

使用cin.ignore()用来清除缓冲区的一个字符一般是换行符‘\n’先执行getline()在用cin。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。