当前位置: 首页 > news >正文

手撕string

目录

引言

1,成员变量

2,先建一个可以跑的

2_1,构造函数

2_2, 扩容函数reserve

2_3,push_back

2_4,append[ ]

2_5,operator << 

2_6,测试一下,看猪跑

3,默认成员函数

3_1,拷贝构造函数

3_2, 赋值运算符重载

3_3,析构函数

4,string 里的便利操作

4_1,operator[ ]

4_2,operator +=

4_3,迭代器 iterator/const_iterator + begin() / end()

4_4,测试一下

5,完善功能

5_1,Member constants : npos

5_2,find

5_3,substr

5_4,insert

5_5,erase

5_6,resize

5_7,测试一下

6,信息获取功能一锅端

6_1,size

6_2,capacity

6_3,c_str

6_4,empty

6_5,clear

7,string 比较一锅端

8,operator >>  输入

补充说明

string 里的隐式类型的转换

不足

结束语

革命尚未成功,同志仍须努力


引言

前面已经学习了c++的基础知识,这一期就带领大家来手撕string。废话不多说,现在就开始吧。

1,成员变量

一个类最主要的部分莫过于成员变量了,那该怎么设计类string的成员变量勒?

string是对字符类型有着非常便捷的一系列操作的类,所以我们用 char* _str 来作为第一个成员变量,通过对其进行扩容等一系列操作,就可以非常灵活的控制其大小,不会浪费空间的同时也可以灵活变通可大可小,说到扩容,那就必然少不了int _size,  int _capacity 俩件套。

这里解释一下为什么要在成员变量前加 “ _ ",仅仅是为成员变量加上一个” 身份标签 “,使我们在其他场合下能够区分成员变量,当然哈,在成员变量前加 “ _ "是我的习惯,在后面加也是可以的。

2,先建一个可以跑的

2_1,构造函数

在使用过程中,我们通常是用一个字符或者一个字符串来定义string的对象。

那么我们可以把参数设置成一个字符串,并给出一个缺省值空串。根据咱们传的参数给_str进行相对应的扩容(用new即可),然后再把参数的内容拷贝到 _str 里就 ok 了。

2_2, 扩容函数reserve

在后续添加字符的时候扩容是少不了的,接下来就来实现  reserve  函数。参数给定一个 len,reserve 将其_capacity 扩大到  len。

那再扩容函数里面是不是要用 realloc 呢?realloc 分为原地扩容和异地扩容,咱们都到c++了,咱们就用 new。

开好空间后将_str 的数据拷贝过去,delete[ ] 掉_str 原有的数据,再把其赋值给 _str。

2_3,push_back

尾插一个字符,先判断是否需要扩容,再尾插,记得_size++ 和 ' \0 '

2_4,append[ ]

追加一个字符串,先判断是否需要扩容,再追加,记得_size++ 和 ' \0 '

2_5,operator << 

目前咱们有了构造函数,有了添加操作,再来一个打印函数,咱们就可以看见猪跑了。

但是勒,这个 operator << 不能放在类里面,因为operator << 的左操作数会被 this 侵占。所以我们定义到类外面,再使用友元进行访问,

2_6,测试一下,看猪跑

从打印的结果上来看,目前咱们的代码是没有太大问题的

3,默认成员函数

3_1,拷贝构造函数

3_2, 赋值运算符重载

这里给大家介绍两种写法

3_3,析构函数

4,string 里的便利操作

4_1,operator[ ]

在字符串/字符数组中,[ ] 用着贼香,string 也应该有一个,咱们就来重载一个

要注意哈 访问一个, 修改一个

4_2,operator +=

虽然前面有了 push_back 和 append 但是频繁调用也很麻烦, += 应运而生,但是勒,咋没没有必要再写一遍,我们再 operator += () 里面调用 push_back 或者 append 函数即可,增加代码的复用性。

4_3,迭代器 iterator/const_iterator + begin() / end()

这里的迭代器本质就是 char* / const char* 啦,直接typedef一下。

有了迭代器,咱们就可以使用范围 for ,上面的 operator << 就可进行改善啦

4_4,测试一下

从打印的结果上来看,目前咱们的代码是没有太大问题的

5,完善功能

5_1,Member constants : npos

类外面进行初始化

使用过  string::find  的都知道,当没有找到的时候返回的是 npos 那么npos 是什么呢?

其实 npos 是一个公共静态成员变量(一般是 size_t 类型),表示该类型的最大值,主要作用是,查找操作的失败标记,或者是表示字符串末尾。在类外使用的时候要带上域作用限定符。

5_2,find

可以借助<string.h> 中的 strstr 函数帮助我们查询,但是要注意 strstr 找到返回的是指针,没找到返回NULL.

