探索C嘎嘎的奇妙世界:第十四关---STL(string的模拟实现)
1. string类的模拟实现
1.1 经典的string类问题
// 为了和标准库区分,此处使用String
class String
{
public:/*String():_str(new char[1]){*_str = '\0';}*///String(const char* str = "\0") 错误示范//String(const char* str = nullptr) 错误示范String(const char* str = ""){// 构造String类对象时,如果传递nullptr指针,可以认为程序非if (nullptr == str){assert(false);return;}_str = new char[strlen(str) + 1];strcpy(_str, str);}~String(){if (_str){delete[] _str;_str = nullptr;}}
private:char* _str;
};
// 测试
void TestString()
{String s1("hello bit!!!");String s2(s1);
}
1.2 浅拷贝
1.3 深拷贝

2.string各类主要接口的模拟实现
2.1 迭代器
string.h:typedef char* iterator;typedef const char* const_iterator;iterator begin();//迭代器起始位置iterator end();//迭代器const_iterator begin()const;const_iterator end()const;string.cpp:string::iterator string::begin(){return _str;}string::iterator string::end(){return _str + _size;}string::const_iterator string::begin()const{return _str;}string::const_iterator string::end()const{return _str + _size;}
上述代码中定义了一个类`string`,该类具有`begin()`和`end()`函数,用于返回迭代器对象。
迭代器是一种用于遍历容器元素的对象。迭代器将容器中的元素组织起来,以便可以按顺序访问它们。
在`string.h`中,`typedef char* iterator;`和`typedef const char* const_iterator;`定义了两种迭代器类型,分别用于可变和常量的字符串。
`string::begin()`和`string::end()`函数分别返回迭代器的起始位置和结束位置。
在`string.cpp`中,`string::begin()`和`string::end()`函数被实现。`string::begin()`函数返回字符串的起始位置,即指向第一个字符的指针。`string::end()`函数返回字符串的结束位置,即指向最后一个字符后面的位置的指针。
`string::begin()const`和`string::end()const`函数是常量成员函数,用于返回常量字符串的迭代器的起始位置和结束位置。
通过使用这些迭代器,可以在循环中遍历字符串中的每个字符,并执行相应的操作。
2.2 size、c_str、运算符[ ]的重载、构造函数以及析构函数
string.h:string(const char* str = "");~string();size_t size()const;const char* c_str()const;char& operator[](size_t pos);const char& operator[](size_t pos)const;string.cpp:string::string(const char*str):_size(strlen(str)){_str=new char[_size+1];_capacity = _size;strcpy(_str, str);}string::~string(){delete[] _str;_str = nullptr;_capacity = _size = 0;}size_t string::size()const{return _size;}const char* string:: c_str()const{return _str;}char& string:: operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& string:: operator[](size_t pos)const{assert(pos < _size);return _str[pos];}
上述代码中定义了一个类`string`,该类包含了几个常用的字符串相关函数。
在`string.h`中,构造函数`string(const char* str = "")`用于创建一个字符串对象。析构函数`~string()`用于销毁字符串对象并释放内存。`size_t size()const`函数用于返回字符串的长度`const char* c_str()const`函数用于返回字符串的C风格字符数组。
`char& operator[](size_t pos)`和`const char& operator[](size_t pos)const`函数分别用于访问字符串中指定位置的字符。`operator[]`函数设计为“下标运算符重载”,允许使用类似数组下标的方式来访问字符串中的字符。
在`string.cpp`中,构造函数`string::string(const char* str)`用于根据传入的C风格字符串创建一个新的字符串对象。函数内部首先计算传入的字符串的长度,然后动态分配空间并复制字符串内容。析构函数`string::~string()`用于释放字符串所占用的内存。`size_t string::size()const`函数返回字符串的长度。`const char* string::c_str()const`函数返回指向字符串的C风格字符数组的指针。
`char& string::operator[](size_t pos)`和`const char& string::operator[](size_t pos)const`函数实现了通过下标访问字符串中特定位置字符的功能。函数内部使用断言`assert`来确保访问的位置在有效范围内。
通过使用这些函数,可以方便地创建、访问和操作字符串对象。
2.3 reserve、push_back、append以及运算符+=重载
string.h:void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char*str);string.cpp:void string::reserve(size_t n)//保留空间{if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_capacity = n;}}void string::push_back(char ch)//尾插字符{if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;_str[_size + 1] = '\0';_size++;}void string::append(const char* str)//尾插字符串{size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(char ch){push_back(ch);return *this;}string& string::operator+=(const char* str){append(str);return *this;}
在上述代码中定义了一些用于修改字符串对象的函数。
在`string.h`中,`void reserve(size_t n)`函数用于保留至少能容纳n个字符的空间。`void push_back(char ch)`函数在字符串的末尾插入一个字符。`void append(const char* str)`函数在字符串的末尾插入一个C风格的字符数组。`string& operator+=(char ch)`函数用于在字符串末尾添加一个字符,并返回修改后的字符串对象的引用。`string& operator+=(const char* str)`函数用于在字符串末尾添加一个C风格的字符数组,并返回修改后的字符串对象的引用。
在`string.cpp`中,`void string::reserve(size_t n)`函数用于在需要的情况下扩展字符串的容量。如果n大于当前容量,它将创建一个新的更大的字符数组,并将原字符串的内容复制到新的数组中。然后释放原来的字符数组,并将指针指向新的数组,同时更新容量变量。`void string::push_back(char ch)`函数在字符串的末尾插入一个字符。如果字符串当前的大小已经等于容量,则先扩展容量,然后插入字符。`void string::append(const char* str)`函数在字符串的末尾插入一个C风格的字符数组。如果插入后的长度超过容量,则先扩展容量,然后将字符数组的内容复制到字符串中。`string& string::operator+=(char ch)`函数利用`push_back()`函数在字符串末尾添加一个字符,并返回修改后的字符串对象的引用。`string& string::operator+=(const char* str)`函数利用`append()`函数将C风格的字符数组添加到字符串末尾,并返回修改后的字符串对象的引用。
通过使用这些函数,可以方便地修改字符串对象,包括扩展容量、在末尾插入字符和字符数组等操作。
2.4 insert、erase以及find
string.h:void insert(size_t pos, char ch);void insert(size_t pos, const char*str);void erase(size_t pos=0, size_t len = npos);size_t find(char ch, size_t pos=0);size_t find(const char*str, size_t pos=0); string.cpp:void string::insert(size_t pos, char ch){assert(pos <= _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2;reserve(newcapacity);}//memmove(_str + pos + 1, _str + pos, sizeof(char) * (_size - pos + 1));//法一size_t end = _size+1;//法二while (end > pos){_str[end] = _str[end-1];end--;}_str[pos] = ch;_size++;}void string::insert(size_t pos, const char* str){assert(pos <= _size);size_t len = strlen(str);if (_size+len > _capacity){reserve(_size+len);}//memmove(_str + pos + len, _str + pos, sizeof(char) * (_size - pos + 1));//法一size_t end = _size+len;//法二while (end >pos+len-1){_str[end] = _str[end-len];end--;}memcpy(_str + pos, str, len);_size+=len;}void string::erase(size_t pos, size_t len){assert(pos < _size);if (len >= _size-pos){_str[pos] = '\0';_size = pos;}else{strcpy(_str + pos, _str + pos + len);_size -= len;}}size_t string::find(char ch, size_t pos){for (size_t i = pos; i < _size; i++){if (_str[i] == ch)return i;}return npos;}size_t string::find(const char* str, size_t pos){char* p = strstr(_str + pos, str);return p - _str;}
在上述代码中定义了一些用于在字符串对象中查找和修改字符的函数。
在`string.h`中,`void insert(size_t pos, char ch)`函数在指定位置插入一个字符。`void insert(size_t pos, const char* str)`函数在指定位置插入一个C风格的字符数组。`void erase(size_t pos=0, size_t len=npos)`函数从指定位置开始,删除指定长度的字符。`size_t find(char ch, size_t pos=0)`函数从指定位置开始,查找字符在字符串中第一次出现的位置。`size_t find(const char* str, size_t pos=0)`函数从指定位置开始,查找一个C风格的字符数组在字符串中第一次出现的位置。
在`string.cpp`中,`void string::insert(size_t pos, char ch)`函数在指定位置插入一个字符。如果字符串的大小已经等于容量,则先扩展容量,然后将插入位置后的字符依次后移,并将指定位置处的字符替换为插入的字符。`void string::insert(size_t pos, const char* str)`函数在指定位置插入一个C风格的字符数组。如果插入后的长度超过容量,则先扩展容量,然后将插入位置后的字符依次后移,并将指定位置处的字符替换为插入的字符数组中的字符。`void string::erase(size_t pos, size_t len)`函数从指定位置开始,删除指定长度的字符。如果删除的长度大于等于从指定位置到字符串末尾的长度,则将指定位置处的字符设为'\0',并更新字符串的大小。否则,将删除位置后的字符依次前移,覆盖被删除的字符,并更新字符串的大小。`size_t string::find(char ch, size_t pos)`函数从指定位置开始,在字符串中查找字符第一次出现的位置。遍历字符串中从指定位置开始的字符,如果找到与目标字符相同的字符,则返回该位置的索引。如果没有找到,返回`npos`。`size_t string::find(const char* str, size_t pos)`函数从指定位置开始,在字符串中查找一个C风格的字符数组第一次出现的位置。利用`strstr()`函数找到指定字符数组在字符串中的地址,并计算地址和字符串的地址差值,即为指定字符数组第一次出现的位置的索引。
通过使用这些函数,可以方便地在字符串对象中插入、删除和查找字符和字符数组。
2.5 swap、substr以及运算符< > <= >= == !=的重载
string.h:void swap(string& s);string substr(size_t pos = 0, size_t len = npos);bool operator<(const string& s) const;bool operator>(const string& s) const;bool operator<=(const string& s) const;bool operator>=(const string& s) const;bool operator==(const string& s) const;bool operator!=(const string& s) const;string.cpp:void string::swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}string string::substr(size_t pos, size_t len){// len大于后面剩余字符,有多少取多少if (len > _size - pos){string sub(_str + pos);return sub;}else{string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}}bool string::operator<(const string& s) const{return strcmp(_str, s._str) < 0;}bool string::operator>(const string& s) const{return !(*this <= s);}bool string::operator<=(const string& s) const{return *this < s || *this == s;}bool string::operator>=(const string& s) const{return !(*this < s);}bool string::operator==(const string& s) const{return strcmp(_str, s._str) == 0;}bool string::operator!=(const string& s) const{return !(*this == s);}
在上述代码中实现了一些额外的功能和操作符重载。
- `void swap(string& s)`:交换当前字符串和参数字符串的内容、大小和容量。
- `string substr(size_t pos = 0, size_t len = npos)`:返回从指定位置开始的子字符串。
- `bool operator<(const string& s) const`:重载小于操作符,判断当前字符串是否小于参数字符串。
- `bool operator>(const string& s) const`:重载大于操作符,判断当前字符串是否大于参数字符串。
- `bool operator<=(const string& s) const`:重载小于等于操作符,判断当前字符串是否小于等于参数字符串。
- `bool operator>=(const string& s) const`:重载大于等于操作符,判断当前字符串是否大于等于参数字符串。
- `bool operator==(const string& s) const`:重载等于操作符,判断当前字符串是否等于参数字符串。
- `bool operator!=(const string& s) const`:重载不等于操作符,判断当前字符串是否不等于参数字符串。
这些功能和操作符重载使得字符串类更加方便实用,可以更灵活地进行字符串的操作和比较。
2.6 clear以及运算符<< >>重载
string.h:void clear();istream& operator>> (istream& is, string& str);ostream& operator<< (ostream& os, const string& str);string.cpp:void string::clear(){_str[0] = '\0';_size = 0;}istream& operator>> (istream& is, string& str){str.clear();char ch = is.get();while (ch != ' ' && ch != '\n'){str += ch;ch = is.get();}return is;}ostream& operator<< (ostream& os, const string& str){for (size_t i = 0; i < str.size(); i++){os << str[i];}return os;}
在上述代码中定义了一个简单的字符串类 string,并在 string 类中实现了 clear() 方法。
在 string 类的实现文件 string.cpp 中,clear() 方法将字符串数组 _str 的第一个字符设置为 '\0',并将字符串的大小 _size 设置为 0。
另外,还重载了输入流运算符 >> 和输出流运算符 <<。
在输入流运算符的实现中,先调用 string 类的 clear() 方法清空字符串,然后使用 istream 对象的 get() 方法逐个读取字符,直到遇到空格或换行符,将字符添加到字符串中。
在输出流运算符的实现中,使用 ostream 对象的 << 运算符逐个输出字符串中的字符。
最后,返回相应的输入流或输出流对象。
到此我们只是简单的模拟实现了一下STL中string的相关接口~,后续我们会一一展开学习的,希望这篇博客能给您带来一些启发和思考!那我们下次再一起探险喽,欢迎在评论区进行讨论~~~
相关文章:

探索C嘎嘎的奇妙世界:第十四关---STL(string的模拟实现)
1. string类的模拟实现 1.1 经典的string类问题 上一关已经对string类进行了简单的介绍,大家只要能够正常使用即可。在面试中,面试官总喜欢让学生自己来模拟实现string类,最主要是实现string类的构造、拷贝构造、赋值运算符重载以及析构函数…...
【JavaScript脚本宇宙】玩转图像处理:从基础到高级,这些库你不能错过!
让你的网页图像栩栩如生:六种必备图像处理库 前言 在数字图像处理中,我们经常需要对图片进行各种操作,如调整亮度、对比度、饱和度等,以达到所需的效果。为了简化这些操作并提供更丰富的功能,出现了许多专门用于图像…...

python+unity手势控制地球大小
效果图如下 具体操作如下 1 在unity窗口添加一个球体 2 给球体添加材质,材质图片使用地球图片 地球图片如下 unity材质设置截图如下 3 编写地球控制脚本 using System.Collections; using System.Collections.Generic; using UnityEngine;public class test : MonoBehavio…...

CSS【实战】抽屉动画
效果预览 技术要点 实现思路 元素固定布局(fixed)在窗口最右侧外部js 定时器改变元素的 right 属性,控制元素移入,移出 过渡动画 transition transition: 过渡的属性 过渡的持续时间 过渡时间函数 延迟时间此处改变的是 right …...

【Linux Vim的保姆级教程】
🌈个人主页: 程序员不想敲代码啊 🏆CSDN优质创作者,CSDN实力新星,CSDN博客专家 👍点赞⭐评论⭐收藏 🤝希望本文对您有所裨益,如有不足之处,欢迎在评论区提出指正,让我们共…...
力扣668.乘法表中第k小的数
力扣668.乘法表中第k小的数 二分查找 是否有k个比mid小的数 class Solution {public:int findKthNumber(int m, int n, int k) {auto check [&](int mid) -> bool{int res0;int row 1,col n;while(row < m){if(row * col < mid){res col;if(res > k) re…...
css伪类和伪元素选择器
伪类选择器关注元素的状态和条件,而伪元素选择器则关注元素的视觉表现和扩展。两者都是CSS中强大的工具,能够帮助开发者实现复杂的样式布局和交互效果。 伪类选择器 伪类选择器在CSS中用于选择元素的特定状态或位置。以下是一些常见的伪类选择器及其使…...
第壹章第15节 C#和TS语言对比-泛型
C#提供了泛型的完整支持,不仅在编译时,运行时仍然保留泛型的类型信息,同时提供了更加丰富的泛型约束和更加全面的协变逆变支持。TS的泛型,在语法表现形式上,和C#差不多,但本质上两者是不一样的。TS的泛型&a…...

苹果电脑下载vite包错
苹果电脑下载vite包错/Users/lili/.npm/_cacache/index-v5/c5/50/b451703d03b3802b9ee6b7ff2b0bde4de7f26830eb52c904d6911c137cf8包错解决方式 解决方式:sudo chown -R 501:20 "/Users/wangxin/.npm"...

自动化测试git的使用
git是一款分布式的配置管理工具。本文主要讲git如何在自动化测试中安装,上传及拉取下载代码。 1 、git 介绍 每天早上到公司,从公司的git服务器上下载最新的代码,白天在最新的代码基础上,编写新的代码,下班时把“代码…...

MyBatis系列四: 动态SQL
动态SQL语句-更复杂的查询业务需求 官方文档基本介绍案例演示if标签应用实例where标签应用实例choose/when/otherwise应用实例foreach标签应用实例trim标签应用实例[使用较少]set标签应用实例[重点]课后练习 上一讲, 我们学习的是 MyBatis系列三: 原生的API与配置文件详解 现在…...

Jenkins构建 Maven项目(微服务)并自动发布
前面讲了docker 安装Jenkins和gitlab代码管理工具,接下来我们讲一下Jenkins怎么构建 Maven项目。 1. 首先Jenkins配置下面3中工具类 首先是在本地安装三个jenkins自动配置相关的工具 1.1 JDK 由于我们使用docker来启动jenkins,其自带有jdk,…...

简单易用的多功能图床Picsur
什么是 Picsur ? Picsur 是一款易于使用、可自行托管的图片分享服务,类似于 Imgur,并内置转换功能。支持多种格式的图片,包括 QOI、JPG、PNG、WEBP(支持动画)、TIFF、BMP、GIF(支持动画…...
数据库-查询语句习题
SELECT Sname 姓 名,year of birth: 出生年,YEAR(GETDATE())-Sage BIRTHYEAR,LOWER(SNAME) SNAME --起别名 没有特殊字符不需要引号,有特殊字符要加引号;别名(解释作用显示给用户看)用空格或as连接 FROM STUDENT; --消除重复行 DI…...

进程间通信以及线程的同步互斥机制
1.进程间通信机制 常用的六种通信机制: 管道、消息队列、共享内存、信号灯集、信号、Socket 管道(Pipe)和无名管道(匿名管道): 管道是一种半双工的通信方式,数据只能单向流动,通常…...

优思学院|做车企的质量工程师转行跳槽能干嘛?
前言 质量工程师,是现代制造业和服务业中不可或缺的重要角色。他们负责制定和执行提高产品质量和优化业务流程的战略。这不仅涉及设立质量标准、开发测试系统,还包括记录生产过程中的问题并找到解决方案。尤其在汽车行业,由于对质量的高度要…...

ctfshow-web入门-命令执行(web53-web55)
目录 1、web53 2、web54 3、web55 1、web53 这里的代码有点不一样,说一下这两种的区别: (1)直接执行 system($c); system($c);这种方式会直接执行命令 $c 并将命令的输出直接发送到标准输出(通常是浏览器ÿ…...
【INTEL(ALTERA)】make: nios2-swexample-create:未找到命令
目录 说明 解决方法 说明 由于外部内存接口英特尔 Stratix 10 FPGA IP 出现问题,如果在 Windows 平台上使用英特尔 Quartus Prime Pro Edition Software v20.4 或更早版本的"使用软Nios处理器进行片上调试"选项,编译Nios II 片上处理器调试…...
一周刷爆leetcode!(b站视频)
文章目录 一、排序思想的题目二、使用步骤1. 一、排序思想的题目 跟着b站一周刷爆leetcode这个视频开始刷一下leetcode的题目 进行一下记录啥的 二、使用步骤 1. 315. 计算右侧小于当前元素的个数 代码如下: 写了一下暴力解法,没有通过 使用归并排序…...
1.xshell传不了文件输出0000如何解决.....2.k8s中metalLB文件内容
xshell传不了文件输出0000如何解决 centos版本 1,因为没有工具下载即可 yum -y install lrzszk8s中metalLB文件内容 2.metalLB文件内容 cat metallb-native.yaml apiVersion: v1 kind: Namespace metadata:labels:pod-security.kubernetes.io/audit: privilegedpod-securit…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...

深入剖析AI大模型:大模型时代的 Prompt 工程全解析
今天聊的内容,我认为是AI开发里面非常重要的内容。它在AI开发里无处不在,当你对 AI 助手说 "用李白的风格写一首关于人工智能的诗",或者让翻译模型 "将这段合同翻译成商务日语" 时,输入的这句话就是 Prompt。…...
蓝桥杯 2024 15届国赛 A组 儿童节快乐
P10576 [蓝桥杯 2024 国 A] 儿童节快乐 题目描述 五彩斑斓的气球在蓝天下悠然飘荡,轻快的音乐在耳边持续回荡,小朋友们手牵着手一同畅快欢笑。在这样一片安乐祥和的氛围下,六一来了。 今天是六一儿童节,小蓝老师为了让大家在节…...

智能在线客服平台:数字化时代企业连接用户的 AI 中枢
随着互联网技术的飞速发展,消费者期望能够随时随地与企业进行交流。在线客服平台作为连接企业与客户的重要桥梁,不仅优化了客户体验,还提升了企业的服务效率和市场竞争力。本文将探讨在线客服平台的重要性、技术进展、实际应用,并…...
Qwen3-Embedding-0.6B深度解析:多语言语义检索的轻量级利器
第一章 引言:语义表示的新时代挑战与Qwen3的破局之路 1.1 文本嵌入的核心价值与技术演进 在人工智能领域,文本嵌入技术如同连接自然语言与机器理解的“神经突触”——它将人类语言转化为计算机可计算的语义向量,支撑着搜索引擎、推荐系统、…...

基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【C语言练习】080. 使用C语言实现简单的数据库操作
080. 使用C语言实现简单的数据库操作 080. 使用C语言实现简单的数据库操作使用原生APIODBC接口第三方库ORM框架文件模拟1. 安装SQLite2. 示例代码:使用SQLite创建数据库、表和插入数据3. 编译和运行4. 示例运行输出:5. 注意事项6. 总结080. 使用C语言实现简单的数据库操作 在…...
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南
精益数据分析(97/126):邮件营销与用户参与度的关键指标优化指南 在数字化营销时代,邮件列表效度、用户参与度和网站性能等指标往往决定着创业公司的增长成败。今天,我们将深入解析邮件打开率、网站可用性、页面参与时…...
掌握 HTTP 请求:理解 cURL GET 语法
cURL 是一个强大的命令行工具,用于发送 HTTP 请求和与 Web 服务器交互。在 Web 开发和测试中,cURL 经常用于发送 GET 请求来获取服务器资源。本文将详细介绍 cURL GET 请求的语法和使用方法。 一、cURL 基本概念 cURL 是 "Client URL" 的缩写…...

C++实现分布式网络通信框架RPC(2)——rpc发布端
有了上篇文章的项目的基本知识的了解,现在我们就开始构建项目。 目录 一、构建工程目录 二、本地服务发布成RPC服务 2.1理解RPC发布 2.2实现 三、Mprpc框架的基础类设计 3.1框架的初始化类 MprpcApplication 代码实现 3.2读取配置文件类 MprpcConfig 代码实现…...