(C++) string认识与应用 构造 迭代器 遍历与访问 内部函数

本文详细介绍了C++中的string类,包括其构造函数、拷贝构造、赋值重载,以及遍历方式(下标、迭代器和范围for),并重点讲解了size(),capacity(),push(),append(),reserve(),resize(),find(),insert(),erase()等内部函数的用法。
摘要由CSDN通过智能技术生成

# 0 string

要使用string,要包含头文件。

#include <string>

string其实就是用来管理字符串的顺序表。
string的产生在数据库之前,并不划分到容器中,规范上来说和其他的容器也有一定差别,最主要的是冗余的代码太多。
由于其内部函数的重载太多,且部分功能重叠,下面都只是捡最常见常用的部分来写。

# 1 string的默认成员函数

文章只涉及构造,拷贝构造与赋值重载。

剩下三个都很简单,没什么好提的。

# 1.1 string的构造函数

string内部的构造函数有许多重载:
第二个显然就是拷贝构造。
在这里插入图片描述
最常用的是第一种,无参调用:

// 直接构造一个string类型的对象
	string s1;

和第四种,用一个字符串来初始化构造:

// 这里s2和s3的两种写法本质上是一样的
// 二者都是构造
// 前者是构造很明显
// 后者是先用字符串构造一个临时的string,然后拷贝给s3
// 连续的构造+拷贝构造被优化成单构造
	string s2 ("abcde");
	string s3 = "abcde";

其它的都太少用了,所以不提了。
要求记得所有的接口是很不现实的,需要用的时候搜搜就好。

# 1.2 string的拷贝构造

就是上面那张图的第二个构造函数。
毕竟拷贝构造就是构造函数的一种重载嘛。

// 下面两种写法同样是一致的
// 都是单拷贝构造
	string s4 = s3;
	string s5(s4);

# 1.3 string的赋值重载

赋值重载也有多个重载:
在这里插入图片描述

	// 对于两个已经存在的对象的拷贝,才是赋值重载
	// 分别是用另一个string赋值
	s1 = s5;
	cout << s1 << endl;
	
	// 用字符串赋值
	s1 = "12345";
	cout << s1 << endl;

	// 用一个字符赋值
	s1 = 'k';
	cout << s1 << endl;

string中重载了流插入和流提取,所以可以直接用。
在这里插入图片描述

# 2 string的遍历与访问

大体上可以看作三种方法,
分别是熟悉的用下标和[ ]的组合;
迭代器;
以及范围for。

# 2.1 下标和[ ]

string内部实现了对[ ]的重载,允许了和以前访问顺序表一致的方式来遍历string。

void Test2()
{
	string s1 = "abcdef";
	cout << s1 << endl;

	// 允许访问与修改
	s1[0]++;
	cout << s1 << endl;

	cout << s1[2] << endl;
}

在这里插入图片描述

# 2.2 迭代器

关于迭代器的具体细节和实现方式,不同结构的迭代器各有不同。
对于string这样底层空间连续的结构来说,迭代器就是简单的指针。

void Test3()
{
	string s1 = "123456";
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << endl;
		++it;
	}
}

# 2.3 范围for

范围for底层是用迭代器实现的,本质上是迭代器的简单替换
即虽然写法是范围for,但是编译器会直接将其替换为迭代器。

void Test3()
{
	string s1 = "123456";
	// 这是迭代器
	//string::iterator it = s1.begin();
	//while (it != s1.end())
	//{
	//	cout << *it;
	//	++it;
	//}
	//cout << endl;

	// 这是范围for
	for (auto e : s1)
	{
		cout << e;
	}
	cout << endl;
}

从编译器的角度来看,这两段代码完全一样。

# 3 string内部函数

首先,string的成员函数种类繁杂,每个函数都可能有不止一个的重载,
再有,部分重载乃至函数本身可能并没有实现的必要。
一一细说既效率低下,也没实际价值。
下面只介绍最常用的函数和部分重载。

# 3.1 size(),length(),capacity()

size()和length()的功能是一样的,无需参数,返回对象中数据的有效长度。
所谓有效长度,即不计算‘\0’。