我们可以根据返回的指针和  begin( ) 做减法,就可以得到下标啦

5_3,substr

5_4,insert

在数据挪动的时候特别容易出错,一定要注意。

5_5,erase

在数据挪动的时候特别容易出错,一定要注意。

5_6,resize

resize的功能我们来复习一下,主要功能: 改变 _size 。

传入一个数 n 和 一个字符 c

如果 n <= _size ,就缩小size 并将多余的数据删除

如果 n > _size,就增加 _size 并 初始化

5_7,测试一下

ok的呀

6,信息获取功能一锅端

这些都比较简单直接上代码

6_1,size

6_2,capacity

6_3,c_str

6_4,empty

6_5,clear

7,string 比较一锅端

字符串的比较是按照字典序来比较的

一定要注意啊,比较咱们是不能用 strcmp 的,因为 strcmp 遇见 ' \0 ' 就停止了,而string 的对象中间可能会夹杂着 ' \0 ';

有了俩个之后,后面就不用写了,直接复用就ok了


8,operator >>  输入

输入就比输出麻烦太大了,输入了,咱们要先清空要输入的对象里面的原始数据,也需要解决前导空格的问题,而且还要保证效率......

istream& operator>>(istream& in, ssy::string& s)
{
	s.clear();  //输入,会对之前的数据进行删除
	char ch = in.get();
	//跳过前导无用的空格
	while (ch == ' ' || ch == '\n')
	{
		ch = in.get();
	}

	char buff[128];
	int i = 0;
	while (ch != ' ' && ch != '\n')
	{
		buff[i++] = ch;   //为了防止扩容太频繁,借助buff数组
		if (i == 127)
		{
			buff[i] = '\0';
			s += buff;
			i = 0;
		}
		ch = in.get();
	}

	if (i != 0)
	{
		buff[i] = '\0';
		s += buff;
	}

	return in;
}

输入测试:

补充说明

string 里的隐式类型的转换

在 append / push_back 我们分别写出了尾插一个字符/字符串。

而在插入 insert 和 find 函数里面我们没有去区分 单个字符和字符串,因为无论我们传参传的是单个字符还是一个字符串,单参数的构造函数支持隐式类型的转换,它都会被转换成 string 类型。

不足

虽然咱们手撕了一个 string 但是 咱们撕的只能说是一个简易版,我只是把 string 里面常用,经典的函数带着大家手撕了一下,库里面的 string 的功能是非常强大的,而且每个函数都有多种重载。

所以说,咱们手撕的还是会有很多功能做不到的,例如 

ssy :: string s1(ssy);

ssy :: string s2(666);

s1 += s2;

咱们的 operator +=  是不支持 对象间的 += 的。

结束语

大家可以通过这篇博客感受一下string 的创建,也可以继续完善咱们自己的string

革命尚未成功,同志仍须努力

http://www.dtcms.com/a/99017.html

相关文章:

  • 【C#】ForEach vs foreach
  • swift-7-汇编分析闭包本质
  • 蓝桥杯省赛 棋盘 3533 二维差分+二维前缀和
  • Ruoyi-Vue拆解:优雅实现Vue页面过渡动画
  • 消息队列篇--通信协议篇--SSL/TLS协议
  • 【教学类-58-16】黑白三角拼图14——黑白三角图连接部分的白线(2*2宫格)
  • AI大模型底层技术——Multi-LoRA Combination Methods
  • 【免费】2007-2019年各省地方财政科学技术支出数据
  • leetcode 2360 图中最长的环 题解
  • 明天该穿哪件内衣出门?
  • 数据结构(并查集,图)
  • pip install cryptacular卡住,卡在downloading阶段
  • 嵌入式硬件篇---嘉立创PCB绘制
  • 【密码学】一文了解密码学的基本
  • 爱普生FC-135晶振5G手机的极端温度性能守护者
  • Ditto-Talkinghead:阿里巴巴数字人技术新突破 [特殊字符]️
  • Vue3组件响应式优化方法
  • Visual Studio 2022静态库与动态库创建及使用完全指南
  • Gerbv 与 Python 协同:实现 Gerber 文件智能分析与制造数据自动化
  • 知能行每日综测
  • vue.js前端条件渲染指令相关知识点
  • AI 时代,我们该如何写作?
  • MySQL———作业实验
  • Java进阶
  • 记录vite引入sass预编译报错error during build: [vite:css] [sass] Undefined variable.问题
  • MySQL的基础语法1(增删改查、DDL、DML、DQL和DCL)
  • HTML5 Web SQL 数据库学习笔记
  • 通信之光纤耦合器
  • cookie详解
  • comp2123 RangeFunc matrix