C++ string模拟实现
一 如何区分自定义类与标准库中的同名类
// string.h
#define _CRT_SECURE_NO_WARNINGS 1
#pragma once
#include<iostream>
using namespace std;namespace bit
{class string{}
}// Test.cpp
include "string.h"int main()
{return 0;
}
既然要模拟实现string底层那就得先理解为什么我写的string和库string里面不会冲突。
1 头文件查找路径
当我们用双引号 ""
包围头文件时,编译器会首先在当前目录下查找这个头文件。这意味着它会优先找到我们自己定义的头文件(比如 string.h
),而不是标准库中的头文件。因为标准库的头文件通常在其他系统目录中,所以不会发生冲突。
2 避免名字冲突
虽然使用双引号包含头文件可以让编译器优先使用我们自定义的头文件,但如果我们在头文件中定义了一个与标准库相同名称的类或函数,仍然可能导致混淆或冲突。
为了解决这个问题,我们可以使用命名空间。命名空间就像是一个独立的区域,把我们的代码和标准库的代码隔离开来。比如,我们创建一个 bit
命名空间,然后在这个命名空间里定义一个与标准库同名的类或函数,这样就可以避免冲突。
当我们在代码中使用这些定义时,需要明确指明是哪个命名空间下的。比如,使用 bit::string
来表示我们自定义的 string
类,而 std::string
则表示标准库中的 string
类。这样编译器就能清楚地区分它们。
二 构造 / 拷贝 / 析构函数
2.1 构造
2.1.1 空字符串构造函数(默认构造函数)
string():_str(new char[1]),_size(0),capacity(0)
{_str[0] = '\0';
}
在std::string
类,空字符串的初始化会创建一个包含单个字符('\0')这个字符用于表示字符串的结束。
那么:_str(new char[1])就是在堆上new一个包含1个char
元素的数组。然后给这唯一的元素赋值'\0'(赋值运算都是在构造函数体内进行)。
2.1.2常量字符串构造函数
string(const char* str)_str(new char[strlen(str)+1])_size(strlen(str))_capasize(strlen(str)){strcpy(_str , str);}
既然要把常量字符串复制过来那么首先要知道它的长度(strlen(str)计算长度不包过'\0'所以要+1),然后让成员变量_str指向堆上新new的空间,空间有了接下俩就可以把字符串复制过来了,而C语言中strcpy函数就是一个很好的选择。从上面代码可以看出来我们多次调用strlen函数来计算字符串长度,可不可以只使用一次,并且将有值构造和默认构造合二唯一?
2.1.3 合并
string(const char* str = " ")_size(strlen(str))
{_str = new char[_size + 1];_capacity = _size;strcpy(_str , str);
}
合并之后它可以同时作为默认构造函数和常量字符串构造函数。我们首先在初始化列表中确定了字符串的长度并初始化了大小和容量,然后在构造函数体中分配适当大小的内存并将字符串复制到新内存中。
2.2 拷贝构造(深拷贝)
// 深拷贝
string(const string& s)
{_str = new char [s.capacity + 1];_size = s._size;_capacity = s._capacity;strcpy(_str , s._str)
}// 浅拷贝
string(const string& s)
{_str = s._str;// 直接复制指针_size = s._size;_capacity = s._capacity;}
回顾一下深拷贝与浅拷贝基本知识内容就基本上懂为什么要写深拷贝而不是以往的浅拷贝
深拷贝:
复制对象时,分配新的内存,并复制指针指向的内容。结果是两个对象各自拥有独立的内存,不会互相影响。
浅拷贝:
复制对象时,仅复制指针,而不复制指针指向的内容。结果是两个对象共享同一块内存,这可能导致一个对象修改数据,另一个对象的数据也被修改,甚至导致双重释放问题(两个对象在析构时都试图释放同一块内存)。
2.3 析构
~string()
{delete[] _str;_str = nullptr;size = 0;capacity = 0;}
讲完了如何初始化那就该讲讲怎么遍历了
三 遍历字符串
遍历字符串有operator[ ] 、迭代器 俩种方式,那现在让我们模拟实现它们吧。
3.1 operator[ ]
重载operator[]
可以让我们像访问数组元素一样访问类的成员变量。
char& operator[](size_t pos)
{assert(pos < _size);return _size[pos]
}
3.2 迭代器
我们一般说迭代器类似指针但是却不是指针
typedef char* iterator;iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}
四 对内容进行修改
4.1 reserve
// 开空间void reserve(size_t n)
{if(n > capacity){char* tmp = new char[n + 1];strcpy(str , tmp);delete[] _str;_str = tmp;capacity = n;}
}
4.2 push_back
// 尾部添加单个字符void push_back(char ch)
{ if(_size == capacity){reserve(capacity == 0 ? 4: capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0'
}
4.3 append
// 尾部添加一个字符串void append(const char* str)
{size_t len = strlen(str);if(len + _size > capacity){reserve(len + _size);}strncpy(_str + _size , str , len);_size += len;
}
operator+=
// 尾插单个字符版string& operator+=(char ch)
{ push_back(ch);return *this;
}// 尾插字符串版string& operator+=(const char* str)
{ append(str);return *this;
}//尾插字符串测试代码int main()
{String str;str += "Hello, " += "world!";
return 0;
}
当执行 str += "Hello, ";
时,编译器会识别出这是 operator+=
操作,并且调用我们为 String
类定义的 operator+=
函数。
在 operator+=
函数内部,this
是一个指向 str
对象的指针。所以在函数内部,this->
和 str.
是等价的。
在 operator+=
函数中,调用了 append(str)
,其中 str
是传入的 C 字符串 "Hello, "
。此时,this
仍然指向 str
对象。
operator+=
返回当前对象的引用 *this
,即 str的引用
。
4.4 insert
//在指定位置插入字符void insert(size_t pos, char ch)
{assert(pos <= _size);if(pos == _capacity){reserve(capacity == 0 ? 4: capacity * 2);}size_t end = _sizewhile(end >= pos){_str[end + 1] = _str[end];--end;}_str[pos] = ch;_size += 1;
}//在指定位置插入字符串void insert(size_t pos, const char* ch)
{assert(pos <= _size);size_t len = strlen(ch);if(_size + len >= _capacity){reserve((_size + len) *2);}size_t end = _size;while(end >= pos){ _str[end + _size] = _str[end];--end;}strncpy(_str + pos , ch , len);_size += len;
}
4.5 erase
// 从指定位置删除指定长度的字符void erase(size_t pos, size_t len = npos)
{ assert(pos < _size);if(len + pos > _size || len == npos){ _str[pos] = '\0';_size = pos;}strcpy(_str + pos , _str + pos + len);_size -= len;
}
当 pos + len
超过了有效数据的总长度时,说明操作已经超出范围,这时候最简单的做法就是从 pos
开始删除后面的所有内容。反之,如果 len
没有超出范围,那么就不需要做任何删除操作。
- 如果没有显式传递
len
参数,它默认会使用npos
作为len
的值。npos
通常表示一个无效位置或者未找到的值,通常等同于-1
(但在size_t
类型中,-1
实际上是一个非常大的正整数)。 - 当
len == npos
时,意味着你没有指定要删除或操作的长度。在这种情况下,函数通常会理解为你希望操作直到字符串的末尾。
4.6 find
// 查找字符size_t find(char ch,size_t pos=0) const
{ assert(pos < _size);for (size_t i = pos; i < _size; i++){if (_str[i] == ch)return i;}return npos;
}// 查找字符串// const 在函数签名后面:表示这个成员函数不能修改所属对象的状态。
size_t find(const char* str, size_t pos = 0) const
{ assert(pos < _size);// 用于查找一个字符串在另一个字符串中的首次出现位置// 找到返回它在 _str + pos 中首次出现的位置;如果未找到,a 将为 nullptr。const char* m = strstr(_str + pos, str);if(a){ return m - _str; //指针减去指针返回它们相差的个数 }else{ return nops; }
}
4.7 substr
// 在原字符串中获取子串string substr(size_t pos = 0, size_t len = npos)
{string Tmp;assert(pos < _size);if(pos + len > _size || len == pos){for(int i = pos; i < _size; i++){// 字符被添加到了 sub 对象所指向的字符串存储空间中,而这个存储空间的指针是 sub 对象的一部分。Tmp += _str[i];}else{for(int i = pos; i < len + pos; i++){sub += _str[i];}}}return Tmp;
}
五 重载函数
5.1 operator=
/ 赋值重载string& operator=(const string& s)
{ char* Tmp = new char[strlen(s._capacity) + 1];strcpy(Tmp , _str);delete[] _str;_size = s._size;_capacity = s._capacity;return *this;
}
5.2 operator==
// 等几个比较函数bool operator==(const string& s1, const string& s2)
{ int m = strcmp(s1._str , s2._str);return m == 0;
}bool operator<(const string& s1, const string& s2)
{int x = strcmp(s1._str , s2._str);return x < 0;
}
5.3 operator<<
// 流插入与提取ostream& operator<<(ostream&out,const string&s)
{for(auto e : s){out << ch;}return out
}
相关文章:

C++ string模拟实现
一 如何区分自定义类与标准库中的同名类 // string.h #define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> using namespace std;namespace bit {class string{} }// Test.cpp include "string.h"int main() {return 0; } 既然要模拟实现str…...

Lora 全文翻译
作者: 地点:hby 来源:https://arxiv.org/pdf/2106.09685 工具:文心 LORA: LOW-RANK ADAPTATION OF LARGE LANGUAGE MODELS 摘要 自然语言处理的一个重要范式包括在通用领域数据上进行大规模预训练,并适应特定任务或…...

结题阶段(2024年8月)
海门区教育科学 “十四五”规划2022年度立项课题 结题鉴定材料 课 题 名 称 高中信息技术项目化教学的研究与应用 课题负责人 郭书艳 所 在 单 位 江苏省包场高级中学 报 送 日 期 2024 年 6 月 20 日…...

贪吃蛇(C语言详解)
贪吃蛇游戏运行画面-CSDN直播 目录 贪吃蛇游戏运行画面-CSDN直播 1. 实验目标 2. Win32 API介绍 2.1 Win32 API 2.2 控制台程序(Console) 2.3 控制台屏幕上的坐标COORD 2.4 GetStdHandle 2.5 GetConsoleCursorlnfo 2.5.1 CONSOLE_CURSOR_INFO …...

国际以太网专线(IEPL)与国际专线(IPLC)服务
中国联通国际公司产品: 国际以太网专线 (IEPL)/国际专线(IPLC) 在全球化的今天,企业越来越依赖于高速、稳定且安全的国际网络连接来支持其跨国业务活动。中国联通国际公司作为中国领先的电信运营商之一,在这一领域提供了多种优质…...

vue 子父组件互相改值
在Vue.js中,子组件想要修改父组件的状态(如数据属性的值)时,通常遵循以下步骤: 父组件向子组件传递数据:通过props(属性)将需要被子组件操作的值传入子组件。例如,在父组…...

java之拼图小游戏(开源)
public class LoginJFrame extends JFrame {//表示登录界面,以后所有跟登录相关的都写在这里public LoginJFrame() {//设置界面的长和宽this.setSize(603,680);//设置界面的标题this.setTitle("拼图登陆界面");//设置界面置顶this.setAlwaysOnTop(true);/…...

Linux Shell批量测试IP连通性
Linux 通过Shell脚本来实现读取txt文件中的IP地址,并使用telnet对其后的所有端口进行测试,判断是否可以连接。每个IP地址的端口测试时间限制为5秒。 IP文件 : ips.txt 192.168.1.1 22,80,443 192.168.1.2 21,25,110 192.168.1.3 8080每一行包含一个IP地…...

已解决:anaocnda如何备份环境与安装环境
1.使用pip进行备份 激活对应的虚拟环境,切换到桌面或者想备份的位置。 备份即可: pip freeze > requirements.txt如何安装备份? pip install -r requirements.txt2.使用conda进行备份 激活对应的虚拟环境,切换到桌面或者想…...

自动化与高效设计:推理技术在FPGA中的应用
想象一下,你正在设计一个复杂的电路系统,就像在搭建一座精巧的积木城堡。你手头有各种形状和功能的积木块,这些积木块可以组合成任何你需要的结构。在这个过程中,你有两种主要的方法:一种是手动挑选和搭建每一块积木&a…...

对react模块和模块化理解
在React开发中,模块化和React模块是两个紧密相关但又有区别的概念。理解它们对于构建高效、可维护的React应用至关重要。 模块化 模块化是一种将大型代码库拆分成更小、更易于管理的部分(即模块)的软件设计技术。每个模块都封装了特定的功能…...

CAN总线-----帧格式
目录 前言 一、CAN总线帧格式分类 1.数据帧(重点) 2.遥控帧 3.错误帧 4.过载帧 5.间隔帧 二、位填充 三、波形实例 前言 本期我们就开始学习CAN总线的帧格式,对应帧格式的话,在前面我们学习I2C协议和SPI协议等协议的时候…...

UE网络同步(一) —— 一个项目入门UE网络同步之概念解释
最近在学习UE网络同步,发现了一个非常好的教程,并且附带了项目文件,这里从这个小项目入手,理解UE的网络同步 教程链接:https://www.youtube.com/watch?vJOJP0CvpB8w 项目链接:https://github.com/awforsyt…...

MATLAB中rsf2csf函数用法
目录 语法 说明 示例 将实数 Schur 形式变换为复数 Schur 形式 rsf2csf函数的功能是将实数 Schur 形式转换为复数 Schur 形式。 语法 [Unew,Tnew] rsf2csf(U,T) 说明 [Unew,Tnew] rsf2csf(U,T) 将实矩阵 X 的 [U,T] schur(X) 的输出从实数 Schur 形式变换为复数 Sc…...

Java基础 文字小游戏
souf System.out.printf("你好啊%s","张三") 输出你好啊张三 System.out.printn()放在中间可以换行 System.out.printf("%s你好啊%s","张三","李四") 输出 张三你好啊李四 只有输出没有换行效果。 制作一个文字小游戏…...

「数组」归并排序 / if语句优化|小区间插入优化(C++)
概述 在上一篇文章中,我们介绍了快速排序以及随机快速排序: 「数组」快速排序 / 随机值优化|小区间插入优化(C) 今天,我们来介绍归并排序。 相比于快速排序是冒泡排序融合了分治思想后形成的究极promax进化版&…...

颠覆传统 北大新型MoM架构挑战Transformer模型,显著提升计算效率
挑战传统的Transformer模型设计 在深度学习和自然语言处理领域,Transformer模型已经成为一种标准的架构,广泛应用于各种任务中。传统的Transformer模型依赖于一个固定的、按深度排序的层次结构,每一层的输出都作为下一层的输入。这种设计虽然…...

接口优化笔记
索引 添加索引 where条件的关键自动或者order by后面的排序字段可以添加索引加速查询 索引只能通过删除新增进行修改,无法直接修改。 # 查看表的索引 show index from table_name; show create table table_name; # 添加索引 alter table table_name add index …...

pandas 科学计数法显示
我注意到pandas中有一个问题, 默认情况下,就是其中的数据的小数位不能超过6位,比如0.0000007就会被显示为0,这个结果如下 全部以科学技术显示 import pandas as pd import numpy as np# 设置显示格式为科学计数法 pd.options.d…...

PHP正则替换字符串中的图片地址
在PHP中,可以使用preg_replace()函数来实现正则表达式的替换功能。以下是一个简单的例子,演示如何替换字符串中的图片地址。 double $str 图片地址1:<img src"http://example.com/image1.jpg"> 图片地址2:<i…...

基于多商户AI智能名片商城小程序的粉丝忠诚度提升策略:深度融合足额法则与多维度激励体系
摘要:在数字化浪潮的推动下,多商户AI智能名片商城小程序以其独特的商业模式和技术优势,正逐步成为连接商家与消费者,特别是粉丝群体的重要平台。本文深入探讨了如何通过深度融合足额法则与多维度激励体系,有效提升多商…...

BigDecimal高精度运算
1. BigDecimal是什么类型,为什么可以转为double BigDecimal 是 Java 中用于表示任意精度的十进制数的类。它主要用于金融和商业计算,能够提供比 double 类型更高精度的运算,特别是在处理货币等需要精确计算的场景中。 1.1 BigDecimal 的基…...

C/C++实现蓝屏2.0
🚀欢迎互三👉:程序猿方梓燚 💎💎 🚀关注博主,后期持续更新系列文章 🚀如果有错误感谢请大家批评指出,及时修改 🚀感谢大家点赞👍收藏⭐评论✍ 前…...

Unity音频管理器插件AudioToolKit
Unity音频管理器插件AudioToolKit 介绍AudioToolKit介绍具体用法总结 介绍 最近在自己写音频管理器的时候在网上发现了一款比较好用并且功能很全的一个音频管理插件,叫做AudioToolKit的插件。 如果需要的可以直接从我资源中找AudioToolKit。 AudioToolKit介绍 A…...

搜维尔科技:驾驶模拟器背后的技术: Varjo的虚拟/混合现实 (VR/XR)提供独特的优势,最终加快汽车开发创新的步伐
专业驾驶模拟器广泛应用于车辆开发,帮助汽车行业在开发过程的早期做出更好的设计决策。总体目标是为测试驾驶员提供最真实的驾驶体验,包括动态动作和声音,并测试控制算法或辅助系统等功能。环境越真实,驾驶员的体验就越接近最终车…...

OSL 冠名赞助Web3峰会 “FORESIGHT2024”圆满收官
OSL 望为香港数字资产市场发展建设添砖加瓦 (香港,2024 年 8 月 13 日)- 8 月 11 日至 12 日, 由 香港唯一专注数字资产的上市公司 OSL 集团(863.HK)冠名赞助,Foresight News、 Foresight Ventu…...

LeetCode 3148.矩阵中的最大得分:每个元素与其左或上元素之差的最大值(原地修改O(1)空间)
【LetMeFly】3148.矩阵中的最大得分:每个元素与其左或上元素之差的最大值(原地修改O(1)空间) 力扣题目链接:https://leetcode.cn/problems/maximum-difference-score-in-a-grid/ 给你一个由 正整数 组成、大小为 m x n 的矩阵 g…...

主流的开源大型语言模型
本期我们来聊聊目前主流的开源大型语言模型。这些模型就像是AI界的超级英雄,各具特色,为我们的研究和开发提供了强大的力量。🚀 GPT-Neo:这是EleutherAI的杰作,它模仿了OpenAI的GPT-3。GPT-Neo虽然规模小一些…...

【自动驾驶】话题通信
目录 构建发布者构建订阅者编写lanch文件自动启动节点测试运行ROS的目录结构 切换到工作空间的src目录下: 构建发布者 catkin_create_pkg publisher std_msgs rospy roscpp编写发布者程序: // 1.包含头文件 #include "ros/ros.h" #include &…...

【Linux】中的软件安装:深入探索RPM、SRPM与YUM
🐇明明跟你说过:个人主页 🏅个人专栏:《Linux :从菜鸟到飞鸟的逆袭》🏅 🔖行路有良友,便是天堂🔖 目录 一、引言 1、Linux的起源与发展 2、RPM、SRPM与YUM的简要介…...