【C++初阶】string模拟实现

请添加图片描述

✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
🌟🌟 追风赶月莫停留 🌟🌟
🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀🍀
🌟🌟 平芜尽处是春山🌟🌟
🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟🌟
🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿🌿
✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨✨
✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅✅

🍋string模拟实现

  • 🍑构造函数
  • 🍑析构函数
  • 🍑重载
    • 🍍方括号引用
    • 🍍+=操作
    • 🍍=操作
  • 🍑迭代器
  • 🍑增删查改
    • 🍍增
    • 🍍找
    • 🍍流提取和流插入

🍑构造函数

//有参构造
string(char* str)
{
	size_t _size = strlen(str);
	_capacity = _size;
	str = new char[_capacity+1];
	strcpy(_str, str);
}
//无参构造
string()
{
	_str = new char[1];
	_size = 0;
	_capacity = 0;
	_str[0] = '\0';
}

至于无参构造中,为了防止解引用发生错误,所以特有开了一个空间,并赋值为斜杠0。

上面代码就是普通的构造函数的写法,无参和有参构造,这里我们并不采用初始化列表的方式进行初始化。

但实际我们并不会这么写,会直接写一个全缺省:

string (const char* str = "\0")
{
	size_t _size = strlen(str);
	_capacity = _size;
	_str = new char[_capacity+1];
	strcpy(_str, str);
}

上面中初始化时并不能直接赋值给’\0’,str是字符串类型而’\0’是字符,两者类型不一样,所以应赋值"\0"。当然也可以不用赋值,直接空字符串也是,因为常量字符串中自带斜杠0。

🍑析构函数

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

析构函数就没有什么特别需要注意的了,和常规写法差不多

🍑重载

🍍方括号引用

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

引用在这里的作用是减少拷贝和修改返回值,如果单纯返回该里面的元素,就不会用引用了。

🍍+=操作

string& operator+=(char str)
{
	push_back(str);
	return *this;
}

string& operator+=(const char* str)
{
	append(str);
	return *this;
}

operator+=()函数操作就会简单就能实现,直接分别调用push_back()和append()函数即可,当然也可以自己在里面实现,不过实现的过程都差不多。

还有一个点需要大家注意,就是运算符重载需要有返回值。

🍍=操作

string& operator=(cconst string& s)
{
	if(_str != &s)
	{
		char* tem = new char[s._capacity+1];
		strcpy(tem, s._str);
		delete[] _str;
		_str = tem;
		_size = s._size;
		_capacity = s._capacity;
	}
	return *this;
}

该函数就是重载等号,如:

string s1("abcdef");
string s2 = s1;

该函数的作用就是string类同等类型相互赋值时,

🍑迭代器

typedef char* iterator;

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

string类中迭代器的实现就很简单了。

不同容器的迭代器方式不一样,大家以后可以在学习其它容器的迭代器实现的时候可以进行比较着学习

🍑增删查改

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

这是一个扩容函数,在push_back或insert时,空间都有可能满,所以会先进行扩容。

🍍增

void push_back(char ch)
{
	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newcapacity);
	}
	_str[_size] = ch;
	_size++;
	_str[_size] = '\0';
}

push_back()函数是在原本string中最后面的位置添加一个字符。

void append(const char* str)
{
	size_t len = strlen(str);
	if (_size+len > _capacity)
	{
		reserve(_size+len);
	}
	strcpy(_str+_size, str);
	_size += len;
}

append()函数和push_back()函数还是有点大径相同,只不过append()是增加一个字符串在原string类后面,不过有一些细节还是需要注意。

void insert(size_t pos, char str)
{
	assert(pos <= _size);
	if (_size == _capacity)
	{
		size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;
		reserve(newcapacity);
	}
	size_t end = _size ;
	while (end >= pos)
	{
		_str[end + 1] = str[end];
		end--;
	}
	_str[pos] = str;
	_size++;
}

