【STL】String的底层构造

news2024/11/14 22:04:38

1.String类对象的构造(后面有每一个接口的实现)

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin();
		iterator end();

		const_iterator begin() const;
		const_iterator end() const;

		//string();
		string(const char* str = "");
		string(const string& s);
		string& operator=(const string& s);
		~string();

		const char* c_str() const;

		size_t size() const;
		char& operator[](size_t pos);
		const char& operator[](size_t pos) const;

		void reserve(size_t n);

		void push_back(char ch);
		void append(const char* str);

		string& operator+=(char ch);
		string& operator+=(const char* str);

		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos = 0, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);

		void swap(string& s);
		string substr(size_t pos = 0, size_t len = npos);

		bool operator<(const string& s) const;
		bool operator>(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>=(const string& s) const;
		bool operator==(const string& s) const;
		bool operator!=(const string& s) const;
		void clear();
	private:
		// char _buff[16];
		char* _str;

		size_t _size;
		size_t _capacity;

		//  
		//const static size_t npos = -1;

		// ֧
		//const static double N = 2.2;

		const static size_t npos;
	};

	istream& operator>> (istream& is, string& str);
	ostream& operator<< (ostream& os, const string& str);
}

2.String类常见的构造方式

void test_string1()
{
	// 常用
	string s1;
	string s2("hello world");
	string s3(s2);

	// 不常用 了解
	string s4(s2, 3, 5);
	string s5(s2, 3);
	string s6(s2, 3, 30);
	string s7("hello world", 5);
	string s8(10, 'x');

	cout << s1 << endl;
	cout << s2 << endl;
	cout << s3 << endl;
	cout << s4 << endl;
	cout << s5 << endl;
	cout << s6 << endl;
	cout << s7 << endl;
	cout << s8 << endl;

	cin >> s1;
	cout << s1 << endl;
}

3.String的隐式类型转换与构造

void test_string2()
{
	string s1("hello world"); //构造
	string s2 = "hello world"; //隐式类型转换
	const string& s3 = "hello world";// 临时对象具有常性,加const
 }

4.String类的基本操作函数

void test_string3()
{
  string s1("hello world");
  cout << s1.size() << endl;
//capacity 比 实际空间少一个,有一个多的是预留给\0
  cout << s1.capacity() << endl;
  cout << s1.max_size() << endl;
}

5.String的三种遍历方式

        5.1  :使用[]来完成遍历

        

string s1 = "hello world";
	for (int i = 0; s1[i]; i++)
	{
		cout << s1[i] << " ";
	}
	cout << endl;

        5.2 : 使用迭代器完成遍历

        

string::iterator it1 = s1.begin();
	while (it1 != s1.end()) { 
		cout << *it1 << " ";
		++it1;
	}
	cout << endl;
 
	cout << typeid(it1).name() << endl

        5.3 :使用auto 来完成遍历

//遍历方式3:范围for
	// 底层:就是迭代器
	for (auto e : s1) {
		cout << e << " ";
	}

6.String的逆置 - reverse

void test_string5() //反向迭代器
{
	string s1("hello world");
	string::const_iterator it1 = s1.begin();
	//auto it1 = s1.begin();
	while (it1 != s1.end())
	{
		//*it1 += 3;// 不能修改
		cout << *it1 << " ";
		++it1;
	}
	string s2("hello world");
 
	string::reverse_iterator it2 = s2.rbegin();
	while (it2 != s2.rend()) {
		*it2 += 3;
		cout << *it2 << " ";
		++it2;
	}
}

7.String的sort 排序

void test_string6()
{
	string s1("hello world");
	cout << s1 <<endl;
 
	//按字典序排序
	sort(s1.begin(), s1.end());
	
	//第一个和最后一个参与排序
	sort(++s1.begin(), --s1.end());
 
	//前五个排序
	sort(s1.begin(), s1.begin() + 5);
	cout << s1 << endl;
}

8.string 的插入删除

void push_back(char ch);
void append(const char* str);
void insert(size_t pos, char ch);
void insert(size_t pos, const char* str);
void string::insert(size_t pos, char ch)
{
	assert(pos <= _size);

	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newcapacity);
	}

	/*int end = _size;
	while (end >= (int)pos)
	{
		_str[end + 1] = _str[end];
		--end;
	}*/

	size_t end = _size + 1;
	while (end > pos)
	{
		_str[end] = _str[end - 1];
		--end;
	}

	_str[pos] = ch;
	++_size;
}

8.2:在pos位置插入字符串

        

