C++:string的模拟实现

news2024/11/27 21:54:46

目录

1.string的四大默认函数

1.1构造函数

1.2析构函数

1.3拷贝构造

1.4赋值运算符重载

2.访问string的三种方式

2.1[]访问

2.2迭代器访问

2.3范围for(本质是迭代器)

3.string相关功能的实现

3.1modify

3.2capacity

3.3access

3.4relations

3.5补充

4.补充


1.string的四个默认函数

1.1构造函数

		//构造函数
		String(const char* str = "")
			:_size(strlen(str))
		{
			if (str == nullptr) 
				exit(-1);

			_capacity = _size == 0 ? 3 : _size;
			_str = new char[_capacity + 1];
			strcpy(_str,str);

		}

1.2析构函数

		//析构函数
		~String() 
		{
			if (_str == nullptr)
				assert(false);

			delete[] _str;
            _str = nullptr;
			_size = _capacity = 0;
		}

1.3拷贝构造

		//拷贝构造
		String(const String& s) 
		{
			_str = new char[strlen(s._str)+1];
			strcpy(_str,s._str);
		}

1.4赋值运算符重载

		//赋值运算符
		String& operator=(const String& s) 
		{
			if (this != &s) 
			{
				char* tmp = new char[strlen(s._str)+1];
				strcpy(tmp,s._str);
				delete[] _str;

				_str = tmp;
				_size = s._size;
				_capacity = s._capacity;
			}
			return *this;
		}

2.访问string的三种方式

2.1[]访问

		char& operator[](size_t pos) 
		{
			return *(_str + pos);
		}

2.2迭代器访问

		//迭代器
		typedef char* iterator;
		typedef const char* const_iterator;


		iterator begin() 
		{
			return _str;
		}

		iterator begin()const
		{
			return _str;
		}

		iterator end()
		{
			return _str + _size;
		}

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

2.3范围for(本质是迭代器)

	//范围for
	cout << "范围for: ";
	for (auto ch : s1) 
	{
		cout << ch;
	}

3.string相关功能的实现

3.1modify

-push_back

		//尾插一个字符
		void push_back(char ch) 
		{
			//检查是否扩容
			if (_size + 1 > _capacity)
				reserve(2*_capacity);

			//插入数据
			_str[_size] = ch;
			++_size;

			_str[_size] = '\0';
		}

-+= 字符

		//重载
		String& operator+=(char ch) 
		{
			push_back(ch);
			return *this;
		}

-append

		//append
		void append(const char* str) 
		{
			int len = strlen(str);
			if (_size + len > _capacity) //扩容
			{
				reserve(_capacity + len);
			}
			//插入数据
			strcat(_str,str);
			_size += len;
		}

-+=字符串

		//重载+=
		String& operator+=(const char* str) 
		{
			append(str);
			return *this;
		}

-clear

		//clear
		void clear() 
		{
			_size = 0;
			_str[_size] = '0';
		}

-swap

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

-C格式字符串

		//C格式的字符串
		const char* c_str()const
		{
			return _str;
		}

3.2capacity

-size

		//获取长度
		size_t size()const
		{
			return _size;
		}

-capacity

		//获取容量
		size_t size()const
		{
			return _capacity;
		}

-bool empty

		bool empty()const
		{
			return _size == 0;
		}

-reserve(扩容)

		//reserve(扩容)
		void reserve(size_t n)
		{
			if (n < _size) //删除数据
			{
				_str[n] = '\0';
			}
			if (n > _capacity)
			{
				//拷贝原来的数据
				char* tmp = new char[n + 1];
				strcpy(tmp, _str);
				delete[] _str;
				_str = tmp;
				_capacity = n;
			}
		}

-resize

		void resize(size_t n,char ch = '\0')
		{
			if (n < _size) 
			{
				_size = n;//删除数据
				_str[_size] = '\0';
			}
			else //n>=_size
			{
				if (n > _capacity)
				{
					reserve(n);
				}
				//将剩余的字符初始化
				size_t i = _size;
				while (i < n)
				{
					_str[i] = ch;
					i++;
				}
				_size = n;//改变size大小
				_str[_size] = '\0';
			}
		}

