从陌生到熟练使用string类

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨

🐻推荐专栏1: 🍔🍟🌯C语言初阶

🐻推荐专栏2: 🍔🍟🌯C语言进阶

🔑个人信条: 🌵知行合一

🍉本篇简介:>:讲解C++中有关string类的使用,从构造函数到容量操作,到遍历以及增删查改和最后的运算符重载.

目录

一、构造函数

string库的学习:传送门

在库中我们可以看到,string类的构造函数是很丰富的.

重点掌握牛牛框起来的四个哦,其他的忘记了咱可以查文档.

构造函数使用演示:

cpp 复制代码
void test1()
{
	//无参构造	string();
	string s1; 
	cout << "s1=  " << s1 << endl;
	
	//拷贝构造,	string (const string& str);
	s1 += "HELLO CSDN!!!";//下面讲,这里是为了s1里面有数据,方便拷贝构造
	string s2(s1);
	cout << "s2=  " << s2 << endl;

	//用另一个string类的字串初始化	string (const string& str, size_t pos, size_t len = npos);
	string s3(s1, 6,4);
	cout << "s3=  " << s3 << endl;

	//使用字符串进行初始化	string (const char* s);
	string s4("CJN Rush Rush Rush");
	cout << "s4=  " << s4 << endl;

	//string(const char* s, size_t n);
	string s5("CJN Rush Rush Rush",7);//不常用
	cout << "s5=  " << s5 << endl;

	//string(size_t n, char c);
	string s6(5, 'X');//不常用
	cout << "s6=  " << s6 << endl;	
}

运行结果:

s1=

s2= HELLO CSDN!!!

s3= CSDN

s4= CJN Rush Rush Rush

s5= CJN Rus

s6= XXXXX

二、容量(capacity)相关的操作

我们看一下库中对capacity(容量)的相关操作有哪些.

(1)size()和length()

其实size()length()并没有本质区别.

都是用于返回string中字符串的有效字符长度.

但是,由于string实现的比较早,当时设计的是length(),后来STL出来以后,为了统一,增加了size()接口.

cpp 复制代码
	string s1;
	string s2("hello");
	//size和length并没有什么区别.
	cout << s1.size() << "  " << s1.length() << endl;
	cout << s2.size() << "  " << s2.length() << endl;

0 0

5 5

(2)resize()与reserve()

resize()用于改变字符串的有效字符长度.不够的地方用第二个参数填充.

cpp 复制代码
	string s3("HELLO CSDN!!!");
	s3.resize(5);		//将字符串的有效字符长度改为5
	cout << s3 << endl;
	string s4("HELLO CSDN!!!");
	s4.resize(25,'x');	//将字符串的有效字符长度改为25,不够的地方用字符'x'填充
	cout << s4 << endl;

运行结果:

HELLO

HELLO CSDN!!!xxxxxxxxxxxx

resize()的改变会影响capacity(容量)吗?

cpp 复制代码
	string s5("HELLO CSDN!!!");
	cout << "s5.capacity=" << s5.capacity() << endl;
	s5.resize(25, 'x');
	cout << "s5.capacity=" << s5.capacity() << endl;
	s5.resize(5, 'x');
	cout << "s5.capacity=" << s5.capacity() << endl;//并没有缩容

运行结果:

s5.capacity=15

s5.capacity=31

s5.capacity=31

当然,如果容量太小,不足以存储有效字符,必然是会扩容的!

扩容选择:(扩容方式是未定义的)

扩容是按有效字符长度扩容.

按之前容量的1.5倍扩容,更或者是2倍扩容.

reserve():请求改变容量的大小.

cpp 复制代码
	string s6("HELLO CSDN!!!");
	cout << "s6.capacity=" << s6.capacity() << endl;
	s6.reserve(50);
	cout << "s6.capacity=" << s6.capacity() << endl;
	s6.reserve(30);
	cout << "s6.capacity=" << s6.capacity() << endl;//并没有缩容

	//一般都是不缩容的,缩容行为是未定义的.
	s6.clear();
	s6.reserve(0);
	cout << "s6.capacity=" << s6.capacity() << endl;//这里缩容了

