STL之string模拟实现

ROS2仿真抓取分拣案例,使用myCobot 280机械臂结合ROS2系统搭建机械分拣站 本案例展示了如何利用myCobot 280 urdf模型构建一个对象分类站,并在ROS2 jazzy中完成运动规划。 阅读详情
一个问题:C语言中的字符串和C++中的字符串有什么不同?

答:C 语言中:
1、C 语言的字符串实际上是字符数组,C语言的字符串是将很多个字符放在连续的存储空间中,也就是数组。
2、C 语言的字符串是以 ‘\0’ 作为结尾标志的,也就是字符数组以 ‘\0’ 结尾就是 C语言风格的字符串
3、C 语言字符串的 ‘\0’ 结尾标志引发了很多问题:首先,我们很容易遗忘 ‘\0’ 的存在、以及在数据存储时我们要考虑到 ‘\0’、在对 C语言字符串进行操作时,一旦没有 ‘\0’ ,很容易造成缓冲区溢出,从而导致程序崩溃。
C++中:
1、C++ 中引入了自动的内存管理,所以对字符串的拼接、拷贝动作就不用我们考虑申请空间了。在C语言中的strcpy、strcat我们都要考虑字符串的空间是否足够大。
2、C++中的字符串不再使用 ‘\0’ 作为结尾了。
3、如果要获取字符串的长度,C语言中是使用 strlen ,但是 strlen 的时间复杂度是O(n),而 C++中是直接将字符串的长度保存下来了,所以时间复杂度是 O(1);
4、C语言字符串的拷贝是一个一个的拷贝,而C++的字符串拷贝使用的是写时拷贝技术,效率更高。

string模拟实现代码:

#include <iostream>
#include <assert.h>
using namespace std;

class String
{
public:
	typedef char* iterator;
	typedef const char* const_iterator;
	String(char* str = "")
	{
		assert(str != nullptr);
		// _size:有效字符数量,不包含'\0'
		_size = strlen(str);
		_str = new char[_size + 1];
		strcpy(_str, str);		//while(*_str++ = *str++);
		_capacity = _size;
	}

	String(const String& s)
		:_str(nullptr)
		, _size(0)
		, _capacity(0)
	{
		String tmp(s._str);
		Swap(tmp);
	}

	void Swap(String& s)
	{	
		//成员函数swap,完成指针的交换,无深拷贝,效率高
		swap(_str, s._str);
		swap(_size, s._size);
		swap(_capacity, s._capacity);
	}

	String& operator=(String s)
	{
		Swap(s);
		return *this;
	}

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

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

	iterator begin()
	{
		return _str;
	}

	iterator end()
	{
		return _str + _size;
	}

	const_iterator begin() const
	{
		return _str;
	}

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

	size_t Size() const
	{
		return _size;
	}

	size_t Capacity() const
	{
		return _capacity;
	}

	~String()
	{
		if (_str)
		{
			delete[] _str;
			_str = nullptr;
			_size = _capacity = 0;
		}
	}

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

	void PushBack(char c)
	{
		//检查空间是否足够
		if (_size == _capacity)
		{
			//初始容量设置为15
			size_t newC = (_capacity == 0 ? 15 : 2 * _capacity);
			Reserve(newC);
		}
		_str[_size++] = c;
		_str[_size] = '\0';
	}

	void Reserve(size_t n)
	{
		if (n > _capacity)
		{
			//申请空间
			char* tmp = new char[n + 1];
			strcpy(tmp, _str);
			delete[] _str;
			//更新指针
			_str = tmp;
			//更新容量
			_capacity = n;
		}
	}

	void PopBack()
	{
		if (_size > 0)
		{
			_str[--_size] = '\0';
		}
	}

	void Resize(size_t n, char c = '\0')
	{
		//大于容量,重新分配容量
		if (n > _capacity)
		{
			Reserve(n);
		}
		//大于_size,重新分配_size,多的补'\0'
		if (n > _size)
		{
			memset(_str + _size, c, n - _size);
		}
		_size = n;
		_str[_size] = '\0';
	}

