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…...
利用ngx_stream_return_module构建简易 TCP/UDP 响应网关
一、模块概述 ngx_stream_return_module 提供了一个极简的指令: return <value>;在收到客户端连接后,立即将 <value> 写回并关闭连接。<value> 支持内嵌文本和内置变量(如 $time_iso8601、$remote_addr 等)&a…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
dedecms 织梦自定义表单留言增加ajax验证码功能
增加ajax功能模块,用户不点击提交按钮,只要输入框失去焦点,就会提前提示验证码是否正确。 一,模板上增加验证码 <input name"vdcode"id"vdcode" placeholder"请输入验证码" type"text&quo…...
测试markdown--肇兴
day1: 1、去程:7:04 --11:32高铁 高铁右转上售票大厅2楼,穿过候车厅下一楼,上大巴车 ¥10/人 **2、到达:**12点多到达寨子,买门票,美团/抖音:¥78人 3、中饭&a…...
postgresql|数据库|只读用户的创建和删除(备忘)
CREATE USER read_only WITH PASSWORD 密码 -- 连接到xxx数据库 \c xxx -- 授予对xxx数据库的只读权限 GRANT CONNECT ON DATABASE xxx TO read_only; GRANT USAGE ON SCHEMA public TO read_only; GRANT SELECT ON ALL TABLES IN SCHEMA public TO read_only; GRANT EXECUTE O…...
【Zephyr 系列 10】实战项目:打造一个蓝牙传感器终端 + 网关系统(完整架构与全栈实现)
🧠关键词:Zephyr、BLE、终端、网关、广播、连接、传感器、数据采集、低功耗、系统集成 📌目标读者:希望基于 Zephyr 构建 BLE 系统架构、实现终端与网关协作、具备产品交付能力的开发者 📊篇幅字数:约 5200 字 ✨ 项目总览 在物联网实际项目中,**“终端 + 网关”**是…...
Ascend NPU上适配Step-Audio模型
1 概述 1.1 简述 Step-Audio 是业界首个集语音理解与生成控制一体化的产品级开源实时语音对话系统,支持多语言对话(如 中文,英文,日语),语音情感(如 开心,悲伤)&#x…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