insert()函数是一个可以在容器内插入字符的函数,在进行插入的时候都要对容器内的空间进行检查,防止空间满。在这里还要注意一点,我们是利用了end来当做循环条件,而end的类型是size_t ,而size_t是无符号整型。

而当pos为0时,这个时候循环结束条件就是end=-1,但end是size_t 类型,所以当end=-1时,实际上并不会得到你所期望的负数结果。由于size_t是一个无符号整形,所以它会将-1解释为一个非常大的正数。

在这里插入图片描述
所以这种情况下,程序就会陷入死循环。

void insert(size_t pos, char* str)
{
	size_t len = strlen(str);
	if (_size + len > _capacity)
	{
		reserve(_size + len);
	}
	size_t end = _size;
	while (end >= pos)
	{
		_str[end + len] = _str[end];
		end--;
	}
	strncpy(_str+pos, str, len);
	_size += len;
}

该insert()函数和上面的insert()函数功能差不多,但是这里insert()是插入一段字符,而上面的insert()函数是插入一个字符。

这里最后不能用strcpy(),因为strcpy()会把斜杠0一起复制过去,这样就会覆盖原有的一个值。

🍍找

size_t Find(char ch, size_t pos = 0)
{
	for(size_t i = pos; i < _str.size(); i++)
	{
		if (_str[i] == ch)
		{
			return i;
		}
	}
	return npos;
}

Find()函数是查找某个元素,并返回下标值,npos是全局静态变量,它值为-1, 在这里我们给了pos默认值,默认是从0开始找,也可以指定从那个数开始找。

size_t Find(const char* str, size_t pos = 0)
{
	const char* ptr = strstr(_str+pos,  str);
	if (ptr == nullptr)
	{
		return npos;
	}
	else
	{
		return ptr - _str;
	}
}

该函数是查找一段字符串的函数,并返回该字符串的起始位置,npos是全局静态变量,值为-1;

string substr(size_t pos, size_t len = npos)
{
	assert(pos < _size);
	size_t end = pos + len;
	if (len == npos || pos + len > _size)
	{
		end = _size;
	}
	string str;
	for (size_t i = pos; i < end; i++)
	{
		str += _str[i];
	}
	return str;
} 
	

substr()函数从主容器中取出指定范围的数据,其中npos是在上面已经提到过了,而在这len也是size_t类型,上面说过size_t是无符号整型,一旦len为负数,系统就会理解len是一个很大的值,也就相当于要取出的数大于pos后面的数据长度了,所以只是把后面的数全部取出来,和pos+len的情况是一样,所以在这里就吧它俩当成一种情况

使用substr()函数时要注意有没有深拷贝构造函数,程序会报错,需要提前写构造函数:

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

🍍流提取和流插入

ostream& operator<<(ostream& out, const string& s)
{
	for (auto ch : s)
	{
		out << ch;
	}
	return out;
}

不仅仅可以使用范围for,也可以使用迭代器或者原生指针输出。

该函数就是模拟流插入。string类的流提取函数写法还是很简单,另外这里也不需要写成友元形式,上面我们模拟实现了很多函数,都可以帮助我们完成,不过也有一些类的流提取需要加友元形式,才能正常运行。

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

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

上述是流提取函数,get()是C++中读取空格的操作符,相当于C语言中getchar()是一个作用。

关于clear()函数,因为我们在这里是 s += ch,是+=操作,所以数据并不会覆盖,所以我们需要先清理掉原有数据,再进行流插入。

这里关于流提取还有一个小问题,当我们输入的字符过多的时候,如果按照原来的扩容方法就会造成空间浪费,有一个改进的写法:

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

istream& operator>>(istream& in, string& s)
{
	s.clear();
	char open[128] = {0};
	char ch = in.get();
	while(ch != ' ' && ch != '\n')
	{
		open[i++] = ch;
		if (i == 127)
		{
			open[i] = '\0';
			s += open;
			i = 0;
		}
		ch = in.get();
	}

	if (i > 0)
	{
		open[i] = '\0';
		s += ch;
	}

	return in;
}