s6.capacity=15

s6.capacity=63

s6.capacity=63

s6.capacity=15

是否缩容是未定义行为,取决于编译器,这里如果不清楚数据,直接将reserve(0),依旧不会缩容.

(3)clear()和empty()

cpp 复制代码
	string s7;
	cout << s7.empty() << endl;
	s7 += "HELLO";
	cout << s7.empty() << endl;
	cout << "s7.size=" << s7.size() << endl;
	cout << "s7.capacity" << s7.capacity() << endl;
	s7.clear();
	cout << "s7.size=" << s7.size() << endl;
	cout << "s7.capacity" << s7.capacity() << endl;

运行结果:

1

0

s7.size=5

s7.capacity15

s7.size=0

s7.capacity15

显然clear只是清除有效字符,将字符清零,并不会影响capacity容量.

(4)小结:

  1. size()length()底层实现原理是一样的,都是返回有效的字符个数.只是为了STL的接口相统一.

  2. resize(size_t n)resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。
    注意:resize在改变元素个数时.

    (1)如果是将元素个数增多,可能会改变底层容量的大小,不然存储不了那么多有效字符.

    (2)如果是将元素个数减少,底层空间总大小不变。

  3. reserve((size_t res_arg=0))函数是请求改变string的容量.

    (1)当res_arg大于当前的容量的时候,会进行扩容.

    (1)当res_arg小于当前的容量的时候,一般不会缩容.

  4. clear只是清除有效字符,将字符清零,并不会影响capacity容量.

三、访问与遍历

正向迭代器与反向迭代器:(这里对C++11的用法暂时不介绍)

下标访问符 方括号[ ]重载

示例:

cpp 复制代码
void test3()
{
	string s1("This is a little boy");
	string::iterator it = s1.begin();	//s1.begin()会返回有效字符串中第个元素的位置
	while (it != s1.end())				//s1.end()会返回有效字符串最后一个元素的位置的后一个位置
	{
		cout << *it ;
		it++;
	}
	cout << endl;

	string::reverse_iterator rit = s1.rbegin();//反向迭代器
	while (rit != s1.rend())				//s1.end()会返回有效字符串最后一个元素的位置的后一个位置
	{
		cout << *rit;
		rit++;
	}
	cout << endl;

	cout << "s1.begin=" << *(s1.begin()) << endl;
	cout << "s1.end=" << *(s1.end()-1) << endl;		//不可直接访问s1.end(),因为不是有效字符,而是最后一个有效字符的下一个位置.
	cout << "s1.rbegin=" << *(s1.rbegin()) << endl;
	cout << "s1.rend=" << *(s1.rend()-1) << endl;	//这里为什么是+1而不是-1,留在后面的专门反向迭代器讲解

	//可以像数组一样用下标直接访问
	cout << s1[0] << endl;
	cout << s1[3] << endl;
	cout << s1[8] << endl;
}

四、增删改查

(1)追加字符/字符串(append)

cpp 复制代码
void test4()
{
	string s1("hello C");
	cout << "s1=" << s1 << endl;
	//尾插一个字符
	s1.push_back('S');
	s1.push_back('D');
	s1.push_back('N');
	cout << "s1=" << s1 << endl;
	cout << "----------------------------------" << endl;

	string s2("hello C");
	cout << "s2=" << s2 << endl;
	s2.append("SDN");		//追加字符串
	cout << "s2=" << s2 << endl;
	cout << "----------------------------------" << endl;

	string s3("hello C");
	cout << "s3=" << s3 << endl;
	s3 += "SDN";						//最喜欢使用这个,易读也简单
	cout << "s3=" << s3 << endl;
}

个人感想:
push_back一次插入一个字符太麻烦了,append虽然可以追加字符串,但是终究是没有+=来的香.

