【C++】学习笔记——string_2

文章目录


结合文档食用~

六、string类

2. 反向迭代器

一般来说,迭代器都是正向的遍历容器,虽然可以通过从 end ** 遍历到 begin 的方法来反向遍历容器,但是有这样一种迭代器,叫做反向迭代器**,可以做到反向遍历容器。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test1()
{
	string s1("hello,world");
	// 反向迭代器 -- reverse_iterator
	string::reverse_iterator rit = s1.rbegin();
	while (rit != s1.rend())
	{
		cout << *rit << ' ';
		++rit;
	}
	cout << endl;
}

int main()
{
	test1();
	return 0;
}


反向迭代器就是反方向跑,每次+1其实都是往左跑。

const迭代器

当构造时使用 const 修饰,普通的迭代器就不能够使用了。

cpp 复制代码
void test2()
{
	const string s1("hello,world");
	// 这里会出现报错
	string::iterator it = s1.begin();
	while (it != s1.end())
	{
		cout << *it << ' ';
		++it;
	}
	cout << endl;
}

此时由于类型不匹配,我们需要调整迭代器。

使用 const_iterator 就可以了。那么普通迭代器和 const迭代器 有什么区别呢?其实知道const就知道了,普通迭代器对容器是可读可写的,const迭代器就只可读。

string类对象的容量操作(补)

size()

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test3()
{
	string s1("hello,world");
	cout << s1 << endl;
	cout << s1.size() << endl;
	cout << s1.length() << endl;
	cout << s1.capacity() << endl;
	cout << s1.max_size() << endl;
}

int main()
{
	test3();
	return 0;
}

size() 函数返回string类中的元素个数。
length() 函数和 size() 函数作用一样,返回元素个数。
capacity() 函数返回容器的当前容量,即分配的空间,size() 是使用的空间。
max_size() 函数不常用,返回这个容器能够存储的最大长度,跟编译器有关,输出结果不唯一。

既然知道了 capacity ,我们来看一看VS环境下的C++扩容机制吧。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test4()
{
	string s;
	// 初始容量
	int sz = s.capacity();
	cout << sz << endl;
	// 循环插入数据
	for (int i = 0; i < 100; ++i)
	{
		s.push_back('a');
		// 容量有变化时
		if (sz != s.capacity())
		{
			sz = s.capacity();
			// 输出新的容量
			cout << "capacity changed:" << sz << endl;
		}
	}
}

int main()
{
	test4();
	return 0;
}

也不需要让大家找什么规律,我直接说了:①capacity 求的是不包含字符串末尾的 '\0' 的空间,初始实际上是分配了 16 的空间大小,可用空间只有 15 个数据长度。②第一次扩容是 2倍扩容 。③剩下的扩容都是 1.5倍扩容。在其他环境下不一定是这种扩容机制哦。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test5()
{
	string s("hello,world!!!!!!!!!!!!!!!!!!!!!!");

	cout << s << endl;
	cout << s.capacity() << endl;
	cout << s.empty() << endl;
	s.clear();
	cout << s << endl;
	cout << s.empty() << endl;
	cout << s.capacity() << endl;

}

int main()
{
	test5();
	return 0;
}

empty() 函数翻译过来就知道功能就是判断容器是否为空,为空返回true,非空返回false
clear() 函数就是清理的意思,它会将容易里的数据都清除。但是,我们发现,capacity() 并没有相应的减少,说明 clear 只清理了数据,并没有释放空间。那我们想要释放空间该怎么办?

string 提供了这样一个函数,作用是将 capacity 缩小到 size 大小。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test5()
{
	string s("hello,world!!!!!!!!!!!!!!!!!!!!!!");

	cout << s << endl;
	cout << s.capacity() << endl;
	cout << s.empty() << endl;
	s.clear();
	cout << s << endl;
	cout << s.empty() << endl;
	cout << s.capacity() << endl;
	// 缩容操作
	s.shrink_to_fit();
	cout << s.capacity() << endl;
}

int main()
{
	test5();
	return 0;
}

实际上它并不能把空间全部释放掉,最小缩容到 16 (有一个'\0')。

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test6()
{
	string s("hello,worlddddddddddddddddd");
	cout << s.size() << endl;
	cout << s.capacity() << endl;
	s.reserve(100);
	cout << s.capacity() << endl;
}