改进过的流提取就节省了很多空间,这里是利用了数组open,来临时存储数据,数组满了,再直接利用操作符"+="操作即可。

关于本章知识点如果有不足或者遗漏,欢迎大家指正,谢谢!!!

请添加图片描述
请添加图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

2024年抖店什么类目赚钱?这八个类目最赚钱,想开店的快来瞅瞅!

哈喽~我是电商月月 做抖音小店的商家都知道&#xff0c;选品是非常重要的 那什么样的商品类型赚钱&#xff0c;哪些商品又适合新手操作呢? 今天我就给大家推荐几个热销类目&#xff0c;特别是最后两个&#xff0c;下半年说不定会小爆一把哦 一&#xff0e;日用百货 这个类…

自制无感无刷电机驱动板

自制无感无刷电机驱动板 分别测试了基于C251的STC32G单片机、Arduino AVR的ATmega328PB、以及ARM的ST32F103单片机。 &#x1f9f2;测试转动效果 ✒目前市面上开源的有关无刷电机的项目数不胜数&#xff0c;其控制原理都大同小异&#xff0c;在没有领透其技术要领情况下&#x…

第六节笔记及作业----Lagent AgentLego 智能体应用搭建

关于 Agent 的相关理论 大语言模型存在一些局限性&#xff0c;比如会出现幻觉问题、有时效性问题以及可靠性问题。智能体的定义是具备感知、决策和行动能力的实体。智能体主要由感知部分、大脑部分和动作部分组成。智能体有多种类型&#xff0c;如 ReAct 类型&#xff08;侧重…

5.10.8 Transformer in Transformer

Transformer iN Transformer (TNT)。具体来说&#xff0c;我们将局部补丁&#xff08;例如&#xff0c;1616&#xff09;视为“视觉句子”&#xff0c;并将它们进一步划分为更小的补丁&#xff08;例如&#xff0c;44&#xff09;作为“视觉单词”。每个单词的注意力将与给定视…

智慧党建小程序源码系统 源码全开源支持二次开发 带完整的安装代码包以及搭建部署教程

源码系统概述 智慧党建小程序源码系统是一款基于微信小程序开发的党建管理工具&#xff0c;它集党员管理、党费收缴、活动组织、信息发布等功能于一体&#xff0c;实现了党建工作的全面数字化。该系统采用先进的云计算和大数据技术&#xff0c;支持多平台、多终端访问&#xff…

J-STAGE (日本电子科学与技术信息集成)数据库介绍及文献下载

J-STAGE (日本电子科学与技术信息集成)是日本学术出版物的平台。它由日本科学技术振兴机构&#xff08;JST&#xff09;开发和管理。该系统不仅包括期刊&#xff0c;还有论文集&#xff0c;研究报告、技术报告等。文献多为英文&#xff0c;少数为日文。目前网站上所发布的内容来…

二.基础篇: 面向对象进阶

1. 基础篇语法篇&#xff1a;一.基础篇&#xff1a;基础语法-CSDN博客 面向对象进阶 本章主要学习内容&#xff1a; static继承包&#xff0c;final&#xff0c;权限修饰符&#xff0c;代码块抽象类接口多态内部类 1. static static翻译过来就是静态的意思static表示静态&am…

家用洗地机哪款最好用?附热门洗地机品牌推荐,看完这篇不踩坑

随着技术的不断发展&#xff0c;现在的洗地机功能已经越来越强大了&#xff0c;它可以高效的扫地、拖地、不用手动清洗滚刷&#xff0c;甚至有些中高端型号还能边洗地边除菌&#xff0c;远程操控自清洁&#xff0c;简直就是家居清洁的小能手&#xff01;那么&#xff0c;家用洗…

‘vue-cli-service‘ is not recognized as an internal or external command解决方案

vue-cli-service is not recognized as an internal or external command, operable program or batch file.解决方案 先进行 &#xff1a; npm install -g vue/cli 命令安装vue cli 是必须的。 如果 npm run build 还是报错 遇到同样的提示&#xff1a; 这时候先安装依赖 np…

