使用柔性数组重写MyString

news2024/11/18 11:30:24

hello,各位宝子,今天阿崽将使用c++和柔性数组的方式重新去写String类

在开始本次知识前,首先给大家介绍下柔性数组这个buff特点:

结构中的柔性数组成员前面至少要包含一个其他成员 sizeof返回的这种结构大小不包括柔性数组的内存 包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以便于适应柔性数组预期的实际大小

感兴趣的宝子可以自己去看看柔性数组详细的内容。

目录

一.MyStirng 结构体设计

二.MyString类

2.1私有属性

2.2构造函数

2.3析构函数

2.4赋值函数

 2.5加法运算符重载(对象)

2.6+=运算符重载

2.7返回某下标元素

2.8改变某下标所对应的元素值


一.MyStirng 结构体设计

struct StrNode
    {
        int ref; // 标识该字符串被几个对象所持有
        int capa;//当前空间大小
        int len;//当前字符串大小
        char data[0]; //柔性数组,存储字符串,因为字符串长度未知所以使用柔型数组的方式
    };

二.MyString类

2.1私有属性

private:
    struct StrNode
    {
        int ref; 
        int capa;
        int len;
        char data[0]; 
    };
    StrNode* pstr;//用该指针去指向我们构造的结构体,因为指针只要四个字节大小(x86)省空间
    StrNode* GetNode(int total) 
    {
        StrNode* s = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * total);
        if (nullptr == s) exit(EXIT_FAILURE);
        return s;
    }//为该结构体开辟空间
    MyString(StrNode* p) :pstr(p) {}//该函数在后面加法运算中详细介绍

2.2构造函数

MyString(const char* p = nullptr) :pstr(nullptr)
    {
        if (p != nullptr)
        {
            int len = strlen(p);//字符串长度,因为后面开辟的空间比字符串本身空间大所以不需要+1
            int total = len * 2;
            pstr = GetNode(total);
            pstr->ref = 1;
            pstr->len = len;
            pstr->capa = total - 1;
            strcpy_s(pstr->data,len+1, p);
        }
    }

 

结果我们通过调试的方式,监视该过程

 

2.3析构函数

~MyString()
    {
        if (pstr != nullptr && --pstr->ref == 0)
        {
            free(pstr);
        }
        pstr = nullptr;
    }

在调用析构函数前有一个非常重要的点就是:当前字符串调用的对象个数,如果只有一个对象持有该字符串,可以直接调用析构函数,但是如果不为1,就说明有多个对象持有该资源,因为无法知道是否析构其他对象,所以我们只需要将ref这个指标减一,因为这些对象所指空间都是一样的,所以最后统一释放该字符串即可

 

2.4赋值函数

MyString& operator=(const MyString& s)  {
        if (this != &s) {
            if (pstr!=nullptr&&--pstr->ref==0) {
                delete[]pstr;
            }
            pstr = s.pstr;
            if (pstr != nullptr) {
                this->pstr->ref++;
            }
        }
        return *this;
    }

在使用赋值函数时(例:MyString s2;s2=s1;)首先要判断自身给自身赋值这个情况,其次要判断s2这个对象本身原来是否有指向字符串空间,并且指向该字符串的对象只有一个时释放该空间,将新的空间通过移动赋值方式直接赋值,然后指标加一。否则让s1中的ptr指向s2中的ptr。如果s2不为空那么指标加一,表示该s2有两个字符串

 

 2.5加法运算符重载(对象)