	void Erase(size_t pos, size_t len)
	{
		assert(pos < _size);
		if (pos + len >= _size)
		{
			_size = pos;
			_str[_size] = '\0';
		}
		else{
			//从pos + len的位置开始挪动数据,每个数据向前挪动 len 个位置
			for (size_t i = pos + len; i <= _size; i++)
			{
				_str[pos++] = _str[i];
			}
			_size -= len;
		}
	}

	void Append(const char* str)
	{
		size_t sz = strlen(str);
		if (_size + sz >= _capacity)
		{
			Reserve(_size + sz);
		}
		//从'\0'的位置开始插入字符串str
		strcpy(_str + _size, str);
		_size = _size + sz;
	}

	void Insert(size_t pos, char c)
	{
		assert(pos <= _size);
		//扩容
		if (_size >= _capacity)
		{
			size_t newCapacity = (_capacity == 0 ? 15 : 2 * _capacity);
			Reserve(newCapacity);
		}
		//元素挪动,从后往前挪动,留出pos位置插入新元素
		size_t end = _size;
		//注意此处不要用
		//while (end >= pos){
		//	_str[end + 1] = _str[end];
		//	--end;		
		//因为当头插时,end减到0的时候循环还会进来,然后再减1,由于end是size_t类型,所以会变成整型最大值
		//}
		while (end > pos)
		{
			_str[end] = _str[end - 1];
			--end;
		}
		//插入元素
		_str[pos] = c;
		_size++;
		_str[_size] = '\0';
	}

	void Insert(size_t pos, const char* str)
	{
		assert(pos <= _size);
		size_t sz = strlen(str);
		//增容。因为是插入字符串,所以不能简单的增容二倍,增加的容量要能够放下原有的和新的字符
		if (_size >= _capacity)
		{
			Reserve(_size + sz);
		}

		//挪动元素,从最后一个到最前面,一个一个往后挪
		size_t end = _size + sz;
		while (end > pos + sz - 1)
		{
			_str[end] = _str[end - sz];
			end--;
		}

		//插入新元素,注意不能用strcpy,因为会把新字符串的'\0'也拷贝过去而覆盖原有的数据
		//strncpy可以使用
		strncpy(_str + pos, str, sz);
		//或者一个一个拷贝
		//while(*str)
		//{
		//	  _str[pos++] = *str++;
		//}
		_size += sz;
	}

	size_t find(char c)
	{
		for (size_t i = 0; i < _size; i++)
		{
			if (_str[i] == c){
				return i;
			}
		}
		//如果没找到返回npos
		return npos;
	}
	//静态成员在类外初始化
	static const size_t npos;

	//字符串第一次出现的位置
	size_t find(size_t pos, char* str)
	{
		char* posPtr = strstr(_str + pos, str);
		if (posPtr)
		{
			return posPtr - _str;	//返回坐标
		}
		else
		{
			return npos;
		}
	}

	String& operator+=(char c)
	{
		PushBack(c);
		return *this;
	}

	String& operator+=(const char* str)
	{
		Append(str);
		return *this;
	}

	String& operator+=(const String& s)
	{
		//多种写法
		//1)*this += s._str;
		//2)*this += s.c_str();
		Append(s._str);
		return *this;
	}

private:
	friend ostream& operator<<(ostream& _cout, const String& s);
	char* _str;
	size_t _size;
	size_t _capacity;
};
const size_t String::npos = -1;

ostream& operator<<(ostream& _cout, const String& s)
{
	_cout << s.c_str();
	return _cout;
}

//测试[]
void PrintString(const String& s)
{
	for (size_t i = 0; i < s.Size(); i++)
	{
		cout << s[i];
	}
	cout << endl;
}

//测试iterator
void PrintWithIterator(const String& s)
{
	String::const_iterator sit = s.begin();
	while (sit != s.end())
	{
		cout << *sit << endl;
		++sit;
	}
	cout << endl;
}

