string类函数--深入浅出了解

目录

  • 1.为什么学习string类
    • 1.1C语言中的字符串
    • 1.2OJ题中的优势
  • 2.标准库中的string类
  • 3.string类的常用接口函数
    • 3.1string类对象的常见构造
    • 3.2string类对象的容量操作
    • 3.3string类对象的访问及遍历操作
    • 3.4string类的修改操作
    • 3.5string类的非成员函数
  • 总结

1.为什么学习string类

1.1C语言中的字符串

C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。

1.2OJ题中的优势

OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数。

2.标准库中的string类

  1. 字符串是表示字符序列的类
  2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
  3. string类是使用char作为它的字符类型,即使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
  4. string类basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traitsallocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
  5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码字符)来操作。

总结:

string是表示字符串的字符串类 ② 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
string在底层实际是:basic_string模板类别名,typedefbasic_stringchar_traits,
allocator>string; ④不能操作多字节或者变长字符的序列。
⑤在使用string类时,必须包含#include头文件以及using namespace std

3.string类的常用接口函数

3.1string类对象的常见构造

string类的构造函数如下:
string类函数--深入浅出了解_第1张图片
介绍经常使用的构造函数:

string();//用空字符串构造一个空string类对象,长度为0
string (const char* s);//用C语言字符串构造string类对象
string (size_t n, char c);//用n个字符c构造string类对象
string (const string& str);//用一个string类str拷贝构造string类对象
string (const string& str, size_t pos, size_t len = npos);
//从str对象pos位置拷贝len字节内容构造string类对象,如果str对象很短或len=npos,则拷贝str对象末尾
static const size_t npos = -1;
//npos为静态成员变量,-1存储在无符号整型中会发生整型提升,为整型的最大值

栗子:

void Test1()
{
	string str1;
	cout << str1 << endl;
	string str2("hello world");
	cout << str2 << endl;
	string str3(10, 'x');
	cout << str3 << endl;
	string str4(str2);
	cout << str4 << endl;
	string str5(str2, 6);
	cout << str5 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第2张图片
string类赋值运算符重载

和内置类型赋值运算符一样,string类赋值运算符重载,会将赋值对象原有的数据进行覆盖赋值!

string (1)	
string& operator= (const string& str);
//用string类str对象进行赋值
c-string (2)	
string& operator= (const char* s);
//用C字符串进行赋值
character (3)	
string& operator= (char c);
//用C字符进行赋值

eg:

void Test2()
{
	string str1("hello world");
	cout << str1 << endl;
	string str2;
	str2 = str1;
	cout << str2 << endl;
	str2 = "xxxxx";
	cout << str2 << endl;
	str2 = 'y';
	cout << str2 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第3张图片

3.2string类对象的容量操作

size_t size() const;//以字节为单位返回字符串的有效长度
size_t length() const;//以字节为单位返回字符串的有效长度
size_t capacity() const;//以字节形式返回string类存储的容量大小
bool empty() const;//检测字符串是否为空串,是返回true,否则返回false

eg1:

void Test3()
{
	string str1("hello world");
	printf("string类的大小为:");
	cout << str1.size() << endl;
	printf("string类的大小为:");
	cout << str1.length() << endl;
	printf("string类的存储容量为:");
	cout << str1.capacity() << endl;
	printf("string类的判空值为:");
	cout << str1.empty() << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第4张图片

  1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()
void clear();//清空有效字符串的内容,使string类对象变为空字符串
void resize (size_t n);
void resize (size_t n, char c);
//将string类有效字符数调整为n,多出的空间为用指定的字符c进行初始化,如果不指定则用'\0'进行初始化
void reserve (size_t n = 0);//为string类预留n字节存储空间大小

eg2:

void Test4()
{
	string str1("hello world");
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
	str1.resize(20, 'x');//调整有效字符的个数--调大
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
	str1.reserve(50);//调整存储空间的大小--调大
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
	str1.clear();//清除有效字符大小
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第5张图片

  1. clear()只是将string中有效字符清空,不改变底层空间大小。
  2. resize(size_t n)resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)'\0'来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。

eg3:

void Test5()
{
	string str1("hello world");
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
	str1.resize(6);//调整有效字符的个数--调小
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
	str1.reserve(6);//调整存储空间的大小--调小
	printf("string对象的内容为:");
	cout << str1 << endl;
	printf("string类的字符串大小为:");
	cout << str1.size() << endl;
	printf("string类当前的存储容量为:");
	cout << str1.capacity() << endl;
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第6张图片
注意:

4.resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
5. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好
6. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserve不会改变容量大小

eg4:

void Test6()
{
	string str1("hello world");
	size_t old = str1.capacity();
	cout << "初始容量为:" << str1.capacity() << endl;
	for (int i = 0; i <= 100; i++)
	{
		str1 += 'x';
		if (old != str1.capacity())
		{
			cout << "扩容:" << str1.capacity() << endl;
			old = str1.capacity();
		}
	}
}

代码编译运行的结果为:
string类函数--深入浅出了解_第7张图片

6.在VS2019编译器下,string类以原有容量的1.5倍进行扩容。

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

函数名称:

char& operator[] (size_t pos);
//可以对返回string类对象pos位置的字符进行读写
const char& operator[] (size_t pos) const;
//只能对const string类对象pos位置的字符读取操作,不饿进行修改

eg1:

void Test8()
{
	string str1("hello world");
	//对修改前的str1对象进行读取操作
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1[i];
	}
	cout << endl;
	//对str1对象进行修改操作
	for (int i = 0; i < str1.size(); i++)
	{
		str1[i]++;//等价于str.operator[i]++
		cout << str1[i];
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第8张图片
函数名称:

char& at (size_t pos);
//可以对返回string类对象pos位置的字符进行读写
const char& at (size_t pos) const;
//只能对const string类对象pos位置的字符读取操作,不饿进行修改

eg2:

void Test9()
{
	string str1("hello world");
	//对修改前的str1对象进行读取操作
	for (int i = 0; i < str1.size(); i++)
	{
		cout << str1.at(i);
	}
	cout << endl;
	//对str1对象进行修改操作
	for (int i = 0; i < str1.size(); i++)
	{
		str1.at(i)++;
		cout << str1.at(i);
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第9张图片
函数operator[]与函数at的区别:
eg3:

void Test10()
{
	//operator[]越界访问
	string str1("hello world");
	str1[12]++;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第10张图片
eg4:

void Test11()
{
	//函数at越界访问
	string str1("hello world");
	try//捕获异常
	{
		str1.at(12)++;
	}
	catch (const exception& e)
	{
		cout << e.what() << endl;
	}
}

代码编译运行的结果为:
string类函数--深入浅出了解_第11张图片

string类对象越界访问的时候,函数operator[]通过断言assert报错,函数at通过抛异常报错误。

函数名称:

iterator begin();
const_iterator begin() const;
//begin获取string类第一个字符的迭代器(从左到右)
iterator end();
const_iterator end() const;
//end为获取最后一个字符下一个位置的迭代器(从左到右)

图形理解:
string类函数--深入浅出了解_第12张图片
eg5:

void Test12()
{
	string str1("hello world");
	string::iterator it = str1.begin();
	while (it != str1.end())
	{
		cout << (*it);
		it++;
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第13张图片
汇编代码:
string类函数--深入浅出了解_第14张图片
eg6:

void Test13()
{
	string str1("hello world");
	for (auto& ch:str1)
	{
		cout << ch;
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第15张图片
汇编代码:
string类函数--深入浅出了解_第16张图片

①迭代器是像指针一样的类型,可能是指针;②iterator(迭代器)提供一种统一的方式访问和修改容器的数据,使算法可以通过迭代器去处理容器中的数据;③范围for的底层是通过迭代器实现的。

eg7:

void Test14()
{
	//string类使用迭代器
	string str1("hello world");
	cout << "string类使用迭代器遍历的结果:" << endl;
	string::iterator it = str1.begin();
	while (it != str1.end())
	{
		cout << *it;
		it++;
	}
	cout << endl;
	vector<int> v;
	v.push_back(10);
	v.push_back(20);
	v.push_back(30);
	v.push_back(40);
	v.push_back(50);
	cout << "vector使用迭代器遍历的结果:" << endl;
	vector<int>::iterator vit = v.begin();
	while (vit != v.end())
	{
		cout << *vit << " ";
		++vit;
	}
	cout << endl;

	list<int> lt;
	lt.push_back(10);
	lt.push_back(20);
	lt.push_back(30);
	lt.push_back(40);
	lt.push_back(50);
	cout << "list使用迭代器遍历的结果:" << endl;
	list<int>::iterator lit = lt.begin();
	while (lit != lt.end())
	{
		cout << *lit << " ";
		++lit;
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第17张图片

①任何容器都支持迭代器,并且用法类似;②迭代器跟算法进行配合。

函数名称:

reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
//string类逆置字符串的第一个字符的迭代器(即指向string类从右向左的第一个字符)
reverse_iterator rend();
const_reverse_iterator rend() const;
//string类逆置字符串的最后一个字符下一个位置的迭代器(即指向string类从右向左的最后一个字符的下一个位置)

图形理解
eg8:

void Test15()
{
	string str1("hello world");
	string::reverse_iterator it = str1.rbegin();
	while (it != str1.rend())
	{
		cout << *it;
		it++;
	}
	cout << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第18张图片

①使用反向迭代器,从string类后面向前遍历;②范围for不支持反向迭代器。

3.4string类的修改操作

函数名称:

void push_back (char c);//在字符串后尾插字符c
string (1)	
string& operator+= (const string& str);
//在字符串后追加类对象str
c-string (2)	
string& operator+= (const char* s);
//在字符串后追加一个字符串s
character (3)	
string& operator+= (char c);
//在字符串后追加一个字符c

eg1:

void Test16()
{
	string str1("hello world");
	str1.push_back('x');
	printf("使用push_back追加一个字符后:\n");
	cout << str1 << endl;
	string str2("yyyyy");
	str1 += str2;
	printf("使用operator+=追加str类对象:\n");
	cout << str1 << endl;
	str1 += "abcdef";
	printf("使用operator+=追加字符串:\n");
	cout << str1 << endl;
	str1 += 'u';
	printf("使用operator+=追加一个字符:\n");
	cout << str1 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第19张图片
函数名称:

string (1)	
string& append (const string& str);
//string类对象追加string类对象的字符串
substring (2)	
string& append (const string& str, size_t subpos, size_t sublen);
//string类对象追加string类subpos位置sublen长度的字符串
c-string (3)	
string& append (const char* s);
//string类对象追加一个常量字符串
buffer (4)	
string& append (const char* s, size_t n);
//string类对象追加常量字符串的前n个字符
fill (5)	
string& append (size_t n, char c);
//string类对象追加n个字符
range (6)	
template <class InputIterator>
   string& append (InputIterator first, InputIterator last);
//string类对象追加一个string类[first,last)区间的字符串

eg2:

void Test17()
{
	string str1("hello world");
	string str2(" fighting");
	str1.append(str2);
	cout << str1 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第20张图片
注意:

  1. string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。

函数名称:

size_t find (const string& str, size_t pos = 0) const;
size_t find (const char* s, size_t pos = 0) const;
//从stringpos位置往后查找str对象(字符串),并返回第一次出现的位置

eg3:

void Test18()
{
	string str1("hello world");
	size_t ret=str1.find("world");
	cout << ret << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第21张图片
函数名称:

size_t rfind (const string& str, size_t pos = npos) const;
size_t rfind (const char* s, size_t pos = npos) const;
//从stringpos位置往前查找str对象(字符串),并返回第一次出现的位置
//返回的下标是string类的正向下标(从前往后数),而不是逆向的下标(从后往前数)

eg4:

void Test19()
{
	string str1("hello world");
	size_t ret = str1.rfind("world");
	cout << ret << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第22张图片
函数名称:

string substr (size_t pos = 0, size_t len = npos) const;
//返回string类从pos位置len长度的字符串构造的对象

eg5:

void Test20()
{
	string str1("hello world");
	string str2 = str1.substr(6);
	cout << str2 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第23张图片
函数名称:

const char* c_str() const;
//返回指向string类C语言字符串

eg6:

void Test21()
{
	string str1("hello world");
	cout << str1.c_str() << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第24张图片

3.5string类的非成员函数

函数名称:

string operator+ (const string& lhs, const string& rhs);
string operator+ (const string& lhs, const char*   rhs);
//string类+运算符重载,使用传值返回,深拷贝效率低

eg1:

void Test22()
{
	string str1("hello world");
	string str2(" fighting");
	string str3 = str1 + str2;
	cout << str3 << endl;
	str3 = str1 + " abc";
	cout << str3 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第25张图片
函数名称:

istream& operator>> (istream& is, string& str);//string类输入运算符重载,遇到空格、'\n',停止读取
ostream& operator<< (ostream& os, const string& str);//string类输出运算符重载

eg2:

void Test23()
{
	string str1;
	cin >> str1;//使用operator>>运算符重载读取(遇到空格、'\n'停止读取)
	cout << str1 << endl;//使用operator<<运算符重载写入
}

代码编译运行的结果为:
string类函数--深入浅出了解_第26张图片
函数名称:

istream& getline (istream& is, string& str, char delim);
istream& getline (istream& is, string& str);
//获取一行字符串给string类对象,可以指定delim终止符,不指定则默认以'\n'为终止符

eg3:

void Test24()
{
	string str1;
	getline(cin, str1);
	cout << str1 << endl;
}

代码编译运行的结果为:
string类函数--深入浅出了解_第27张图片

总结

本章节我们一起学习了string类常用接口函数,希望对大家了解string类有些许帮助,感谢大家阅读,若有不对欢迎纠正!

你可能感兴趣的:(C++初阶学习,c++,学习,开发语言)