3.3access

		// access
		char& operator[](size_t pos)
		{
			return *(_str + pos);
		}

		char& operator[](size_t pos)const
		{
			return *(_str + pos);
		}

3.4relations

		//relational operators
		bool operator<(const String& s) 
		{
			return strcmp(_str, s._str) < 0;
		}
		bool operator <=(const String& s)
		{
			return strcmp(_str, s._str) <= 0;
		}
		bool operator>(const String& s)
		{
			return strcmp(_str, s._str) > 0;
		}
		bool operator >=(const String& s)
		{
			return strcmp(_str, s._str) >= 0;
		}
		bool operator==(const String& s) 
		{
			return strcmp(_str,s._str) == 0;
		}
		bool operator!=(const String& s)
		{
			return strcmp(_str, s._str) != 0;
		}

3.5补充

1.-find     //返回c再string中第一次出现的位置

		//返回c再string中第一次出现的位置
		size_t find(char c,size_t pos = 0) 
		{
			assert(pos < _size);
			while (pos< _size) 
			{
				if (_str[pos] == c) 
				{
					return pos;
				}
				pos++;
			}
			return npos;
		}

--find   //字符串

		//返回子字串在string中第一次出现的位置
		size_t find(const char* str, size_t pos = 0)const
		{
			return strstr(_str,str+pos) - _str - pos;
		}

2.//在pos位置上插入字符c/字符串str,并返回该字符的位置

-字符

		//在pos位置上插入字符c/字符串str,并返回该字符的位置
		size_t insert(size_t pos ,char ch )
		{
			assert(pos < _size);
			//判断是否需要扩容
			if (_size + 1 > _capacity) 
			{
				reserve(2*_capacity);
			}
			//从后往前挪动数据
			size_t end = _size + 1;
			while (end > pos) 
			{
				_str[end] = _str[end - 1];
				end--;
			}

			//在pos位置插入数据
			_str[pos] = ch;
			//更新_size
			_size++;
			return pos;
		}

-字符串


		size_t insert(size_t pos, const char* str) 
		{
			assert(pos < _size);
			size_t len = strlen(str);
			//扩容
			if (_size + len > _capacity) 
			{
				reserve(_capacity + len);
			}

			//挪动数据
			size_t end = _size + len;
			while (end - len > pos) 
			{
				_str[end] = _str[end - len];
				end--;
			}
			//在pos位置插入字符串
			strncpy(_str + pos ,str,len);
			//更新_size
			_size += len;

			return pos;
		}

//删除数据

		// 删除pos位置上的元素,并返回该元素的下一个位置
		
		String& erase(size_t pos,size_t len) 
		{
			assert(pos < _size);
			//将pos后的数据删完
			if (len == npos || pos + len > _size) 
			{
				_str[pos] = '\0';
				_size = pos ;
			}
			else //删除一部分
			{
				//把删除len后面的数据拷贝到pos后
				strcpy(_str + pos ,_str + pos + len);
				_size -= len;
			}
			return *this;
		}

3.>>与<<的重载

<<

	ostream& operator<<(ostream& _cout, const my_func::String& s)
	{
		for (auto e : s)
		{
			_cout << e;
		}
		_cout << endl;
		return _cout;
	}

>>

	istream& operator>>(istream& _cin,my_func::String& s)
	{	
		s.clear();//清空之前的内容
        //先往数组里面放,满了/读取到'\n'再往s里面放
        //这样避免频繁的扩容
        
		char buff[128];
		char ch = cin.get();
		size_t i = 0;
		while (ch != '\n')
		{
			buff[i++] = ch;
			if (i == 127) 
			{
				s += buff;//满了往s里面加
				i = 0;
			}
			ch = cin.get();//继续读取
		}

		if (i != 0) 
		{
			s += buff;
		}
		return _cin;
	}

4.补充

1.reserve与resize

reserve不会改变_size的大小(有效元素的个数)

(当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小。)

resize会改变并且用字符初始化多出来的空间

(resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变)