MyString operator+(const MyString& s) const{
		if (s.pstr == nullptr && this->pstr == nullptr) { return MyString(); }
		if (s.pstr == nullptr && this->pstr != nullptr) return *this;
		if (s.pstr != nullptr && this->pstr == nullptr) return s;
		int len = s.pstr->len + this->pstr->len;
		int total = len * 2;
		StrNode* n = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * total);
		if (nullptr == n) exit(EXIT_FAILURE);
		n->ref = 1;
		n->len = len;
		n->capa = total - 1;
		strcpy_s(n->data,this->pstr->len+1, this->pstr->data);
		strcat_s(n->data, len+2, s.pstr->data);
		return MyString(n);
	}

 加法是一个双目运算符,因为该方法是类中的方法,会有一个this指针所以形参这块只需要一个参数,其次我们要判断我们传进来的两个对象是否为空,对其他三种情况(s为空,this为空;s不为空,this为空;s为空,this不为空)依次进行判断。就到了两者都不为空,开辟一个新的空间依次保存这个两个对象所存储的字符串,注意最后的返回,因为n是结构体指针类型,而我们的构造函数没有这种构造方式,所以在私有属性中再添加一种构造方法:MyString(StrNode* p) :pstr(p) {}这样我们的加法才能运行。

会了这个函数,那么如果参数变为一个对象加一个字符串,一个字符串加一个对象都是同理,我们可以将字符串通过构造函数的方式然后加上对象就行(就是这个函数)

MyString operator+(const char* p, const MyString& s) {
	return MyString(p) + s;
}

2.6+=运算符重载

MyString& operator+=(const char* s) {
		if (this->pstr != nullptr && s != nullptr) {
			if (pstr->ref > 1) {
			    int total = pstr->len + strlen(s);
				int le = pstr->len;
				pstr->ref -= 1;
				char* tmp = pstr->data;
				pstr = GetNode(total);
				pstr->ref = 1;
				pstr->len = total;
				pstr->capa = total * 2;
				strcpy_s(pstr->data, le, tmp);
				strcat_s(pstr->data, total + 1, s);
			}
			else {
				int total = pstr->len + strlen(s);
				if (pstr->capa< total)
				{
					pstr = (StrNode*)realloc(pstr, sizeof(StrNode) + total * 2 + 1);
					pstr->capa = total * 2;
				}
				pstr->len = total;
				strcat_s(pstr->data,pstr->len+1,s);
			}
		}
		else if (this->pstr == NULL && s == NULL)
		{
			pstr = NULL;
			pstr->ref += 1;
		}
		return *this;
	}

 这个函数比较复杂,我们一点点分析。

 首先我们需要判断传进来的两个对象的字符串是否都为空,如果都为空格,空加空还是空的,只要把空字符串的ref指标加一。如果都不为空,我们需要先判断加等对象的字符串是不是只有一个对象所持有,有可能是两个对象都指向“hello”字符串,而加等的对象只有一个,如果直接改变,另外一个也就会随之改变。所以我们使用ref这个指标-1,开辟一个新的空间,将原有的字符串拷贝进去,与他相等的对象不会产生混乱。如果只有一个就很简单,直接开辟新的空间,ref--,将相加的结果赋值给新空间,该对象直接指向新空间。

加等后

考虑到加等后将该对象赋值给另外一个对象,为了不重新调用赋值函数,我们使用引用的方式返回。就可以实现s2=s1+="hello"这个功能。

2.7返回某下标元素

char& operator[](const int index)const {
		if (index<0 || index>this->pstr->len) {
			exit(EXIT_FAILURE);
		}
		return pstr->data[index];
	}

2.8改变某下标所对应的元素值

	void revise(const int index, char p) {
		if (index<0 || index>this->pstr->len||this->pstr==nullptr) {
			exit(EXIT_FAILURE);
		}
		pstr->data[index] = p;
	}

这里我想的比较简单就是先判断下标元素是否正确后,然后直接改变,并没有考虑到原先持有该空间的对象个数,所以感兴趣的宝子们可以自行写下。

今天就更到这里啦,等我把这个MyString类的所有方式全部写完再与各位宝子分享。

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

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

相关文章

不想打工做什么好呢?厌倦打工的不妨试试以下几种赚钱方式

除开一些比较幸运的人&#xff0c;谁不是一边打工养家&#xff0c;一边在找寻好机会&#xff1f;人与人之间本来就存在诸多的不公平。有的人这辈子只能靠打工养家&#xff0c;只有少数人能不靠打工来挣钱养家&#xff0c;但是这极少部分人凭什么是你&#xff1f; 现在社会上&am…