void string::insert(size_t pos, const char* str)
{
	assert(pos <= _size);

	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}

	/*int end = _size;
	while (end >= (int)pos)
	{
		_str[end + len] = _str[end];
		--end;
	}*/

	size_t end = _size + len;
	while (end > pos + len - 1)
	{
		_str[end] = _str[end - len];
		--end;
	}

	memcpy(_str + pos, str, len);
	_size += len;
}

对于push_back,直接复用insert

void string::push_back(char ch)
{
	insert(_size, ch);
}

8.3 earse的实现

        

void string::erase(size_t pos, size_t len)
{
	assert(pos < _size);

	// len大于前面字符个数时,有多少删多少
	if (len >= _size - pos)
	{
		_str[pos] = '\0';
		_size = pos;
	}
	else
	{
		strcpy(_str + pos, _str + pos + len);
		_size -= len;
	}
}

9.String中查找一个字符与字符串(Find 的实现)

size_t string::find(char ch, size_t pos)
{
	for (size_t i = pos; i < _size; i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}

	return npos;
}
size_t string::find(const char* sub, size_t pos)
{
	char* p = strstr(_str + pos, sub);
	return  p - _str;
}

10.resize与reserve

        

void test_string11()
{
	string s1;
	s1.resize(5, '0'); //初始值
	cout << s1 << endl;
 
	// 再扩容
	s1.reserve(100);
	cout << s1.size() << "  " << s1.capacity() << endl;
 
	//reserve 在vs下不会缩容,没有规定
	s1.reserve(20);
	cout << s1.size() << "  " << s1.capacity() << endl;
 
	s1.resize(10);
	cout << s1.size() << "  " << s1.capacity() << endl;
 
	s1.resize(120);
	cout << s1.size() << "  " << s1.capacity() << endl;
 
   //由此发现resize影响capacity、size
   (当再开辟空间大于原先capacity才会影响capacity), 
   reserve不影响size
 
	//插入(空间不够扩容)
	string s2("hello world");
	s2.resize(20, 'x'); //不会清掉之前的字符,在后面填写
	cout << s2 << endl;
 
	// 删除
	s2.resize(5); 
}

11.c_str的比较

void test_string13()
{
	string a = "abc";
	string b = a;
 
	//a.c_str() == b.c_str()比较的是存储字符串位置的地址,
	// a和b是两个不同的对象,内部数据存储的位置也不相同,因此不相等
	if (a.c_str() == b.c_str())cout << "True" << endl;
	else cout << "False" << endl;
}

12.string的总接口的实现

        接口:

#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;

namespace bit
{
	class string
	{
	public:
		typedef char* iterator;
		typedef const char* const_iterator;

		iterator begin();
		iterator end();

		const_iterator begin() const;
		const_iterator end() const;

		//string();
		string(const char* str = "");
		string(const string& s);
		string& operator=(const string& s);
		~string();

		const char* c_str() const;

		size_t size() const;
		char& operator[](size_t pos);
		const char& operator[](size_t pos) const;

		void reserve(size_t n);

		void push_back(char ch);
		void append(const char* str);

		string& operator+=(char ch);
		string& operator+=(const char* str);

		void insert(size_t pos, char ch);
		void insert(size_t pos, const char* str);
		void erase(size_t pos = 0, size_t len = npos);

		size_t find(char ch, size_t pos = 0);
		size_t find(const char* str, size_t pos = 0);

		void swap(string& s);
		string substr(size_t pos = 0, size_t len = npos);

		bool operator<(const string& s) const;
		bool operator>(const string& s) const;
		bool operator<=(const string& s) const;
		bool operator>=(const string& s) const;
		bool operator==(const string& s) const;
		bool operator!=(const string& s) const;
		void clear();
	private:
		// char _buff[16];
		char* _str;

		size_t _size;
		size_t _capacity;

		//  
		//const static size_t npos = -1;

		// ֧
		//const static double N = 2.2;

		const static size_t npos;
	};

	istream& operator>> (istream& is, string& str);
	ostream& operator<< (ostream& os, const string& str);
}

接口的实现:

#include"string.h"

namespace bit
{
	const size_t string::npos = -1;

	//string::string()
	//{
	//	_str = new char[1]{'\0'};
	//	_size = 0;
	//	_capacity = 0;
	//}

	string::iterator string::begin()
	{
		return _str;
	}

	string::iterator string::end()
	{
		return _str + _size;
	}

	string::const_iterator string::begin() const
	{
		return _str;
	}

	string::const_iterator string::end() const
	{
		return _str + _size;
	}

	// 21:10
	string::string(const char* str)
		:_size(strlen(str))
	{
		_str = new char[_size + 1];
		_capacity = _size;
		strcpy(_str, str);
	}