2.str与c_str

  • c_str是string类提供的成员函数,用于将string对象转换为C风格的字符串(以空字符结尾的字符数组)。

示例:

c_str在使用cout打印的时候,遇到\0就会停止打印

str    在使用重载后的<<打印,是按_size打印的

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

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

相关文章

基于Appium的UI自动化测试

为什么需要UI自动化测试 移动端APP是一个复杂的系统&#xff0c;不同功能之间耦合性很强&#xff0c;很难仅通过单元测试保障整体功能。UI测试是移动应用开发中重要的一环&#xff0c;但是执行速度较慢&#xff0c;有很多重复工作量&#xff0c;为了减少这些工作负担&#xff…

八大排序(二)--------冒泡排序

本专栏内容为&#xff1a;八大排序汇总 通过本专栏的深入学习&#xff0c;你可以了解并掌握八大排序以及相关的排序算法。 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;八大排序汇总 &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库…

高端知识竞赛中用到的软件和硬件有哪些

现在单位搞知识竞赛&#xff0c;已不满足于用PPT放题&#xff0c;找几个简单的抢答器、计分牌弄一下了&#xff0c;而是对现场效果和科技感要求更高了。大屏要分主屏侧屏&#xff0c;显示内容要求丰富炫酷&#xff1b;选手和评委也要用到平板等设备&#xff1b;计分要大气些&am…

QT在安装后添加新组件【QT基础入门 环境搭建】

一、Qt的安装目录下找到MaintenanceTool工具 二、双击该exe文件运行该工具(界面可能不相同但功能一样) 登录账号,进入以下界面,点击下一步 选择更新组件,出现以下提示 三、此时需要手动添加储存库 1.进入下面网站,选择一个国内镜像 Qt Downloads 点击后面的HTTP可进入…

java CAS详解(深入源码剖析)

CAS是什么 CAS是compare and swap的缩写&#xff0c;即我们所说的比较交换。该操作的作用就是保证数据一致性、操作原子性。 cas是一种基于锁的操作&#xff0c;而且是乐观锁。在java中锁分为乐观锁和悲观锁。悲观锁是将资源锁住&#xff0c;等之前获得锁的线程释放锁之后&am…

如何才能实现批量抠图?一键批量抠图的办法

批量抠图是在处理大量图片时非常实用的技术&#xff0c;它可以帮助您快速准确地去除图片的背景或选择特定的对象。在编辑图片和设计时是一项必不可少的技能。 今天分享一款简单方便的抠图工具&#xff0c;智能识别并抠取图片中的各种物体、人物、动物等&#xff0c;效果不错&a…

简单聊聊G1垃圾回收算法整个流程 --- 理论篇 -- 下

简单聊聊G1垃圾回收算法整个流程 --- 理论篇 -- 下 软实时性预测转移时间预测可信度GC 暂停处理的调度并发标记中的暂停处理 分代 G1 GC 模式不同点新生代区域分代对象转移具体转移流程分代选择回收集合设置最大新生代区域数 GC的切换GC执行的时机 总结 上一篇 文章我们简单看了…

JDK新特性-Stream流

Stream流是用来操作集合或者数组中的数据的&#xff0c;Stream流提供了一种更加强大的&#xff0c;更加简单的方式来操作集合或者数组中的数据&#xff0c;代码更加简洁&#xff0c;可读性更好。下面是一个简单的例子&#xff1a; public class S1 {public static void main(S…

12万条中法常见词语对照ACCESS数据库

法文是全球通用的语言之一&#xff0c;要拥有国际视野&#xff0c;学懂全球通用语言是您的必然选择。走向成功之门&#xff0c;尽快学会法文吧。《12万条中法常见词语对照ACCESS数据库》收集了汉语常用词语的法文对照翻译。 本数据库是由 Microsoft Access 2000 创建的 MDB 数据…

算法训练 第三周

一、买卖股票的最佳时机 本题给了我们一个数组&#xff0c;这个数组的第i个元素表示股票第i天的价格&#xff0c;要求我们选择一天买入股票&#xff0c;并在这天之后的某一天卖出&#xff0c;问我们何时能获得最大利润。 1.循环嵌套 我们可以循环遍历所有买入的价格&#xff…