void test1()
{
	String s1;
	s1.PushBack('1');
	s1.PushBack('2');
	s1.PushBack('3');
	s1.PushBack('4');
	s1[0] = 'e';
	s1.PopBack();
	s1.Append("asd");
	s1.Resize(3, '\0');
	s1.Reserve(20);
	cout << s1.Capacity() << endl;
	cout << s1.Size() << endl;
	cout << s1.c_str() << endl;
	cout << s1 << endl;
	String s2;
	s2 = s1;
	cout << s2 << endl;
	String s3(s1);
	cout << s3 << endl;
	s3.Erase(2, 1);
	cout << s3 << endl;
	s3.Insert(1, '9');
	cout << s3 << endl;
	s3.Insert(1, "lzl");
	cout << s3 << endl;
	//PrintString(s1);
	//PrintWithIterator(s1);

	cout << s3.find('l') << endl;
	cout << s3.find('w') << endl;
	cout << s3.find(0, "lzl") << endl;
	cout << s3.find(3, "lzl") << endl;

	s3 += 'a';
	cout << s3 << endl;
	s3 += s1;
	cout << s3 << endl;
	s3 += "lzl";
	cout << s3 << endl;
}

int main()
{
	test1();
	system("pause");
	return 0;
}
新时代多目标优化【数学建模】领域的极致探索——数学规划模型 数学规划模型是数学建模中用于描述和解决优化问题的一类模型。它通过构建目标函数和约束条件,将实际问题转化为数学形式,旨在寻找满足约束条件的最优解。数学规划模型广泛应用于各个领域,包括资源分配、生产计划、物流管理和金融投资等,通过线性规划、非线性规划、整数规划等方法,帮助决策者在复杂环境中做出最优选择。 阅读详情

相关推荐

NRF52832串口通信避坑指南:从SDK配置到硬件流控(RTS/CTS)实战

本文详细介绍了NRF52832串口通信的实战指南,从SDK配置到硬件流控(RTS/CTS)的完整实现。通过分析UARTE模块特性、解决SDK版本差异问题、正确配置硬件引脚以及实现稳定通信的代码示例,帮助开发者避开常见陷阱,确保高效可靠的串口通信。特别强调了硬件流控在高速通信中的重要性及其实践方法。

weixin_33739646的博客 282

【C++】STL中string类的实现

在C语言中,使用printf直接输出string类型的字符串可能会出现乱码。这是因为printf函数的%s格式化符号期望传入一个char类型的参数,而string类型的字符串实际上是一个对象,不是一个字符指针。所以在使用printf输出string类型的字符串时,应该使用s.c_str()方法将string类型转换为char类型。而在C++中,使用cout输出string类型的字符串是没有问题的。cout对string类型有特殊的处理方式,可以直接输出string类型的字符串。

2301_76540463的博客 499

从TL431光耦到集成隔离器:3种反激电源反馈方案全对比,你的项目到底该选哪个?

本文深入对比了反激电源设计中TL431光耦、集成隔离器和原边反馈三种主流反馈方案的优缺点,帮助开发者在电源设计中选择最适合的方案。从精度、成本、隔离等级等多维度分析,为反激式(Flyback)拓扑的应用提供实用选型指南。

weixin_30536513的博客 399

【C++】STL中string类的模拟实现

C标准库中也提供了一系列的str库函数,但不符合oop思想(核心:封装、继承、多态),所以C++引入了string类,在OJ中很多有关字符串的题目都是以string类出现的,下面我们深入了解一下string以及模拟实现

weixin_46016019的博客 2869

电机控制实战:SVPWM五段式与七段式算法在STM32上的实现对比

本文深入对比了SVPWM五段式与七段式算法在STM32上的实现效果,详细分析了两种算法在占空比控制、开关损耗和波形质量等方面的差异。通过实测数据,为工程师提供了针对不同应用场景的选型建议,包括电池供电设备和高精度伺服控制系统的优化方案。

h6i7j8的博客 584