	// s2(s1)
	string::string(const string& s)
	{
		_str = new char[s._capacity + 1];
		strcpy(_str, s._str);
		_size = s._size;
		_capacity = s._capacity;
	}

	// s1 = s3
	// s1 = s1
	string& string::operator=(const string& s)
	{
		if (this != &s)
		{
			char* tmp = new char[s._capacity + 1];
			strcpy(tmp, s._str);
			delete[] _str;
			_str = tmp;
			_size = s._size;
			_capacity = s._capacity;
		}

		return *this;
	}

	string::~string()
	{
		delete[] _str;
		_str = nullptr;
		_size = _capacity = 0;
	}

	const char* string::c_str() const
	{
		return _str;
	}

	size_t string::size() const
	{
		return _size;
	}

	char& string::operator[](size_t pos)
	{
		assert(pos < _size);
		return _str[pos];
	}

	const char& string::operator[](size_t pos) const
	{
		assert(pos < _size);
		return _str[pos];
	}

	void string::reserve(size_t n)
	{
		if (n > _capacity)
		{
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;

			_str = tmp;
			_capacity = n;
		}
	}

	void string::push_back(char ch)
	{
		/*if (_size == _capacity)
		{
			size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
			reserve(newcapacity);
		}

		_str[_size] = ch;
		_str[_size + 1] = '\0';
		++_size;*/

		insert(_size, ch);
	}

	// "hello"  "xxxxxxxxxxxxx"
	void string::append(const char* str)
	{
		/*size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}

		strcpy(_str+_size, str);
		_size += len;*/

		insert(_size, str);
	}

	string& string::operator+=(char ch)
	{
		push_back(ch);

		return *this;
	}

	string& string::operator+=(const char* str)
	{
		append(str);

		return *this;
	}

	void string::insert(size_t pos, char ch)
	{
		assert(pos <= _size);

		if (_size == _capacity)
		{
			size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
			reserve(newcapacity);
		}

		/*int end = _size;
		while (end >= (int)pos)
		{
			_str[end + 1] = _str[end];
			--end;
		}*/

		size_t end = _size + 1;
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			--end;
		}

		_str[pos] = ch;
		++_size;
	}

	void string::insert(size_t pos, const char* str)
	{
		assert(pos <= _size);

		size_t len = strlen(str);
		if (_size + len > _capacity)
		{
			reserve(_size + len);
		}

		/*int end = _size;
		while (end >= (int)pos)
		{
			_str[end + len] = _str[end];
			--end;
		}*/

		size_t end = _size + len;
		while (end > pos + len - 1)
		{
			_str[end] = _str[end - len];
			--end;
		}

		memcpy(_str + pos, str, len);
		_size += len;
	}

	// 17:10
	void string::erase(size_t pos, size_t len)
	{
		assert(pos < _size);

		// len大于前面字符个数时,有多少删多少
		if (len >= _size - pos)
		{
			_str[pos] = '\0';
			_size = pos;
		}
		else
		{
			strcpy(_str + pos, _str + pos + len);
			_size -= len;
		}
	}

	size_t string::find(char ch, size_t pos)
	{
		for (size_t i = pos; i < _size; i++)
		{
			if (_str[i] == ch)
			{
				return i;
			}
		}

		return npos;
	}

	size_t string::find(const char* sub, size_t pos)
	{
		char* p = strstr(_str + pos, sub);
		return  p - _str;
	}

	// s1.swap(s3)
	void string::swap(string& s)
	{
		std::swap(_str, s._str);
		std::swap(_size, s._size);
		std::swap(_capacity, s._capacity);
	}

	string string::substr(size_t pos, size_t len)
	{
		// len大于后面剩余字符,有多少取多少
		if (len > _size - pos)
		{
			string sub(_str + pos);
			return sub;
		}
		else
		{
			string sub;
			sub.reserve(len);
			for (size_t i = 0; i < len; i++)
			{
				sub += _str[pos + i];
			}

			return sub;
		}
	}

	bool string::operator<(const string& s) const
	{
		return strcmp(_str, s._str) < 0;
	}

	bool string::operator>(const string& s) const
	{
		return !(*this <= s);
	}

	bool string::operator<=(const string& s) const
	{
		return *this < s || *this == s;
	}

	bool string::operator>=(const string& s) const
	{
		return !(*this < s);
	}

	bool string::operator==(const string& s) const
	{
		return strcmp(_str, s._str) == 0;
	}

	bool string::operator!=(const string& s) const
	{
		return !(*this == s);
	}

	void string::clear()
	{
		_str[0] = '\0';
		_size = 0;
	}

	istream& operator>> (istream& is, string& str)
	{
		str.clear();
		char ch = is.get();
		while (ch != ' ' && ch != '\n')
		{
			str += ch;
			ch = is.get();
		}

		return is;
	}

	ostream& operator<< (ostream& os, const string& str)
	{
		for (size_t i = 0; i < str.size(); i++)
		{
			os << str[i];
		}

		return os;
	}
}