int main()
{
	test6();
	return 0;
}


reserve() 函数的作用就是手动分配空间,但是不一定刚刚好分派到你想要的大小。那么,reserve 可以缩容吗?上面情况是想要分配的空间比原来的 capacity 大,假如想要分配的空间比 size 大,比 capacity 小会怎样?比 size 小会怎样?

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test6()
{
	string s1("hello,worlddddddddddddddddd");
	cout << s1.size() << endl;
	cout << s1.capacity() << endl;
	s1.reserve(100);
	cout << s1.capacity() << endl << endl;

	string s2("hello,worlddddddddddddddddd");
	s2.reserve(100);
	cout << s2.size() << endl;
	cout << s2.capacity() << endl;
	s2.reserve(50);
	cout << s2.capacity() << endl << endl;

	string s3("hello,worlddddddddddddddddd");
	s3.reserve(100);
	cout << s3.size() << endl;
	cout << s3.capacity() << endl;
	s3.reserve(10);
	cout << s3.capacity() << endl << endl;
}

int main()
{
	test6();
	return 0;
}

所以我们知道,reserve 只有比 capacity 大时才扩容。
reserve 是改变容量,resize() 就是改变数据个数。

由上图可知:①给 resize 的值比 size 小时,resize 会将多余的给删除,不会修改 capacity 的值。②当给 resize 的值比 size 大,比 capacity 小时,字符串后面会默认插入 '\0',或者给定的值。③当给 resize 的值比 capacity 大时,字符串会扩容至 resize,然后赋值 '\0' 或给定值。

3. string类的元素访问

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test8()
{
	string s("hello,world");
	// [] 访问
	cout << s[6] << endl;
	// at 访问
	cout << s.at(6) << endl;
	// 直接取头部数据
	cout << s.front() << endl;
	// 直接取尾部数据
	cout << s.back() << endl;
}

int main()
{
	test8();
	return 0;
}

其中 []at 访问几乎没区别,只是对越界的检查方式不同。

4. string类的修改

cpp 复制代码
#include<iostream>
#include<string>
using namespace std;

void test9()
{
	string s("123456789");
	cout << s << endl;
	// 字符串末尾追加
	s += '0';
	cout << s << endl;
	// 末尾追加
	s.append("987");
	cout << s << endl;
	// 尾插一个字符
	s.push_back('6');
	cout << s << endl;
	// 完全覆盖
	s.assign("13345889");
	cout << s << endl;
	// 从下标1开始插入
	s.insert(1, "23");
	cout << s << endl;
	// 从下标3开始删除两个字符
	s.erase(3, 2);
	cout << s << endl;
	// 从下标5开始,将1个字符给替换成
	s.replace(5, 1, "67");
	cout << s << endl;;
}

int main()
{
	test9();
	return 0;
}

insert / erase / replace 需要挪动数据,复杂度大,能不用就不用。这里函数太多,就不一一介绍了,多看看文档就会用了。


未完待续

相关推荐
捕鲸叉2 小时前
怎样在软件设计中选择使用GOF设计模式
c++·设计模式
捕鲸叉2 小时前
C++设计模式和编程框架两种设计元素的比较与相互关系
开发语言·c++·设计模式
Back~~2 小时前
MFC1(note)
学习
未知陨落3 小时前
数据结构——二叉搜索树
开发语言·数据结构·c++·二叉搜索树
engchina3 小时前
Oracle ADB 导入 BANK_GRAPH 的学习数据
数据库·学习·oracle·graph
一丝晨光3 小时前
gcc 1.c和g++ 1.c编译阶段有什么区别?如何知道g++编译默认会定义_GNU_SOURCE?
c语言·开发语言·c++·gnu·clang·gcc·g++
Komorebi.py4 小时前
【Linux】-学习笔记03
linux·笔记·学习
汉克老师4 小时前
GESP4级考试语法知识(贪心算法(四))
开发语言·c++·算法·贪心算法·图论·1024程序员节
程序员劝退师_4 小时前
Kafka学习笔记
笔记·学习·kafka
帅比九日4 小时前
【HarmonyOS NEXT】实战——登录页面
前端·学习·华为·harmonyos