使用柔性数组重写MyString

这篇具有很好参考价值的文章主要介绍了使用柔性数组重写MyString。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

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);
        }
    }

使用柔性数组重写MyString

 

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

使用柔性数组重写MyString

 

2.3析构函数

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

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

使用柔性数组重写MyString

 

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有两个字符串

 使用柔性数组重写MyString使用柔性数组重写MyString

 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

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

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;
	}

使用柔性数组重写MyString

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

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

使用柔性数组重写MyString

加等后

使用柔性数组重写MyString

考虑到加等后将该对象赋值给另外一个对象,为了不重新调用赋值函数,我们使用引用的方式返回。就可以实现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类的所有方式全部写完再与各位宝子分享。文章来源地址https://www.toymoban.com/news/detail-486478.html

到了这里,关于使用柔性数组重写MyString的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包赞助服务器费用

相关文章

  • 动态内存管理、柔性数组

    动态内存管理、柔性数组

    我们已经掌握的内存开辟的方式: 上面开辟的空间大小是固定不可变的 数组申请的大小也是确定了之后就不能改变 这里就引入了动态内存的开辟,可以根据内存的需要进行更改  malloc和free malloc的功能是申请size个连续可用 size_t类型的字节 空间,并返回指向这块空间的void

    2024年02月22日
    浏览(6)
  • 超详细——动态内存分配+柔性数组

    超详细——动态内存分配+柔性数组

    ☃️个人主页:fighting小泽 🌸作者简介:目前正在学习C语言和数据结构 🌼博客专栏:C语言学习 🏵️欢迎关注:评论👊🏻点赞👍🏻留言💪🏻 我们已经学会的内存开辟方式有:创建一个变量,创建一个数组 我们创建一个整形变量就会申请4个字节,创建个数组就会申请

    2023年04月15日
    浏览(6)
  • C语言探索旅程之【柔性数组】

    目录 1. 柔性数组的定义 2. 柔性数组的使用 3. 柔性数组的注意事项 4. 柔性数组的优点 5. 柔性数组的应用场景 当我们谈到C语言中的柔性数组时,我们指的是一种特殊的数组,其大小在运行时动态确定,而不是在编译时确定。柔性数组是C语言中一种非常有用且灵活的特性,特

    2024年03月22日
    浏览(5)
  • 柔性数组和C语言内存划分

    柔性数组和C语言内存划分

    也许你从来没有听说过 柔性数组 (flexible array)这个概念,但是它确实是存在的。 C99 中,结构中的最后⼀个元素允许是未知大小的数组,这就叫做『柔性数组』成员。 例如: 有些编译器会报错⽆法编译可以改成: 1.1 柔性数组的特点: 结构中的柔性数组成员前面必须至少⼀

    2024年01月22日
    浏览(7)
  • Redis(一)原理及基本命令(柔性数组)

    Redis(一)原理及基本命令(柔性数组) Redis(二)网络协议和异步方式(乐观锁悲观锁) Redis(三)存储原理与数据模型(hash冲突、渐进式rehash) Redis跳表 Redis 是 Remote Dictionary Service 的简称,被称为远程字典服务;redis客户端和服务端是基于TCP建立网络通信的。 Redis 是内存

    2024年02月16日
    浏览(6)
  • C语言柔性数组详解:让你的程序更灵活

    C语言柔性数组详解:让你的程序更灵活

    仔细观察下面的代码,有没有看出哪里不对劲? 还有另外一种写法: 你应该一眼就看到了,结构体的最后一个成员数组的写法是 int arr[]; 或者是 int arr[0] ,这两种写法是等价的,意思是这个数组的大小是 不确定的、未知的、可以变化的 。 C99允许这种特殊的结构体存在。这

    2024年02月09日
    浏览(5)
  • 椋鸟C语言笔记#31:结构体(联合体)嵌套、柔性数组

    萌新的学习笔记,写错了恳请斧正。 目录 结构体(联合体)嵌套 嵌套时内嵌结构体(联合体)不创建变量(匿名) 嵌套时内嵌结构体(联合体)创建变量(非匿名) 嵌套初始化 柔性数组 柔性数组的使用 结构体(联合体)嵌套 结构体、联合体可以嵌套,也就是说结构体(

    2024年02月02日
    浏览(8)
  • 【C语言】动态内存管理(malloc,free,calloc,realloc,柔性数组)

    【C语言】动态内存管理(malloc,free,calloc,realloc,柔性数组)

    本章重点 为什么存在动态内存管理 动态内存函数的介绍 malloc free calloc realloc 常见的动态内存错误 几个经典的笔试题 柔性数组 我们已经掌握的内存开辟方式有: int val = 20; //在栈空间上开辟四个字节 char arr[10] = {0}; 在栈空间上开辟十个字节的连续空间 但是上述开辟空间的方

    2024年02月03日
    浏览(5)
  • C语言——动态内存管理(malloc, calloc, realloc, free, 柔性数组详解)

    C语言——动态内存管理(malloc, calloc, realloc, free, 柔性数组详解)

    我们以往定义数组,都是这么定义的: 以这种方式开辟空间有两个特点: 空间开辟的大小是固定的 数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配 因此就导致了这样一个现象:我们无法在后续的过程中修改数组的大小,这是一个十分麻烦的事情 而

    2024年02月16日
    浏览(5)
  • 【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)

    【C进阶】分析 C/C++程序的内存开辟与柔性数组(内有干货)

            本文是对于动态内存管理知识后续的补充,以及加深对其的理解。对于动态内存管理涉及的大部分知识在这篇文章中 ---- 【C进阶】 动态内存管理_Dream_Chaser~的博客-CSDN博客         本文涉及的知识内容主要在两方面: 简单解析C/C++程序的内存开辟 分析柔性数组

    2024年02月09日
    浏览(7)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包