( 数组) 209. 长度最小的子数组——【Leetcode每日一题】

❓209. 长度最小的子数组 难度&#xff1a;中等 给定一个含有 n 个正整数的数组和一个正整数 target 。 找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl1, ..., numsr-1, numsr] &#xff0c;并返回其长度。如果不存在符合条件的子数组&#xff0c;…

【ArcGIS Pro二次开发】(30):数据定义语言DDL详解

在之前的文章【ArcGIS Pro二次开发】(19)&#xff1a;创建要素类&#xff08;FeatureClass&#xff09;中有涉及DDL的知识点&#xff0c;随着深入的学习&#xff0c;在这里做一个小总结。 一、DDL基本概念 ArcGIS Pro二次开发中的DDL API是一种【数据定义语言】&#xff0c;主…

【Web服务器集群】Web基础与HTTP协议

文章目录 一、Web基础1.域名概述1.1域名的概念1.2域名解析1.3域名空间结构 2.域名注册3.网页的概念4.HTML概述4.1HTML概念4.2HTML文档的结构 5.网页基本标签6.Web概述7.静态网页与动态网页7.1静态网页7.2动态网页7.3动态网页语言 二、HTTP协议1.概念2.HTTP协议的版本3.HTTP方法…

pytest+requests+Python3.7+yaml+Allure+Jenkins+docker实现接口自动化

目录 接口自动化测试框架&#xff08;用例自动生成&#xff09; 项目说明 技术栈 环境部署 框架流程图与目录结构图及相关说明 1、框架流程图如下 2、代码目录结构图如下 关联详解 函数助手详解 代码设计与功能说明 1、定义运行配置文件 runConfig.yml 2、接口配置…

构建系统安全防线!Genmai安全漏洞检测框架全面解析

01 Genmai是什么&#xff1f; Genmai是由openkylin社区SecurityGovernance SIG为了挖掘、检测、验证麒麟产品的安全漏洞而主导开发的一款开源主机漏洞扫描、网络漏洞扫描以及基线扫描的安全扫描框架。其致力于能在短时间内对主流的操作系统进行安全检测&#xff0c;并确保准确…

Unity3D :使用 UXML 实例作为模板

推荐&#xff1a;将 NSDT场景编辑器 加入你的3D工具链 3D工具集&#xff1a; NSDT简石数字孪生 使用 UXML 实例作为模板 您可以将现有 UXML 文档实例化为 UXML 文档中的模板作为模板实例&#xff0c;类似于预制件 在 Unity 中工作。 使用 UXML 文档作为模板 要将项目中的现有…

「API 接口获取方法」

在创建一个应用程序的过程中&#xff0c;获取数据是非常关键的一步。而通过API接口获取数据通常是最好的方式之一。那么&#xff0c;如何通过关键字获取API接口呢&#xff1f;以下是一些步骤&#xff1a; 1.确定你需要获取的数据类型 首先&#xff0c;你需要确定你需要获取的…

深入浅出 SQL Server CDC 数据同步

简介 SQL Server 是一款老牌关系型数据库,自 1988 年由 Microsoft、Sybase 和 Ashton-Tate 三家公司共同推出&#xff0c;不断迭代更新至今&#xff0c;拥有相当广泛的用户群体。 如今&#xff0c;我们提到 SQL Server 通常指 Microsoft SQL Server 2000 之后的版本。 SQL S…

软件测试的7个级别,做到3级已经超越80%测试人!

有人说&#xff1a;软件测试就是最low的点点点工作。 有人说&#xff1a;测试工作职位薪水到一定程度只能原地踏步无法提升 也有人说&#xff1a;测试行业相对于开发来说技术性很低&#xff0c;容易被取代。 这其实是对测试行业最大的误解。测试可深可浅&#xff0c;可窄可广…

linux嵌入式学习

