cpp实战项目—string类的模拟实现

cpp—string类的模拟实现

  • string类的模拟实现
    • string.h
    • test.cpp

string类的模拟实现

相信大家看完我的这篇有关string使用的博客(C++中的string类使用,看我这一篇就够了!)之后对于string类的基本使用有了一定的了解,
因此这篇我们来看看string类底层是如何实现的!
在这之前我们需要了解的基本知识有
C++快速入门,看我这一篇就够了!
cpp – 构造函数与析构函数
cpp–拷贝构造函数详解
cpp–赋值运算符重载,浅显易懂!
cpp–初始化列表,超详细,一看就会!
cpp–内存管理(new/delete的用法),超详细讲解,一看就会!
C++中的string类使用,看我这一篇就够了!

string.h

#pragma once
#include <assert.h>namespace s
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){int length = _size;return _str + length;}const iterator begin() const{return _str;}const iterator end() const{return _str + _size;}string(const char* str = ""):_size(strlen(str)),_capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//string(const string& s)//深拷贝构造函数//{//	_str = new char[s._capacity + 1];//	strcpy(_str, s._str);//	_size = s._size;//	_capacity = s._capacity;//}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//深拷贝构造函数的现代写法string(const string& s):_str(nullptr), _size(0), _capacity(0){string tmp(s._str);swap(tmp);}/*string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}*/string& operator=(string tmp){swap(tmp);return *this;}char* c_str(){return _str;}size_t capacity(){return _capacity;}size_t size(){return _size;}//bool operator<(const string& str) const//{//	size_t i = 0;//	//逐个字符比较,直到其中一个字符串结束//	while (i < _size && str._str[i] != '\0')//	{//		if (_str[i] > str._str[i])//		{//			return false;//		}//		else if (_str[i] < str._str[i])//		{//			return true;//		}//		i++;//	}//	if (i == _size && str._str[i] != '\0')//	{//		return true;//	}//	return false;//}bool operator<(const string& str) const{//size_t i = 0; 逐个字符比较,直到其中一个字符串结束//while (i < _size && i < str._size)//{//	if (_str[i] < str._str[i])//	{//		return true;//	}//	else if (_str[i] > str._str[i])//	{//		return false;//	}//	i++;//} 如果前面字符都相等,比较字符串长度//return _size < str._size;//使用库函数return strcmp(_str, str._str) < 0;}bool operator==(const string& s){return strcmp(_str, s._str) == 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) || (*this > s);}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}void clear(){_str[0] = '\0';_size = 0;}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp,_str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size += 1;_str[_size] = '/0';}void append(const char* str){int length = strlen(str)+_size;if(_capacity<length)reserve(length);strcpy(_str + _size, str);_size += strlen(str);}/*void insert(size_t pos, char ch) //方法一{assert(pos <= _size);if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size+1;for (size_t i = end;i > pos;i--){_str[i] = _str[i-1];}_str[pos] = ch;_size++;_str[_size] = '\0';}*/void insert(size_t pos, char ch) //方法二{assert(pos <= _size);if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size;for (int i = (int)end;i >= (int)pos;i--){_str[i+1] = _str[i];}_str[pos] = ch;_size++;_str[_size] = '\0';}void insert(size_t pos, const char* str){int length = strlen(str);if (_size + length > _capacity){reserve(_size+length);}for (int i = (int)_size; i >= (int)pos; i--){_str[i + length] = _str[i];}strncpy(_str+pos, str, length);_size += length;}//strcpy:会复制整个源字符串,直到遇到字符串结束符 '\0',// 它不会对复制的字符数量进行额外的限制。// 如果目标字符串的空间不足以容纳源字符串,会导致缓冲区溢出,// 这是一种非常危险的情况,可能会引发程序崩溃或安全漏洞//strncpy:可以指定最多复制的字符数量 n。// 如果源字符串的长度小于 n,则会将源字符串全部复制到目标字符串,// 并且在目标字符串后面填充 '\0' 直到复制的字符总数达到 n;// 如果源字符串的长度大于等于 n,则只会复制 n 个字符,// 不会自动添加字符串结束符 '\0',// 这可能导致目标字符串不是以 '\0' 结尾的有效字符串string substr(size_t pos, size_t len = npos){string s;size_t end = pos + len;if (pos + len >= _size || len == npos){len = _size - pos;end = _size;}s.reserve(len);for (size_t i = pos;i < pos + len;i++){s += _str[i];}return s;}void erase(size_t pos, size_t len = npos){assert(pos < _size);if (pos + len >= _size || len == npos){_str[pos] = '\0';_size = pos;}else{int end = pos + len;for (int i = pos+len; i <= _size; i++){_str[i-len] = _str[i];}_size -= len;_str[_size] = '\0';}}void resize(int n, char ch = '\0'){if (n > _size){reserve(n);while (_size < n){_str[_size] = ch;++_size;}_str[_size] = '\0';}else if (n <= _size){_str[n] = '\0';_size = n;}}size_t find(char ch, int pos = 0){while (pos < _size){if (ch == _str[pos]){return pos;}++pos;}return npos;}size_t find(const char* sub, int pos = 0){const char* p = strstr(_str + pos, sub);//返回sub在字符串中第一次出现的位置if (p){return p - _str;}else{return npos;}}const static size_t npos;private:char* _str;size_t _size;size_t _capacity;};const  size_t string::npos = -1;istream& operator>>(istream& in, string& s){s.clear();char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';s += buff;}return in;}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}void test_string1(){string s1("hello world");cout << s1.c_str() << endl;string s2;cout << s2.c_str() << endl;cout << s1.size() << endl;cout << s2.size() << endl;cout << s1.capacity() << endl;cout << s2.capacity() << endl;for (size_t i = 0; i < s1.size();i++){cout << s1[i] ;}cout << endl;string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;for (auto& ch : s1){cout << ch << " ";}}void test_string2(){string s1("hello world");cout << s1.c_str() << endl;s1.push_back(' ');s1.append("hello boy");cout << s1.c_str() << endl;}void test_string3(){string s1("hello world");cout << s1.c_str() << endl;s1.insert(0, '%');//在头插时可能出现的问题//在将元素后移的 for 循环中,for (size_t i = end; i >= pos; i--) // 会导致无限循环。因为 size_t 是无符号整数类型,// 当 i 减到 0 后再减 1 会变成一个很大的正数(发生下溢),// 而不是负数,所以循环条件 i >= pos 始终为真。// 可以将循环变量改为有符号整数类型,或者从后往前移动元素cout << s1.c_str() << endl;s1.insert(0, "##############################");cout << s1.c_str() << endl;}void test_string4(){string s1("hello worad");string s2("hello worsld");cout << (s1 < s2) << endl;s1[0] = 'z';cout << (s1 >= s2) << endl;cin >> s1>>s2;cout << s1 <<s2<< endl;}void test_string5(){string s1("hello world");s1.insert(5, "abc");s1.insert(0, "xxx");cout << s1 << endl;s1.erase(0, 3);cout << s1 << endl;s1.erase(5, 100);cout << s1 << endl;}void test_string6(){string s1("hello world");cout << s1 << endl;s1.resize(5);cout << s1 << endl;s1.resize(25, 'x');cout << s1 << endl;}void test_string7(){string s1("test.cpp.tar.zip");//size_t i = s1.find('.');//size_t i = s1.rfind('.');//string s2 = s1.substr(i);//cout << s2 << endl;string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");//string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");// 协议// 域名// 资源名string sub1, sub2, sub3;size_t i1 = s3.find(':');if (i1 != string::npos)sub1 = s3.substr(0, i1);elsecout << "没有找到i1" << endl;size_t i2 = s3.find('/', i1 + 3);if (i2 != string::npos)sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));elsecout << "没有找到i2" << endl;sub3 = s3.substr(i2 + 1);cout << sub1 << endl;cout << sub2 << endl;cout << sub3 << endl;}void test_string8(){string s1("hello world");string s2 = s1;cout << s1 << endl;cout << s2 << endl;string s3("xxxxxxxxxxxxxxx");s1 = s3;cout << s3 << endl;}void test_string9(){string s1("hello world");cin >> s1;cout << s1 << endl;}
}

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;
#include "string.h"
int main()
{s::test_string9();return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/10976.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

创建前端项目的方法

目录 一、创建前端项目的方法 1.前提&#xff1a;安装Vue CLI 2.方式一&#xff1a;vue create项目名称 3.方式二&#xff1a;vue ui 二、Vue项目结构 三、修改Vue项目端口号的方法 一、创建前端项目的方法 1.前提&#xff1a;安装Vue CLI npm i vue/cli -g 2.方式一&…

(leetcode 213 打家劫舍ii)

代码随想录&#xff1a; 将一个线性数组换成两个线性数组&#xff08;去掉头&#xff0c;去掉尾&#xff09; 分别求两个线性数组的最大值 最后求这两个数组的最大值 代码随想录视频 #include<iostream> #include<vector> #include<algorithm> //nums:2,…

【Python】第七弹---Python基础进阶:深入字典操作与文件处理技巧

✨个人主页&#xff1a; 熬夜学编程的小林 &#x1f497;系列专栏&#xff1a; 【C语言详解】 【数据结构详解】【C详解】【Linux系统编程】【MySQL】【Python】 目录 1、字典 1.1、字典是什么 1.2、创建字典 1.3、查找 key 1.4、新增/修改元素 1.5、删除元素 1.6、遍历…

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操

本地部署DeepSeek开源多模态大模型Janus-Pro-7B实操 Janus-Pro-7B介绍 Janus-Pro-7B 是由 DeepSeek 开发的多模态 AI 模型&#xff0c;它在理解和生成方面取得了显著的进步。这意味着它不仅可以处理文本&#xff0c;还可以处理图像等其他模态的信息。 模型主要特点:Permalink…

BW AO/工作簿权限配置

场景&#xff1a; 按事业部配置工作簿权限&#xff1b; 1、创建用户 事务码&#xff1a;SU01&#xff0c;用户主数据的维护&#xff0c;可以创建、修改、删除、锁定、解锁、修改密码等 用户设置详情页 2、创建权限角色 用户的权限菜单是通过权限角色分配来实现的 2.1、自定…

jstat命令详解

jstat 用于监视虚拟机运行时状态信息的命令&#xff0c;它可以显示出虚拟机进程中的类装载、内存、垃圾收集、JIT 编译等运行数据。 命令的使用格式如下。 jstat [option] LVMID [interval] [count]各个参数详解&#xff1a; option&#xff1a;操作参数LVMID&#xff1a;本…

3.Spring-事务

一、隔离级别&#xff1a; 脏读&#xff1a; 一个事务访问到另外一个事务未提交的数据。 不可重复读&#xff1a; 事务内多次查询相同条件返回的结果不同。 幻读&#xff1a; 一个事务在前后两次查询同一个范围的时候&#xff0c;后一次查询看到了前一次查询没有看到的行。 二…

MYSQL--一条SQL执行的流程,分析MYSQL的架构

文章目录 第一步建立连接第二部解析 SQL第三步执行 sql预处理优化阶段执行阶段索引下推 执行一条select 语句中间会发生什么&#xff1f; 这个是对 mysql 架构的深入理解。 select * from product where id 1;对于mysql的架构分层: mysql 架构分成了 Server 层和存储引擎层&a…

ReentrantReadWriteLock源码分析

文章目录 概述一、状态位设计二、读锁三、锁降级机制四、写锁总结 概述 ReentrantReadWriteLock&#xff08;读写锁&#xff09;是对于ReentranLock&#xff08;可重入锁&#xff09;的一种改进&#xff0c;在可重入锁的基础上&#xff0c;进行了读写分离。适用于读多写少的场景…

51单片机开发:温度传感器

温度传感器DS18B20&#xff1a; 初始化时序图如下图所示&#xff1a; u8 ds18b20_init(void){ds18b20_reset();return ds18b20_check(); }void ds18b20_reset(void){DS18B20_PORT 0;delay_10us(75);DS18B20_PORT 1;delay_10us(2); }u8 ds18b20_check(void){u8 time_temp0;wh…

vue2项目(一)

项目介绍 电商前台项目 技术架构&#xff1a;vuewebpackvuexvue-routeraxiosless.. 封装通用组件登录注册token购物车支付项目性能优化 一、项目初始化 使用vue create projrct_vue2在命令行窗口创建项目 1.1、脚手架目录介绍 ├── node_modules:放置项目的依赖 ├──…

labelme_json_to_dataset ValueError: path is on mount ‘D:‘,start on C

这是你的labelme运行时label照片的盘和保存目的地址的盘不同都值得报错 labelme_json_to_dataset ValueError: path is on mount D:,start on C 只需要放一个盘但可以不放一个目录

物联网 STM32【源代码形式-使用以太网】连接OneNet IOT从云产品开发到底层MQTT实现,APP控制 【保姆级零基础搭建】

物联网&#xff08;IoT&#xff09;‌是指通过各种信息传感器、射频识别技术、全球定位系统、红外感应器等装置与技术&#xff0c;实时采集并连接任何需要监控、连接、互动的物体或过程&#xff0c;实现对物品和过程的智能化感知、识别和管理。物联网的核心功能包括数据采集与监…

无心剑七绝《深度求索》

七绝深度求索 深研妙理定乾坤 度世玄机启智门 求路千难兼万险 索萦华夏自为尊 2025年2月1日 平水韵十三元平韵 无心剑七绝《深度求索》以平水韵十三元平韵写成&#xff0c;意境深远&#xff0c;气势磅礴。诗中“深研妙理定乾坤”开篇点题&#xff0c;展现出对深奥道理的钻研与探…

Hot100之普通数组

53最大子数组和 题目 思路解析 我们用一个dp数组来收集我们从左往右&#xff0c;加起来的最大的和 也就是我们的节点不是负数&#xff0c;那我们直接收集就好了 如果是负数&#xff0c;我们就用Max&#xff08;&#xff09;比较是这个节点大还是当前节点大&#xff08;这个情…

如何利用天赋实现最大化的价值输出-补

原文&#xff1a; https://blog.csdn.net/ZhangRelay/article/details/145408621 ​​​​​​如何利用天赋实现最大化的价值输出-CSDN博客 如何利用天赋实现最大化的价值输出-CSDN博客 引用视频差异 第一段视频目标明确&#xff0c;建议也非常明确。 录制视频的人是主动性…

新能源算力战争:为什么AI大模型需要绿色数据中心?

新能源算力战争:为什么AI大模型需要绿色数据中心? 近年来,人工智能(AI)大模型的爆发式增长正在重塑全球科技产业的格局。以GPT-4、Gemini、Llama等为代表的千亿参数级模型,不仅需要海量数据训练,更依赖庞大的算力支撑。然而,这种算力的背后隐藏着一个日益严峻的挑战——…

Spring Boot 中的事件发布与监听:深入理解 ApplicationEventPublisher(附Demo)

目录 前言1. 基本知识2. Demo3. 实战代码 前言 &#x1f91f; 找工作&#xff0c;来万码优才&#xff1a;&#x1f449; #小程序://万码优才/r6rqmzDaXpYkJZF 基本的Java知识推荐阅读&#xff1a; java框架 零基础从入门到精通的学习路线 附开源项目面经等&#xff08;超全&am…

unity学习24:场景scene相关生成,加载,卸载,加载进度,异步加载场景等

目录 1 场景数量 SceneManager.sceneCount 2 直接代码生成新场景 SceneManager.CreateScene 3 场景的加载 3.1 用代码加载场景&#xff0c;仍然build setting里先加入配置 3.2 卸载场景 SceneManager.UnloadSceneAsync(); 3.3 同步加载场景 SceneManager.LoadScene 3.3.…

【Android】布局文件layout.xml文件使用控件属性android:layout_weight使布局较为美观,以RadioButton为例

目录 说明举例 说明 简单来说&#xff0c;android:layout_weight为当前控件按比例分配剩余空间。且单个控件该属性的具体数值不重要&#xff0c;而是多个控件的属性值之比发挥作用&#xff0c;例如有2个控件&#xff0c;各自的android:layout_weight的值设为0.5和0.5&#xff0…