基于CNN对抗嵌入的图像隐写——CNN-Based Adversarial Embedding for Image Steganography

CNN-Based Adversarial Embedding for Image Steganography https://ieeexplore.ieee.org/abstract/document/8603808 这篇论文发表在TIFS( IEEE TRANSACTIONS ON INFORMATION FORENSICS AND SECURITY),TIFS是网络与信息安全领域的国际两大顶级期刊之一,中国计算机学会(CCF)推荐的A类期刊,SCI一区TOP期刊,目前影响因子有7多了。 1 概

weixin_48654804的博客 2279

STL-string简单实现

字符串扩容函数(当我们使用pushback或者append时,有时会出现空间不足的问题,如果强行访问就会出现指针越界的情况,因此这时要对字符串进行扩容)今天复习了string类,做笔记方便日后复习。看完这个类的大体结构,我们开始对其实现。水平有限,希望大家结合图示理解。重载赋值运算符(传统写法)重载赋值运算符(现代写法)

weixin_53417761的博客 427

S32DS IDE调试技巧:如何用Attach功能高效定位汽车电子MCU的Bootloader问题

本文详细介绍了在汽车电子MCU开发中,如何利用S32DS IDE的Attach调试模式高效定位Bootloader与应用程序的协同问题。通过对比常规调试与Attach模式的本质差异,并深入讲解工程配置、镜像合并及实战调试流程,帮助开发者在不复位、不重新下载程序的前提下,实时分析系统状态,快速解决内存映射冲突、中断向量表重定向等疑难杂症。

weixin_29168393的博客 266

STL中string类的用法及其模拟实现

目录 一、string类的默认存储字符类型: 二、string类的使用: 1.创建对象 2.三种遍历sting的方式: 2.1.for+[]的方式: 2.2.迭代器: 2.3.范围for遍历(其实也是依赖类中的迭代器进行遍历元素) 3.插入数据的方式: 4.删除数据 5.reserve和resize(扩容操作) 5.1.resize: 5.2.reserve: 5.3.疑问(resize和reserve两种平台下的扩容规律)? 6.c_str() 7.在字符串中找出子串 8.

weixin_45897952的博客 1325

Flink CDC 实战:5分钟搞定PostgreSQL数据实时同步(附避坑指南)

本文详细介绍了如何使用Flink CDC实现PostgreSQL数据的实时同步,包括环境配置、逻辑复制槽创建、Flink环境搭建及实战验证。通过5分钟快速指南,帮助开发者高效搭建实时数据管道,并提供了常见问题排查和生产环境优化建议。

red88的博客 818

ArcGIS将以大西洋居中的世界地图以中国居中显示

ArcGIS将以大西洋居中的世界地图以中国居中显示 并进行经纬度格网的调整输出

jiekeheiguanglan的博客 5704

STL-string类的实现

string就是字符串的意思,是用来表示字符序列的类,是C++用来代替char 数组的数据结构,里面封装了一些关于操作字符串的方法,该string类的接口与常规容器的接口基本相同,同时再添加了一些专门用来操作string的常规操作。但是不能操作多字节或者变长字符的序列。所以综上所述,我们就可以将string类理解为一个数组,只不过存储在该数组中的元素类型为char类型,且其大小可以实现动态增长,而且在数组末尾隐藏了'\0'

学习日记 870

【网络与爬虫 61】移动端App爬虫终极指南:Android-iOS应用数据提取黑科技全解析

本文全面解析移动端App爬虫技术,涵盖Android和iOS两大平台的数据提取方法。从基础的网络抓包到高级的代码注入,从自动化测试框架到反调试技术绕过,为开发者提供移动端数据采集的完整解决方案和实战经验。

熵数实验室 3023

C++ -- STL【string的模拟实现】

本文将介绍如何模拟实现 STL 的 string,包括其基本功能、数据结构、实现方法等,帮助读者深入理解字符串的操作和应用。

2301_80059080的博客 679

VC中sqlite的使用