https://www.runoob.com/linux/linux-comm-ls.html https://www.bilibili.com/video/BV1w4411B7a4?p19&spm_id_frompageDriver&vd_sourcee7d12c9f66ab8294c87125a95510dac9 1 eMMC eMMC&#xff08;embedded MultiMediaCard&#xff09;是一种集成电路&#xff0c;用…

vue2+wangeditor富文本域

vue2wangeditor富文本域 效果图安装依赖初始化简约模式自定义模式图片设置只允许 base64 方式支持图片服务器 更多配置项目依赖项目代码 效果图 安装依赖 npm i wangeditor/editor wangeditor/editor-for-vue初始化 <template><div class"editor-box">…

IIS 日志解析,增强 IIS 服务器安全性

企业严重依赖 Microsoft Internet 信息服务 &#xff08;IIS&#xff09; 服务器来托管其网页和 Web 应用程序&#xff0c;以及存储其文件。请务必妥善保护您的 IIS 服务器&#xff08;包括 Web 和 FTP&#xff09;。 什么是 IIS 日志 IIS 日志是 Microsoft IIS Web 服务器上…

柔顺机构学读书笔记1:悬臂梁变形

题目&#xff1a; 如图考虑悬臂梁&#xff0c;材料各向同性&#xff0c;即各个方向上的弹性模量和强度都相同。如果在x方向上作用一个可使最大应力等于屈服强度 S S S的力 F x F_x Fx​时&#xff0c; x x x轴方向的变形为多少&#xff0c;书上给出了答案&#xff1a; 我们来验…

网易有道财报:网易有道2023财年收入将强劲增长,亏损将减少?

来源&#xff1a;猛兽财经 作者&#xff1a;猛兽财经 预计2023年收入增长强劲&#xff0c;净亏损收窄 猛兽财经认为网易有道&#xff08;DAO&#xff09;今年是有能力实现更多的收入增长和减少亏损的。具体来说&#xff0c;我们预计网易有道的收入将在2023财年增长至少20%&am…

Semantic Kernel VS LangChain

每当向他人介绍 Semantic Kernel&#xff0c;会得到的第一个问题就是 Semantic Kernel 类似于 LangChain 吗&#xff1f;或者是 C# 版本的 LangChain 吗&#xff1f;因此我总结了这篇文章。 微软MVP实验室研究员 张善友 深圳友浩达 CTO & 首席架构师&#xff0c;微软最有价…

进程间通信-system V共享内存

文章目录 1. system V共享内存1.1 共享内存示意图 2. 共享内存函数2.1 shmget函数2.2 代码实现2.2.1 shmat2.2.2 shmdt 3. 信息量 1. system V共享内存 system V的意思是一套标准&#xff0c;共享内存区是最快的IPC形式。一旦这样的内存映射到共享它的进程的地址空间&#xff…

AI遇上建筑设计,是出圈还是翻车?

AIGC 落地&#xff0c;始于场景&#xff0c;终于价值。 去年以来出现了 AIGC 热潮&#xff0c;引发了 AIGC 及其应用话题的爆发性增长&#xff0c;不少人感慨强人工智能的时代已经离我们不那么遥远了。但是在热潮的另一面&#xff0c;我们看到真正能落地的场景依然是凤毛麟角&a…

【C语言】结构体指针

结构体指针 结构体基础知识注意对于成员的赋值 结构体指针指向结构体变量的指针结构体指针与结构体成员指针用结构体指针引用结构体成员 结构体 基础知识 初识结构体&#xff0c;可以先看这篇浅显易懂的文章结构体–基础篇 所谓结构体&#xff0c;是一组类型可以不同的相关变…

部署输配电线路火灾隐患排查治理

输电线路防山火在线监测装置 一、产品描述&#xff1a; 电力设施为了远离人们的生活区域选择部分扎根在森林里面&#xff0c;减少发生触电事故的发生。但是提到森林就不得不说其中一个山火问题&#xff0c;山火灾害对建设在森林的电力设施造成的损害不可预估&#xff0c;为保障…