Al中秋节由来

文章目录 简介中秋节的庆祝活动有哪些&#xff1f;有没有其他与中秋节相关的传说或故事&#xff1f; 今天的话题是&#xff0c;扯犊子 简介 中秋节是中国传统的重要节日之一&#xff0c;通常在农历八月十五这一天庆祝。中秋节的由来有多种传说和故事。 其中最有名的传说是关于…

什么是HTTP状态码?常见的HTTP状态码有哪些?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 什么是HTTP状态码&#xff1f;⭐ 1xx - 信息性状态码⭐ 2xx - 成功状态码⭐ 3xx - 重定向状态码⭐ 4xx - 客户端错误状态码⭐ 5xx - 服务器错误状态码⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前…

pcl--第五节 点云表面法线估算

估算点云表面法线 * 表面法线是几何表面的重要属性&#xff0c;在许多领域&#xff08;例如计算机图形应用程序&#xff09;中大量使用&#xff0c;以应用正确的光源以产生阴影和其他视觉效果。 给定一个几何表面&#xff0c;通常很难将表面某个点的法线方向推断为垂直于该点…

Qt(day3)

思维导图 小练习 second.h #ifndef SECOND_H #define SECOND_H#include <QWidget> #include<QLabel> #include<QLineEdit> #include<QPushButton> #include<QTimerEvent> #include<QTime> #include<QTextEdit> #include<QTextT…

北京小程序开发-微信小程序开发时间总结

一、双线程模型 渲染线程和逻辑线程 小程序的双线程指的就是渲染线程和逻辑线程&#xff0c;这两个线程分别承担UI的渲染和执行 JavaScript 代码的工作 渲染线程使用 Webview 进行 UI 的渲染呈现。Webview 是一个完整的类浏览器运行环境&#xff0c;本身具备运行 JavaScript…

Shiro 框架基本使用

文章目录 Shiro框架介绍Shiro 基本使用SimpleAccountRealmIniRealmJdbcRealmCustomRealm&#xff08;自定义Realm&#xff09; Shiro框架介绍 Apache Shiro是一个强大且易用的Java安全框架&#xff0c;它执行身份验证、授权、密码和会话管理。Shiro框架通过其三个核心组件&…

网络爬虫-----爬虫的分类及原理

目录 爬虫的分类 1.通用网络爬虫&#xff1a;搜索引擎的爬虫 2.聚焦网络爬虫&#xff1a;针对特定网页的爬虫 3.增量式网络爬虫 4.深层网络爬虫 通用爬虫与聚焦爬虫的原理 通用爬虫&#xff1a; 聚焦爬虫&#xff1a; 爬虫的分类 网络爬虫按照系统结构和实现技术&#…

白鲸开源 X SelectDB 金融大数据联合解决方案公布!从源头解决大数据开发挑战

业务挑战与痛点 随着互联网技术的发展、云计算技术的成熟、人工智能技术的兴起和数字化经济的崛起&#xff0c;数据已成为企业的核心资产。在金融行业中&#xff0c;数字化已成为了支撑各类业务场景的核心力量&#xff0c;包括个人理财、企业融资、股票交易、保险理赔、贷款服…

【Java 基础篇】Java 文件及文件夹操作详解

在Java编程中&#xff0c;文件和文件夹操作是常见的任务之一。你可能需要读取、写入、创建、删除文件或文件夹&#xff0c;以及遍历文件系统中的内容。本文将详细介绍Java中如何执行这些常见的文件和文件夹操作&#xff0c;适用于初学者和基础用户。 1. 文件操作 读取文件内容…

如何显示并管理Python应用的数据?Kendo UI for Angular有妙招!

Angular是Python应用中进行数据管理和显示的一个很好的选择&#xff0c;如果能使用Kendo UI for Angular则可以更进一步。 PS&#xff1a;给大家推荐一个实用组件~Kendo UI for Angular是专业级的Angular UI组件库&#xff0c;不仅是将其他供应商提供的现有组件封装起来&#…