在VC中对sqlite的使用,实现数据库大批数据的快速插入,读取数据库中的数据在ListCtrl中显示

计算机控制技术及应用

《计算机控制技术及应用》通过总结作者的科研成果和吸收国内外的先进理论、方法和技术,以计算机控制系统的网络化、开放化、智能化和集成化发展趋势为主线索,主要介绍计算机控制系统的基本概念和计算机控制系统的典型形式,计算机控制系统的数学描述与基本分析方法,以及数字PID控制器、最少拍控制系统、达林算法、状态变量设计法等设计方法及其各种改进算法。重点突出计算机控制系统输入输出通道接口的设计方法和典型控制系统的设计案例与实现方法等。

STL——string类的模拟实现

1. 1什么是STL标准模板库。

2401_84107961的博客 1469

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

STL—string类—模拟实现

关于string类的大致模拟实现,只实现其常用接口。【传统版写法的模拟string类】

aaa114514aaaa的博客 2019

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

C++STL——string类详解及其模拟实现

STL全称,译为下面展示STL的六大组件:本章,我们将对string部分常用的功能进行说明和使用,最后对string进行简单的模拟实现本章思维导图:注:本章思维导图已经同步导入至。

Forward♞的博客 1710

C++ [STL之string模拟实现]

前面我们介绍了STL容器string的部分接口使用,有了string使我们对字符串的操作如鱼得水,其实string不止于使用方便,其实现也有许多我们值得学习的地方,本节将为您介绍string常用接口的代码实现!

ARMCSKGT的博客 6177

【C++】STL容器之string模拟实现(附带讲解)

本文介绍了C++标准模板库(STL)中的string类及其模拟实现方法。主要内容包括:1)STL和string类的基本概念;2)string类的成员变量(字符指针、大小、容量等)和核心成员函数(构造、拷贝构造、析构等);3)迭代器实现(读写迭代器和只读迭代器);4)运算符重载(赋值、复合赋值、下标访问、输入输出等);5)功能函数如getline的实现。文章重点展示了现代C++编程技巧在string类实现中的应用,如利用构造函数优化拷贝构造和赋值运算符的实现,并提供了多种实现方式的代码示例。

小雄的博客 1868

C++ STL 之 string的模拟实现

STL 之 string的模拟实现 #include <iostream> #include <cassert> using namespace std; //STL里string的模拟实现 namespace my_string { class string { typedef char* iterator; //声明迭代器 static size_t npos; //无符号的-1 friend ostream& operator<<(o

qq_43579888的博客 172

【C++】STL介绍 + string类使用介绍 + 模拟实现string类

本文带大家入坑STL,学习第一个容器string,并初步了解编码。

x_p96484685433的博客 1101

【C++】STL学习——string模拟实现

学习C++STL中的string类,通过模拟实现string来深刻认识string的使用,底层,原理;同时巩固前面所学的C++语法

Mesar的博客 864

STL的string模拟实现

【代码】STL的string模拟实现。

mority_的博客 615

STL简介+string模拟实现

STL简介+string模拟实现

m0_64364831的博客 1136

STL容器string的模拟实现

在上一节已经学习了string的一些常用的接口,那这些接口如何实现?那下面就来学习string接口的模拟实现过程!!!如果_str初始化为nullptr,那么程序会崩溃!!为什么会崩溃呢?这里同样的,在开辟空间的时候要预留一个空间给'\0'!!如果不给预留空间,而是用nullptr初始化,这里的strlen(s)就会对空指针解引用,导致程序崩溃!

2403_82549373的博客 1158

【c++丨STL】string模拟实现(附源码)

今天,我们在学会使用string类的基础上模拟实现了string类的常用功能,这对于我们学习数据结构和string类有很大帮助。之后博主会和大家一起进入下一个容器——vector的学习。

2301_80955819的博客 2433
上一篇: STL之vector模拟实现
下一篇: STL之list的模拟实现
coolnut12138
博客等级 码龄9年 51粉丝 75原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值