capacity()同样无参,返回的是有效数据的最大长度。
这个容量指的并不是开出来的空间大小,会小上一个字节,
因为实际空间最后一个字节一定是‘\0’,这个字节不能算进有效数据。

void Test4()
{
	string s1 = "qwerty";
	cout << s1 << endl;

	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << s1.capacity() << endl;
}

在这里插入图片描述

# 3.2 push(),append(),+=重载

pus()只允许一个一个字符插入,想要插入字符串就要用append()。
+=重载是会根据参数是字符还是字符串,调用push()或是append()。

所以不用分辨字符和字符串,一律用+=是最简单的。

void Test5()
{
	string s1 = "123456";
	cout << s1 << endl;

	s1.push_back('7');
	s1.push_back('8');
	s1.push_back('9');
	cout << s1 << endl;

	s1.append("0123");
	cout << s1 << endl;

	cout << endl;

	string s2 = "123456";
	cout << s2 << endl;

	s2 += '7';
	s2 += '8';
	s2 += '9';
	cout << s2 << endl;

	s2 += "0123";
	cout << s2 << endl;
}

在这里插入图片描述

# 3.3 reserve(),resize()

reserve()只改变capacity,不会对size和数据有任何改动。
resize()不仅可能改变capacity,还会改变size,以至于改变数据。

void Test6()
{
	string s1 = "123456";
	cout << s1.size() << ' ' << s1.capacity() << endl;
	cout << s1 << endl << endl;

// 目标容量小于原容量
// 什么都不做
	s1.reserve(10);
	cout << s1.size() << ' ' << s1.capacity() << endl;
	cout << s1 << endl << endl;

// 目标容量大于原容量
// 进行扩容
	s1.reserve(20);
	cout << s1.size() << ' ' << s1.capacity() << endl;
	cout << s1 << endl << endl;

	cout << endl;

	string s2 = "123456";
	cout << s2.size() << ' ' << s2.capacity() << endl;
	cout << s2 << endl << endl;

// 目标size大于原size,小于容量
// 不扩容,用第二个参数将size填充至目标size
// 如果没有给第二个参数,有缺省值为'\0'
	s2.resize(10, '7');
	cout << s2.size() << ' ' << s2.capacity() << endl;
	cout << s2 << endl << endl;

// 目标size大于容量
// 扩容,并填充
	s2.resize(20,'8');
	cout << s2.size() << ' ' << s2.capacity() << endl;
	cout << s2 << endl << endl;

// 目标size小于原size
// 容量不变,删除数据至只剩下前目标size个
	s2.resize(3);
	cout << s2.size() << ' ' << s2.capacity() << endl;
	cout << s2 << endl << endl;
}

在这里插入图片描述

# 3.4 find(),insert(),erase()

分别是查找,插入和删除。
find有两个参数,第一个是要寻找的字符或字符串,第二个是开始寻找的位置下标。
第二个参数有缺省值,为0,即从其实位置开始找。

插入也是两参数,第一个是目标插入位置下标,第二个是要插入的字符串。
插入数据过程中如果需要扩容,insert函数里面会自己调,不用操心。

删除两参数,第一个是目标删除位置下标。第二个是要删除的数据个数,或者说字节数。
第二个参数也有缺省值,为npos,就是从目标位置开始往后全删。

void Test7()
{
	string s1 = "abcdefg";

// 找到了返回下标
	cout << s1.find('a', 0) << endl;

// 找不到返回npos
	cout << s1.find('a', 1) << endl;
	
	cout<<endl;

// 从0位置插入,就是头插
	s1.insert(0, "123");
	cout << s1 << endl;

// 从size()位置插入,就是尾插
	s1.insert(s1.size(), "456");
	cout << s1 << endl;

// 从0位置,即从头删除两个字符
	s1.erase(0, 2);
	cout << s1 << endl;

// 从下标为3的位置删除1111个字符
// 这个数字过大,所以其实就是只保留前三个字符,后面全删
	s1.erase(3, 1111);
	cout << s1 << endl;
}

在这里插入图片描述

  • 28
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值