深入理解与应用C++ Vector

1. C Vector 简介与基本使用 C 的 vector 是一个序列容器&#xff0c;用于表示可变大小的数组。它结合了数组的高效元素访问和动态大小调整的灵活性。与静态数组相比&#xff0c;vector 的大小可以根据需要自动调整&#xff0c;这是通过在底层使用动态数组来实现的。当新元素被…

返回倒数第K个节点(C语言)———链表经典算法题

题目描述​​​​​​&#xff1a;面试题 02.02. 返回倒数第 k 个节点 - 力扣&#xff08;LeetCode&#xff09;&#xff1a; 答案展示: /*** Definition for singly-linked list.* struct ListNode {* int val;* struct ListNode *next;* };*/int kthToLast(struct Li…

娱乐营销的新玩法:Kompas.ai如何让内容更加趣味化

在数字化时代&#xff0c;内容营销已成为品牌与消费者沟通的重要桥梁。然而&#xff0c;随着信息的爆炸式增长&#xff0c;用户的注意力越来越分散&#xff0c;传统的营销方式已经难以吸引用户的兴趣。在这种背景下&#xff0c;娱乐营销应运而生&#xff0c;它通过将娱乐元素融…

2023年30米分辨率土地利用遥感监测数据

改革开放以来&#xff0c;中国经济的快速发展对土地利用模式产生了深刻的影响。同时&#xff0c;中国又具有复杂的自然环境背景和广阔的陆地面积&#xff0c;其土地利用变化不仅对国家发展&#xff0c;也对全球环境变化产生了深刻的影响。为了恢复和重建我国土地利用变化的现代…

R语言:GSEA分析

#安装软件包 > if (!requireNamespace("BiocManager", quietly TRUE)) install.packages("BiocManager") > BiocManager::install("limma") > BiocManager::install("org.Hs.eg.db") > BiocManager::install("…

【回溯 栈 代数系统 动态规划】282. 给表达式添加运算符

本文涉及知识点 回溯 栈 代数系统 动态规划 LeetCode 282. 给表达式添加运算符 给定一个仅包含数字 0-9 的字符串 num 和一个目标值整数 target &#xff0c;在 num 的数字之间添加 二元 运算符&#xff08;不是一元&#xff09;、- 或 * &#xff0c;返回 所有 能够得到 ta…

C++深度解析教程笔记8

C深度解析教程笔记8 第17课 - 对象的构造&#xff08;上&#xff09;类定义中成员变量i和j的初始值&#xff1f;实验-成员变量的初始值对象初始化解决方案1实验-手动调用函数初始化对象对象初始化解决方案2&#xff1a;构造函数实验-构造函数小结 第18课 - 对象的构造&#xff…

File类~路径、创建文件对象

路径分为相对路径&#xff08;不带盘符&#xff09;&#xff0c;绝对路径&#xff08;带盘符&#xff09; 路径是可以存在的&#xff0c;也可以是不存在的 创建文件对象的三个方法&#xff1a;

QT设计模式:策略模式

基本概念 策略模式&#xff08;Strategy Pattern&#xff09;是一种行为型设计模式&#xff0c;它定义了一系列方法&#xff0c;并使它们可以相互替换。策略模式使得算法可以独立于客户端而变化&#xff0c;使得客户端可以根据需要选择相应的算法。 策略模式通常由以下角色组…

使用非官网购买Chatgpt的api调用

测试代码 from openai import OpenAI client OpenAI(api_key用户密钥) import json import os import timeclass ChatGPT:def __init__(self, user):self.user userself.messages [{"role": "system", "content": "Agent"}]def as…

每周一算法:传递闭包

题目描述 不等式排序 给定 n n n个变量和 m m m个不等式。其中 n n n小于等于 26 26 26&#xff0c;变量分别用前 n n n 的大写英文字母表示。 不等式之间具有传递性&#xff0c;即若 A > B A>B A>B 且 B > C B>C B>C&#xff0c;则 A > C A>C …