C++:模拟实现STL的string
目录
一.实现string类
1.string的构造及析构
2.string类的遍历
3.string类的插入和删除
4.string类的空间处理
5.string类的查找
6.string类的输出和输入
7.string类的常用判断
二.整体代码
1.string.h
2.string.cpp
一.实现string类
在前一节中我们了解了STL中string的部分接口,在这里我们实现一个自己的string类
当我们实现自己的string类时,名字会与库内的冲突,所以可以选择用命名空间解决
1.string的构造及析构
当我们在开空间的时候一般要多开一个用于存放\0
拷贝构造和赋值用传统方法写一般是开新空间,复制过去,释放旧空间,但是在这里我们使用现代写法,直接将空间交换过来使用
而在swap函数中使用::,是为了让他去调用库中的函数,而不是类中的
string(const char* str = "")
{_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//strcpy(_str,str);不安全,会报错,无法实现功能,在后面主要使用strcpy_sstrcpy_s(_str, strlen(str) + 1, str);//c11标准
}//深拷贝,若用编译器自动生成的为浅拷贝,析构时会出现问题
string(const string& s):_str(nullptr),_size(0),_capacity(0)
{string tmp(s._str);//his->swap(tmp);swap(tmp);
}void swap(string& s)
{::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);
}~string()
{delete[] _str;_str = nullptr;_size = _capacity = 0;
}string& operator=(string s)
{//this->swap(s);swap(s);return *this;
}
2.string类的遍历
对于string类的遍历我们可以通过[]+下标,迭代器,范围for语句遍历,以及c_str
所以我们需要自己定义迭代器,重载[]
typedef char* iterator;iterator begin()
{return _str;
}iterator end()
{return _str + _size;
}char& operator[](size_t i)
{assert(i < _size);return _str[i];
}const char& operator[](size_t i) const
{assert(i < _size);return _str[i];
}const char* c_str()
{return _str;
}
3.string类的插入和删除
对于插入我们都要考虑的便是容量不够需要增容,同时也应该考虑字符串开始为空的情况,如果为空就给一个容量,否则就扩2倍
push_back的话我们只需要将字符加在末端即可
append将插入的字符串复制到原字符串末尾即可
+=对于单个push_back,字符串复用append
insert插入单个字符时,将字符从末尾开始向后移一位,将字符插入头即可,插入字符串时后移的位数变为插入字符串的长度
erase删除主要考虑两种情况,删除一部分和全部删完,全部删完比较简单,将删除的位置变为\0,将size变为pos即可,删除部分,将后面的字符前移覆盖
void push_back(char ch){if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}//strcpy(_str + _size, str);strcpy_s(_str + _size, strlen(str) + 1, str);_size += len;}string& operator+=(char ch){this->push_back(ch);return *this;}string& operator+=(const char* str){this->append(str);return *this;}string& insert(size_t pos, char ch){assert(pos < _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;reserve(newcapacity);}int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];--end;}_str[pos] = ch;++_size;return *this;}string& insert(size_t pos, const char* str){assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];--end;}for (size_t i = 0; i < len; ++i){_str[pos++] = str[i];}_size += len;return *this;}void erase(size_t pos, size_t len = npos){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{size_t i = pos + len;while (i <= _size){_str[i - len] = _str[i];++i;}_size -= len;}}
4.string类的空间处理
reserve比较简单,直接开出一段空间即可,而resize则需要考虑空间的缩小,缩小的话将给定位置变为\0,放大空间的话,reserve空间,然后将size后面的都填上给定的或默认字符
size_t size() const{return _size;}size_t capacity() const{return _capacity;}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];//strcpy(tmp, _str);strcpy_s(tmp, strlen(_str) + 1, _str);delete[] _str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0'){if (n < _size){_str[n] = '\0';_size = n;}else{if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; ++i){_str[i] = ch;}_size = n;_str[_size] = '\0';}}
5.string类的查找
size_t find(char ch, size_t pos = 0)
{for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;
}size_t find(const char* str, size_t pos = 0)
{char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - _str;}
}
6.string类的输出和输入
ostream& operator<<(ostream& out, const string& s){for (size_t i = 0; i < s.size(); ++i){cout << s[i];}return out;}//getline()只需要去掉if中的' '即可istream& operator>>(istream& in, string& s){while (1){char ch;ch = in.get();if (ch == ' ' || ch == '\n'){break;}else{s += ch;}}return in;}
7.string类的常用判断
bool operator<(const string& s)
{int ret = strcmp(_str, s._str);return ret < 0;
}bool operator==(const string& s)
{int ret = strcmp(_str, s._str);return ret == 0;
}bool operator<=(const string& s)
{return *this < s || *this == s;
}bool operator>(const string& s)
{return !(*this <= s);
}bool operator>=(const string& s)
{return !(*this < s);
}bool operator!=(const string& s)
{return !(*this == s);
}
二.整体代码
1.string.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace wzyl
{class string{public:typedef char* iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}string(const char* str = ""){_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];//strcpy(_str,str);不安全,会报错,无法实现功能,在后面主要使用strcpy_sstrcpy_s(_str, strlen(str) + 1, str);//c11标准}//深拷贝,若用编译器自动生成的为浅拷贝,析构时会出现问题string(const string& s):_str(nullptr),_size(0),_capacity(0){string tmp(s._str);//his->swap(tmp);swap(tmp);}void swap(string& s){::swap(_str, s._str);::swap(_size, s._size);::swap(_capacity, s._capacity);}~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}string& operator=(string s){//this->swap(s);swap(s);return *this;}size_t size() const{return _size;}size_t capacity() const{return _capacity;}char& operator[](size_t i){assert(i < _size);return _str[i];}const char& operator[](size_t i) const{assert(i < _size);return _str[i];}const char* c_str(){return _str;}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];//strcpy(tmp, _str);strcpy_s(tmp, strlen(_str) + 1, _str);delete[] _str;_str = tmp;_capacity = n;}}void resize(size_t n, char ch = '\0'){if (n < _size){_str[n] = '\0';_size = n;}else{if (n > _capacity){reserve(n);}for (size_t i = _size; i < n; ++i){_str[i] = ch;}_size = n;_str[_size] = '\0';}}void push_back(char ch){if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;reserve(newcapacity);}_str[_size] = ch;++_size;_str[_size] = '\0';}void append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}//strcpy(_str + _size, str);strcpy_s(_str + _size, strlen(str) + 1, str);_size += len;}string& operator+=(char ch){this->push_back(ch);return *this;}string& operator+=(const char* str){this->append(str);return *this;}string& insert(size_t pos, char ch){assert(pos < _size);if (_size == _capacity){size_t newcapacity = _capacity == 0 ? 2 : _capacity * 2;reserve(newcapacity);}int end = _size;while (end >= (int)pos){_str[end + 1] = _str[end];--end;}_str[pos] = ch;++_size;return *this;}string& insert(size_t pos, const char* str){assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity){reserve(_size + len);}int end = _size;while (end >= (int)pos){_str[end + len] = _str[end];--end;}for (size_t i = 0; i < len; ++i){_str[pos++] = str[i];}_size += len;return *this;}void erase(size_t pos, size_t len = npos){assert(pos < _size);if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{size_t i = pos + len;while (i <= _size){_str[i - len] = _str[i];++i;}_size -= len;}}size_t find(char ch, size_t pos = 0){for (size_t i = pos; i < _size; ++i){if (_str[i] == ch){return i;}}return npos;}size_t find(const char* str, size_t pos = 0){char* p = strstr(_str, str);if (p == nullptr){return npos;}else{return p - _str;}}bool operator<(const string& s){int ret = strcmp(_str, s._str);return ret < 0;}bool operator==(const string& s){int ret = strcmp(_str, s._str);return ret == 0;}bool operator<=(const string& s){return *this < s || *this == s;}bool operator>(const string& s){return !(*this <= s);}bool operator>=(const string& s){return !(*this < s);}bool operator!=(const string& s){return !(*this == s);}private:char* _str;size_t _size;//有效字符个数size_t _capacity;//能存多少有效字符,\0不是有效字符static size_t npos;};size_t string::npos = -1;ostream& operator<<(ostream& out, const string& s){for (size_t i = 0; i < s.size(); ++i){cout << s[i];}return out;}//getline()只需要去掉if中的' '即可istream& operator>>(istream& in, string& s){while (1){char ch;ch = in.get();if (ch == ' ' || ch == '\n'){break;}else{s += ch;}}return in;}void test_string1(){string s1("hello");string s2;cout << s1 << endl;cout << s2 << endl;cout << s1.c_str() << endl;cout << s2.c_str() << endl;//3种遍历方式for (size_t i = 0; i < s1.size(); ++i){s1[i] += 1;cout << s1[i] << " ";}cout << endl;string::iterator it = s1.begin();while (it != s1.end()){*it -= 1;cout << *it << " ";++it;}cout << endl;//范围for是由迭代器支持的,所以这段代码最后会被替换成迭代器for (auto e : s1){cout << e << " ";}cout << endl;}void test_string2(){string s1("hello");s1.push_back(' ');s1.push_back('w');s1.push_back('o');s1.push_back('r');s1.push_back('l');s1.push_back('d');cout << s1 << endl;s1.append("xxxxxxxxx");cout << s1 << endl;string s2;s2 += "hello";s2 += ' ';s2 += "world";cout << s2 << endl;}void test_string3(){string s1("hello");s1.insert(1, 'x');s1.insert(1, "xyz");s1.insert(0, 'p');cout << s1 << endl << endl;string s2("hello");s2.reserve(10);cout << s2 << endl;cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(10, 'x');cout << s2 << endl;cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(18, 'a');cout << s2 << endl;cout << s2.size() << endl;cout << s2.capacity() << endl << endl;s2.resize(2);cout << s2 << endl;cout << s2.size() << endl;cout << s2.capacity() << endl;}void test_string4(){string s("helloworld");s.erase(5, 2);cout << s << endl;s.erase(5, 4);cout << s << endl;string s1("abcdabcdef");cout << s1.find("cde") << endl;cout << s1.find("fgh") << endl;}void test_string5(){string s;cin >> s;cout << s << endl;string s1(s);cout << s1 << endl;string s2 = s1;cout << s2 << endl;}
}
2.string.cpp
#include "string.h"int main()
{wzyl::test_string1();wzyl::test_string2();wzyl::test_string3();wzyl::test_string4();wzyl::test_string5();return 0;
}
相关文章:
C++:模拟实现STL的string
目录 一.实现string类 1.string的构造及析构 2.string类的遍历 3.string类的插入和删除 4.string类的空间处理 5.string类的查找 6.string类的输出和输入 7.string类的常用判断 二.整体代码 1.string.h 2.string.cpp 一.实现string类 在前一节中我们了解了STL中stri…...
【Python TensorFlow】入门到精通
TensorFlow 是一个开源的机器学习框架,由 Google 开发,广泛应用于机器学习和深度学习领域。本篇将详细介绍 TensorFlow 的基础知识,并通过一系列示例来帮助读者从入门到精通 TensorFlow 的使用。 1. TensorFlow 简介 1.1 什么是 TensorFlow…...
数据结构:七种排序及总结
文章目录 排序一插入排序1直接插入排序2希尔排序二选择排序3直接选择排序4堆排序三 交换排序5冒泡排序6快速排序四 归并排序7归并排序源码 排序 我们数据结构常见的排序有四大种,四大种又分为七小种,如图所示 排序:所谓排序,就是…...
【安当产品应用案例100集】030-使用企业微信登录Windows,实现工作电脑与业务系统登录方式统一
随着越来越多的企业信息系统从intranet开放到internet,企业员工的办公接入方式也越发多样,信息系统面临的数据安全问题也呈现爆发的趋势。一些大企业,比如Google、Microsoft、Huawei有强大的开发能力、IT能力,可以构建出自己的零信…...
大数据数据存储层MemSQL, HBase与HDFS
以下是对 MemSQL、HBase 和 HDFS 的详细介绍,这些工具在分布式数据存储和处理领域有着重要作用。 1. MemSQL MemSQL(现称为 SingleStore)是一种分布式内存数据库,兼具事务处理(OLTP)和分析处理(OLAP)的能力,专为高性能实时数据处理设计。 1.1 核心特点 内存优先存储…...
【HarmonyOS】鸿蒙应用设置控件通用样式AttributeModifier, @Styles
【HarmonyOS】鸿蒙应用设置控件通用样式AttributeModifier, Styles 前言 在鸿蒙中UI开发经常需要对控件样式进行统一的封装,在API早前版本,一般是通过 Styles进行样式封装复用: Entry Component struct Index {build() {Column(…...
Scala IF...ELSE 语句
Scala IF...ELSE 语句 Scala 是一种多范式的编程语言,它结合了面向对象和函数式编程的特点。在 Scala 中,if...else 语句是一种基本且常用的控制结构,用于根据条件执行不同的代码块。与 Java 或 Python 等其他语言中的 if...else 语句类似&a…...
快速上手vue3+js+Node.js
安装Navicat Premium Navicat Premium 创建一个空的文件夹(用于配置node) 生成pakeage.json文件 npm init -y 操作mysql npm i mysql2.18.1 安装express搭建web服务器 npm i express4.17.1安装cors解决跨域问题 npm i cors2.8.5创建app.js con…...
06 网络编程基础
目录 1.通信三要素 1. IP地址(Internet Protocol Address) 2. 端口号(Port Number) 3. 协议(Protocol) 2.TCP与UDP协议 三次握手(Three-Way Handshake) 四次挥手(…...
Python 的 FastApi 如何在request 重复取request.body()
需求背景: 需要再中间件中获取body 中的信息 但是 又想要在之后 还可以重复取 这个body 因为有的接口写法是直接从body中获取参数,然而这个body是数据流的形式,一旦取一次就导致后面取不到里面的值了 。 解决方式: 1.保存请求体: 在中间件中读取请求…...
qt QFontDialog详解
1、概述 QFontDialog 是 Qt 框架中的一个对话框类,用于选择字体。它提供了一个可视化的界面,允许用户选择所需的字体以及相关的属性,如字体样式、大小、粗细等。用户可以通过对话框中的选项进行选择,并实时预览所选字体的效果。Q…...
AI时代,通才可能会占据更有利的地位
在AI时代,通才不仅有生存的可能,而且根据多个参考内容,他们实际上可能占据更有利的地位。以下几点解释了为什么通才在人工智能时代具有重要性和生存空间: 适应性和灵活性:通才因其广泛的知识基础和跨领域的技能&#x…...
qt QHeaderView详解
1、概述 QHeaderView 是 Qt 框架中的一个类,它通常作为 QTableView、QTreeView 等视图类的一部分,用于显示和管理列的标题(对于水平头)或行的标题(对于垂直头)。QHeaderView 提供了对这些标题的排序、筛选…...
探索PickleDB:Python中的轻量级数据存储利器
文章目录 探索PickleDB:Python中的轻量级数据存储利器1. 背景:为什么选择PickleDB?2. PickleDB是什么?3. 如何安装PickleDB?4. 简单的库函数使用方法创建和打开数据库设置数据获取数据删除数据保存数据库 5. 应用场景与…...
yocto下编译perf失败的解决方法
文章目录 问题分析库没有安装?文件缺少?解决参考问题 在新环境使用yocto编译镜像时,发现最后一直编译不过perf,具体的编译提示错误如下 ERROR: perf-1.0-r9 do_compile: oe_runmake failed ERROR: perf-1.0-r9 do_compile: Execution of /home/ub-1001/work/as66/imx8LBV…...
丹摩征文活动|详解 DAMODEL(丹摩智算)平台:为 AI 开发者量身打造的智算云服务
本文 什么是 DAMODEL(丹摩智算)?DAMODEL 的平台特性快速上手 DAMODEL 平台GPU 实例概览创建 GPU 云实例 储存选项技术支持与社区服务结语 在人工智能领域的飞速发展中,计算资源与平台的选择变得尤为重要。为了帮助 AI 开发者解决高…...
ORACLE _11G_R2_ASM 常用命令
--------查看磁盘组,(空间情况) select name,state,free_mb,total_mb,usable_file_mb from v$asm_diskgroup; --------查看磁盘情况 select GROUP_NUMBER,free_mb,total_mb,disk_number,MOUNT_STATUS,mode_status, HEADER_STATUS,name,PATH from v$asm_disk order …...
掌握Rust模式匹配:从基础语法到实际应用
本篇文章将探讨 Rust 编程语言中至关重要的特性之一——模式匹配。Rust 语言的模式匹配功能强大,不仅能处理简单的值匹配,还能解构和操作复杂的数据结构。通过深入学习模式匹配,程序员可以更加高效地编写出清晰、简洁且易于维护的代码。 Rus…...
HFSS 3D Layout中Design setting各个选项的解释
从HFSS 3D LAYOUT菜单中,选择Design Settings打开窗口,会有六个选项:DC Extrapolation, Nexxim Options, Export S Parameters, Lossy Dielectrics, HFSS Meshing Method, and HFSS Adaptive Mesh. DC Extrapolation 直流外推 直流外推分为标…...
线性表之链表详解
欢迎来到我的:世界 希望作者的文章对你有所帮助,有不足的地方还请指正,大家一起学习交流 ! 目录 前言线性表的概述链表的概述 内容链表的结构链表节点的定义 链表的基本功能单向链表的初始化链表的插入操作头插操作尾插操作 链表的删除操作头…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
CTF show Web 红包题第六弹
提示 1.不是SQL注入 2.需要找关键源码 思路 进入页面发现是一个登录框,很难让人不联想到SQL注入,但提示都说了不是SQL注入,所以就不往这方面想了 先查看一下网页源码,发现一段JavaScript代码,有一个关键类ctfs…...
前端倒计时误差!
提示:记录工作中遇到的需求及解决办法 文章目录 前言一、误差从何而来?二、五大解决方案1. 动态校准法(基础版)2. Web Worker 计时3. 服务器时间同步4. Performance API 高精度计时5. 页面可见性API优化三、生产环境最佳实践四、终极解决方案架构前言 前几天听说公司某个项…...
《从零掌握MIPI CSI-2: 协议精解与FPGA摄像头开发实战》-- CSI-2 协议详细解析 (一)
CSI-2 协议详细解析 (一) 1. CSI-2层定义(CSI-2 Layer Definitions) 分层结构 :CSI-2协议分为6层: 物理层(PHY Layer) : 定义电气特性、时钟机制和传输介质(导线&#…...
Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...
无法与IP建立连接,未能下载VSCode服务器
如题,在远程连接服务器的时候突然遇到了这个提示。 查阅了一圈,发现是VSCode版本自动更新惹的祸!!! 在VSCode的帮助->关于这里发现前几天VSCode自动更新了,我的版本号变成了1.100.3 才导致了远程连接出…...
多模态大语言模型arxiv论文略读(108)
CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文标题:CROME: Cross-Modal Adapters for Efficient Multimodal LLM ➡️ 论文作者:Sayna Ebrahimi, Sercan O. Arik, Tejas Nama, Tomas Pfister ➡️ 研究机构: Google Cloud AI Re…...
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决
Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中,新增了一个本地验证码接口 /code,使用函数式路由(RouterFunction)和 Hutool 的 Circle…...
android13 app的触摸问题定位分析流程
一、知识点 一般来说,触摸问题都是app层面出问题,我们可以在ViewRootImpl.java添加log的方式定位;如果是touchableRegion的计算问题,就会相对比较麻烦了,需要通过adb shell dumpsys input > input.log指令,且通过打印堆栈的方式,逐步定位问题,并找到修改方案。 问题…...