其它的以assign为例,一般用不到(因为实现的有些冗余,可以用别的函数代替),实在要用查库即可:

cpp 复制代码
void test5()
{
	string str("This is a little boy");
	string s1,s2,s3;
	s1.assign(str);
	s2.assign(str, 8, string::npos);
	s3.assign(5, 'c');
	cout << "s1=" << s1 << endl;
	cout << "s2=" << s2 << endl;
	cout << "s3=" << s3 << endl;
}

运行结果:

s1=This is a little boy

s2=a little boy

s3=ccccc

(2)查找(find)/切割(substr)

c_str:为了与C语言兼容,返回C形式的常量字符串.
find:可以查找目标字符/字符串.
string substr (size_t pos = 0, size_t len = npos) const:从pos往后len个字符,返回这段被切割的字符串的副本.

cpp 复制代码
void test6()
{
	string s1("This is a little boy");
	const char* arr = s1.c_str();		//返回C形式的常量字符串
	cout << "arr=" << arr << endl;

	string s2("This is a little boy");

	cout << s2.find('i') << endl;		//查找目标字符
	cout << s2.find("little") << endl;	//查找目标字符串

	string s3("321xxxxxxx@qq.com");
	int pos1 = s3.find('@');
	int pos2 = s3.find(".com");
	string s4, s5, s6;
	s4 = s3.substr(0, pos1-1);			//从0位置开始,往后pos-1个字符
	s5 = s3.substr(pos1, s3.size() - pos2 - 1);
	s6 = s3.substr(pos2);				//第二个参数为往后的字符个数,不写,默认为npos

	cout << "s4= " << s4 << endl;
	cout << "s5= " << s5 << endl;
	cout << "s6= " << s6 << endl;
}

运行结果:

arr=This is a little boy

2

10

s4= 321xxxxxx

s5= @qq

s6= .com

五、运算符重载

小知识点:

npos是-1,只不过类型是const size_t,所以是整数的最大值,通常表示字符串的结尾或无效位置。npos定义在std命名空间中,通常用于字符串的查找操作。

+运算符重载与getline()

cpp 复制代码
void test7()
{
	string s1("HELLO ");
	string s2("CSDN");
	string s3;
	s3 = s1 + s2;		//因为是传值返回,所以效率不高,建议少用
	cout << s3 << endl;

	string name;
	cout << "Please, enter your full name: ";
	getline(cin, name);
	cout << "Hello, " << name << "!\n";

}

比较运算符这里就不一 一介绍了,字符串按ASCII码值进行比较.

string类的使用还是需要多多练习,可以试着写一下相关的oj题练一下手,后续会模拟实现string类,加深对string类的理解.

string相关习题1

今天就讲到这里了,我们下次模拟实现见.

相关推荐
励志要当大牛的小白菜1 小时前
ART配对软件使用
开发语言·c++·qt·算法
qq_513970441 小时前
力扣 hot100 Day56
算法·leetcode
PAK向日葵2 小时前
【算法导论】如何攻克一道Hard难度的LeetCode题?以「寻找两个正序数组的中位数」为例
c++·算法·面试
爱装代码的小瓶子4 小时前
数据结构之队列(C语言)
c语言·开发语言·数据结构
爱喝矿泉水的猛男4 小时前
非定长滑动窗口(持续更新)
算法·leetcode·职场和发展
YuTaoShao4 小时前
【LeetCode 热题 100】131. 分割回文串——回溯
java·算法·leetcode·深度优先
勇哥的编程江湖5 小时前
starrocks官网docker部署mysql无法连接
运维·docker·容器
YouQian7725 小时前
Traffic Lights set的使用
算法
快乐飒男5 小时前
哈希表(c语言)
c语言·哈希算法·散列表
go54631584656 小时前
基于深度学习的食管癌右喉返神经旁淋巴结预测系统研究
图像处理·人工智能·深度学习·神经网络·算法