13.补充:大小写转换

transform(s.begin(),s.end(),s.begin(),::tolower);
transform(s.begin(),s.end(),s.begin(),::toupper);

13.2 substr取子串

str = str.substr(cnt); //取从cnt下标开始一直到结束的所有字符

str = str.substr(cnt,m); //取从cnt下标开始的m个字符

13.3 字符串与数字的相互转化

a、字符串转数字

1 .string s="12";

2 .int y=stoi(s);

b、数字转字符串

     string x=to_string(12);

14.string的相关题型

1.字符串相加

2.仅仅反转字母

3.字符串中第一个唯一字符

4.字符串中最后一个单词长度

5.验证回文串

6.字符串相加

7.反转字符串II

8.反转字符串III

9.字符串相乘

10.找出字符串中第一个只出现一次的字符

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1981612.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

字节实习面试

1.比左边的数都小&#xff0c;比右边的数都大 public class Test3 {/*** 从左往右找当前位置往左最小的* 从右往左遍历找当前位置往右最大的* 比较* param args*/public static void main(String[] args) { // int[] arr new int[]{9,8,7,3,4,2,1};int[] arr new int[…

【第十届泰迪杯数据挖掘挑战赛A题害虫识别】-农田害虫检测识别-高精度完整更新

农田害虫检测识别项目-高精度完整版 一、说明&#xff1a; 该版本为基于泰迪杯完整害虫数据重新制作数据集、优化增强数据集、重新进行模型训练&#xff0c;达到高精度、高召回率的最优模型代码。包含论文、最优模型文件以及相关文件、原始数据集、训练数据集XML版、增强扩充…

五款超好用的报表软件推荐,其中一款竟然完全免费

与以往需要通过繁琐的数据表格和复杂的数字分析不同&#xff0c;可视化报表通过表格、图表和图形&#xff0c;将数据以更加直观的方式呈现出来&#xff0c;使得原本繁杂无序的数据变得清晰易懂。无论是管理层的决策分析&#xff0c;还是一线员工的日常工作&#xff0c;可视化报…

vs+qt一些问题

一直遇到的两个问题&#xff0c;今天解决了 1、 因为前后端分离&#xff0c;前端写完了&#xff0c;后端还在一直修改&#xff0c;但是每次都是单独打开的后端的sln&#xff0c;所以会出现这个&#xff0c;把前端的模块删掉就好了。 2、打开vs项目&#xff0c;很多报错&#…

怎么在视频上加文字?归纳了简单好用的方法

怎么在视频上加文字&#xff1f;在数字媒体制作中&#xff0c;为视频添加文字是一种常见的需求。无论是为了提供字幕、注释、标题还是视觉效果&#xff0c;文字元素都能增强视频的传达力和观赏性。因此&#xff0c;今天本文将介绍四种简单好用的方法&#xff0c;帮助你轻松地在…

硬盘数据恢复:所需时长、全面指南及注意事项

在数字化时代&#xff0c;硬盘作为我们存储重要数据的核心设备&#xff0c;其重要性不言而喻。然而&#xff0c;由于各种原因&#xff0c;如误删除、格式化、硬盘故障等&#xff0c;我们时常面临数据丢失的困境。数据恢复不仅关乎个人隐私和信息安全&#xff0c;更可能影响到我…

Platform Designer各模块(2)

1.On-Chip Memory&#xff08;存储器&#xff09; (RAM or ROM) Intel FPGA IP RAM&#xff1a;主存&#xff0c;与CPU直接交换数据的内部存储器&#xff0c;可读可写&#xff0c;断电不丢失数据&#xff1b; ROM&#xff1a;只能读取数据&#xff0c;断电丢失数据。 2.Syste…

如何利用matlab将现有的地基雷达回波数据调制为机载雷达回波数据???

&#x1f3c6;本文收录于《CSDN问答解惑-专业版》专栏&#xff0c;主要记录项目实战过程中的Bug之前因后果及提供真实有效的解决方案&#xff0c;希望能够助你一臂之力&#xff0c;帮你早日登顶实现财富自由&#x1f680;&#xff1b;同时&#xff0c;欢迎大家关注&&收…

Bug太多,苹果手机升级到18.1后怎么降级

