从陌生到熟练使用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

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

相关推荐
昌sit!27 分钟前
K8S node节点没有相应的pod镜像运行故障处理办法
云原生·容器·kubernetes
捕鲸叉28 分钟前
创建线程时传递参数给线程
开发语言·c++·算法
A charmer32 分钟前
【C++】vector 类深度解析:探索动态数组的奥秘
开发语言·c++·算法
Peter_chq34 分钟前
【操作系统】基于环形队列的生产消费模型
linux·c语言·开发语言·c++·后端
wheeldown1 小时前
【数据结构】选择排序
数据结构·算法·排序算法
hikktn2 小时前
如何在 Rust 中实现内存安全:与 C/C++ 的对比分析
c语言·安全·rust
青花瓷2 小时前
C++__XCode工程中Debug版本库向Release版本库的切换
c++·xcode
观音山保我别报错2 小时前
C语言扫雷小游戏
c语言·开发语言·算法
A ?Charis3 小时前
Gitlab-runner running on Kubernetes - hostAliases
容器·kubernetes·gitlab
幺零九零零3 小时前
【C++】socket套接字编程
linux·服务器·网络·c++