最近苹果公司发布了iOS 18.1开发者测试版和macOS Sequoia 15.1的开发者测试版&#xff0c;此次发布的iOS18.1开发者测试版本苹果给其带来了两个重要的新功能。 1、通话录音功能 现在只要拨打或者是接听电话&#xff0c;界面左上角就会出现通话录音按键&#xff0c;点击即可开启…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第五篇 文件系统构建篇-第七十四章 buildroot构建文件系统

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

老照片修复软件分享3款!码住一些实用的方法!

在数字时代&#xff0c;老照片不仅是时间的印记&#xff0c;更是我们珍贵的记忆载体。然而&#xff0c;随着时间的流逝&#xff0c;这些照片往往会变得模糊、褪色甚至破损。幸运的是&#xff0c;现代科技的发展为我们提供了多种老照片修复软件&#xff0c;让我们能够轻松恢复这…

docker 发布geoserver服务添加字体

1. 创建容器时可直接挂载到系统字体库 2. 已发布的容器挂载字体目录 关闭docker服务 &#xff1a; systemctl stop docker.socket 修改config.v2.json :位置在 cd /var/lib/docker/containers/容器id 重新启动docker服务&#xff1a;systemctl start docker

【启明智显方案分享】6.86寸高清显示屏音频效果器解决方案

一、项目概述 本方案旨在设计一款集成6.86寸高清触摸显示屏的音频效果器&#xff0c;通过HMI&#xff08;Human-Machine Interface&#xff09;芯片Model 4驱动&#xff0c;实现高清晰度的视觉交互。该设备不仅支持音乐、麦克风及温响音量的精细控制&#xff0c;还内置丰富的预…

vue信息列表实现点击加载更多陆续显示后面数据

原理&#xff1a;在点击加载更多后进行判断&#xff1a; if (this.currentPage < this.totalPages - 1) {this.currentPage;} 如果当前页码小于总页码就让当前页码1&#xff0c;通过计算属性动态更新开始和结束值&#xff0c;从而当前页面展示更多数据&#xff1a; paginate…

WPF使用Iconfont字符串的操作方法

1.下载字体库文件 https://www.bootcss.com/p/font-awesome/ 2.放入Fonts文件夹下 3.文件属性修改为 资源 3.引入 FontFamily字体类型 <Setter Property"FontFamily" Value"../../CommonInMy/Fonts/#iconfont"/>注意这里的地址请填写绝对地址&…

哈佛大学单细胞课程|笔记汇总 (二)

哈佛大学单细胞课程|笔记汇总 &#xff08;一&#xff09; &#xff08;二&#xff09;Single-cell RNA-seq data - raw data to count matrix 根据所用文库制备方法的不同&#xff0c;RNA序列&#xff08;也被称为reads或tag&#xff09;将从转录本&#xff08;(10X Genomic…

期权逢高空是什么意思?期权为什么要逢高空呢?

今天带你了解期权逢高空是什么意思&#xff1f;期权为什么要逢高空呢&#xff1f;期权是金融市场上常见的一种金融工具&#xff0c;它赋予持有者在未来某个特定时间以特定价格买入或卖出标的资产的权利。 期权逢高空是什么&#xff1f; 期权逢高空是一种交易策略&#xff0c;…

在Ubuntu 24.04服务器或桌面上安装XFCE

在Ubuntu 24.04 上更改当前 桌面环境或添加新桌面环境并不困难。大多数流行的Linux桌面环境&#xff08;包括 XFCE&#xff09;都可以使用默认的 Ubuntu 24.04 LTS 系统存储库进行安装。因此&#xff0c;在本教程中&#xff0c;我们将学习如何使用 Tasksel 工具在 Ubuntu Linux…

海外仓代理刚入行怎么抢占优势?找对系统就是捷径

海外仓现在就是一块正在越做越大的蛋糕&#xff0c;涌入的货代如果想从海外仓代理做起&#xff0c;并且抢占优势其实也不难。这个过程最关键的就是管理&#xff0c;包括信息、财务、仓库、人员等&#xff0c;易境通DWMS系统就把管理的问题一站式集合起来&#xff0c;一条龙搞定…

RTSP/Onvif安防视频监控云平台EasyNVR无法正常启动(系统缺库)的解决办法

视频安防监控平台EasyNVR可支持设备通过RTSP/Onvif协议接入&#xff0c;并能对接入的视频流进行处理与多端分发&#xff0c;包括RTSP、RTMP、HTTP-FLV、WS-FLV、HLS、WebRTC等多种视频流格式。平台可提供视频实时监控直播、云端录像、云存储、录像检索与回看、告警等视频能力&a…