【C++】——string(模拟实现)
文章目录
- string类构造
- string类拷贝构造
- string类析构
- string类运算符重载
- string类部分常用接口的模拟实现
这篇博客中构造、拷贝构造、析构、还有一些短小频繁调用的函数就不用做函数和定义分离,因为在类中,这种函数会默认是内联函数
string类构造
构造函数有一些容易忽略的细节,我会在下面的代码注释中说明
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace sg
{class string{public:string()//:_str(nullptr) // 不能这么写,因为当我string对象为空,程序解引用到\0才会终止,遇不到就会崩溃:_str(new char[1]{'\0'}) // 空间里至少要有一个字符, _size(0), _capacity(0){}//构造函数string(const char* str){_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);}private:char* _str;size_t _size;size_t _capacity;};void test_string1();}
还有另一种写法,不用初始化,直接在构造函数的参数给上缺省值
/*string():_str(new char[1]{'\0'}), _size(0), _capacity(0)
{}*/
//构造函数
//string(string(const char* str = nullptr)
// 如果参数又给空,程序还是会崩,C语言规定常量字符串后面都会有\0,所以直接给空字符串就行
string(const char* str = "")
{_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);
}
string类拷贝构造
如果使用默认拷贝构造,会引发浅拷贝问题,就是当两个对象指向同一块资源时,释放资源后,会导致一块资源被析构两次,程序会报错。所以自己写一个深拷贝最好
//拷贝构造函数
//s2(s1)
string(const string& s)// this就是s2
{_str = new char[s._capacity + 1]; // 开一个和s1一样大的空间strcpy(_str, s._str); _size = s._size;_capacity = s._capacity;
}
string类析构
string的析构和c语言栈实现中的销毁栈大差不差,如果有疑问可以参考这一篇博客
C语言栈和队列
//析构函数
~string()
{if (_str) //检查一下_str是否为空,如果为空就不用再释放空间了{delete[] _str;_str = nullptr;_size = _capacity = 0;} }
string类运算符重载
string.h
char& operator[](size_t pos)
{assert(pos < _size);return _str[pos];
}
const char& operator[](size_t pos) const
{assert(pos < _size);return _str[pos];
}
string.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include "practice-string.h"
namespace sg
{void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 2;}for (auto e : s2){cout << e << " ";}cout << endl;cout << s2.c_str() << endl;}
}
我通过测试,发现并不能用范围for遍历,报错显示未找到匹配的begin函数,需要我们自己实现
范围for看着很方便,但本质就是迭代器,迭代器模拟的是指针的行为,所以我们返回原生指针即可
string.h
typedef char* iterator;
typedef char* const_iterator;
iterator begin()
{return _str;
}
iterator end()
{return _str + _size;
}
const_iterator begin() const
{return _str;
}const_iterator end() const
{return _str + _size;
}
赋值运算符
string operator=(const string& s)
{if (this != &s)//地址相同,就是自己赋值给自己{delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;
}
string类部分常用接口的模拟实现
string.h
#pragma once
#include<iostream>
#include<assert.h>
#include<string.h>
using namespace std;
namespace sg
{class string{public:typedef char* iterator;typedef char* const_iterator;iterator begin(){return _str;}iterator end(){return _str + _size;}const_iterator begin() const{return _str;}const_iterator end() const{return _str + _size;}/*string():_str(new char[1]{'\0'}), _size(0), _capacity(0){}*///构造函数string(const char* str = ""){_size = strlen(str);_capacity = strlen(str);_str = new char[strlen(str) + 1];strcpy(_str, str);}//析构函数~string(){delete[] _str;_str = nullptr;_size = _capacity = 0;}//拷贝构造函数//s2(s1)string(const string& s){_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}const char* c_str() const{return _str;}size_t size() const{return _size;}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}const char& operator[](size_t pos) const{assert(pos < _size);return _str[pos];}// s2 = s1// s1 = s1string operator=(const string& s){if (this != &s)//地址相同,就是自己赋值给自己{delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}return *this;}void clear(){_str[0] = '\0';_size = 0;}void reserve(size_t n);void push_back(char ch);void append(const char* str);string& operator+=(char ch);string& operator+=(const char* str);void insert(size_t pos, char ch);void insert(size_t pos, const char* str);void erase(size_t pos, size_t len = npos);size_t find(char ch, size_t pos = 0);size_t find(const char* str, size_t pos = 0);string substr(size_t pos = 0, size_t len = npos);private:char* _str;size_t _size;size_t _capacity;static const size_t npos;};void test_string1();void test_string2();bool operator<(const string& s1, const string& s2);bool operator<=(const string& s1, const string& s2);bool operator>(const string& s1, const string& s2);bool operator>=(const string& s1, const string& s2);bool operator!=(const string& s1, const string& s2);bool operator==(const string& s1, const string& s2);ostream& operator<<(ostream& out, const string& s);istream& operator>>(istream& in, string& s);
}
string.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace sg
{const size_t string::npos = -1;//声明和定义分离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){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;++_size;_str[_size] = '\0';}string& string::operator+=(char ch){push_back(ch);return *this;}void string::append(const char* str){size_t len = strlen(str);if (_size + len > _capacity){//大于二倍,需要多少开多少,小于二倍,就按二倍扩reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}strcpy(_str + _size, str);//从\0开始拷贝,\0会自动被挤到后面_size += len;}string& string::operator+=(const char* str){append(str);return *this;}void string::insert(size_t pos, char ch){assert(pos < _size);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}//挪动数据/*size_t end = _size;while (end >= pos){_str[end + 1] = _str[end];--end;}*///挪动数据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);if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}size_t len = strlen(str);size_t end = _size + len;while (end >= pos + len){_str[end] = _str[end - len];--end;}for (size_t i = 0; i < len; i++){_str[pos + i] = str[i];}_size += len;}void string::erase(size_t pos, size_t len){if (len >= _size - pos){_str[pos] = '\0';_size = pos;}else{for (size_t i = pos + len; i <= _size; i++){_str[i - len] = _str[i];}_size -= len;}}size_t string::find(char ch, size_t pos){assert(pos < _size);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){assert(pos < _size);const char* ptr = strstr(_str + pos, str);if (ptr == nullptr){return npos;}else{return ptr - _str;}}string string::substr(size_t pos = 0, size_t len){assert(pos < _size);if (len > _size - pos){len = _size - pos;}string sub;sub.reserve(len);for (size_t i = 0; i < len; i++){sub += _str[pos + i];}return sub;}bool operator<(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) < 0;}bool operator<=(const string& s1, const string& s2){return s1 == s2 || s1 < s2;}bool operator>(const string& s1, const string& s2){return !(s1 <= s2);}bool operator>=(const string& s1, const string& s2){return !(s1 < s2);}bool operator!=(const string& s1, const string& s2){return !(s1 == s2);}bool operator==(const string& s1, const string& s2){return strcmp(s1.c_str(), s2.c_str()) == 0;}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}istream& operator>>(istream& in, string& s){s.clear();//创造一块缓冲const int N = 256;char buffer[N];int i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\0'){buffer[i++] == ch;if (i == N - 1)// buffer条件{buffer[i] = '\0';s += buffer;i = 0;}if (i > 0){buffer[i] = '\0';s += buffer;}return in;}}void test_string1(){string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;for (size_t i = 0; i < s2.size(); i++){s2[i] += 2;}cout << s2.c_str() << endl;}void test_string2(){string s1("hello world");s1 += '!';s1 += '#';cout << s1.c_str() << endl;s1 += "renqing";cout << s1.c_str() << endl;s1.insert(0, '#');cout << s1.c_str() << endl;string s2("hello world");s2.insert(5, "big");cout << s2.c_str() << endl;s2.erase(5, 3);cout << s2.c_str() << endl;}}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
int main()
{//sg::test_string1();sg::test_string2();return 0;
}
相关文章:
【C++】——string(模拟实现)
文章目录 string类构造string类拷贝构造string类析构string类运算符重载string类部分常用接口的模拟实现 这篇博客中构造、拷贝构造、析构、还有一些短小频繁调用的函数就不用做函数和定义分离,因为在类中,这种函数会默认是内联函数 string类构造 构造函…...
c++20 std::format 格式化说明
在标头<format>定义 ()功能很强大,它把字符串当成一个模板,通过传入的参数进行格式化,并且使用大括号‘{}’作为特殊字符代替‘%’。 1、基本用法 (1)不带编号,即“{}”(2)带…...
HTB-Unified(log4j2漏洞、MongoDb替换管理员密码)
前言 各位师傅大家好,我是qmx_07,今天给大家讲解Unified靶机 渗透过程 信息搜集 服务器开放了SSH服务,HTTP服务 访问网站 验证log4j2漏洞 8443端口:UniFi 网络 ,访问查询 是否有Nday漏洞利用 可以观察到UniFi的版…...
每天五分钟深度学习PyTorch:不同的神经网络层设置不同的学习率
本文重点 我们前面学习了基本网络模型的搭建,获取网络模型的子结构,以及优化器optim,我们发现我们设置优化器的时候,是对整个模型设置的,也就是说整个模型的参数学习率是一样,本节课程我们学习如何给不同的网络层设置不同的学习率。主要还是通过优化器optim来实现的,本…...
【渗透测试】——DVWA靶场搭建
📖 前言:DVWA(Damn Vulnerable Web Application)是一个用于安全漏洞测试的 PHP/MySQL 网络应用,旨在为安全专业人士提供一个合法的环境,以测试他们的技能和工具,同时帮助 Web 开发者更好地理解 …...
国内人工智能产业发展现状及对策研究
一、引言 人工智能作为新时代科技革命和产业变革的核心力量,正深刻改变着全球经济格局。我国政府高度重视人工智能产业发展,将其列为国家战略性新兴产业。在此背景下,本文旨在分析我国人工智能产业发展现状,探讨面临的挑战&#x…...
完整版订单超时自动取消功能
前几天对实习还是继续学习技术产生了抉择,问了一个前辈,他抛给我一个问题,怎么做15分钟订单自动取消,我说然后到时间之后,自动执行这个订单关闭业务,比如把锁了的库存给解开等等操作,然后在数据…...
算法刷题:300. 最长递增子序列、674. 最长连续递增序列、718. 最长重复子数组、1143. 最长公共子序列
300. 最长递增子序列 1.dp定义:dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.递推公式:if (nums[i] > nums[j]) dp[i] max(dp[i], dp[j] 1); 注意这里不是要dp[i] 与 dp[j] 1进行比较,而是我们要取dp[j] 1的最大值…...
go 笔记
数据结构与 方法(增删改查) 安装goland,注意版本是2024.1.1,不是2024.2.1,软件下载地址也在链接中提供了 ‘go’ 不是内部或外部命令,也不是可运行的程序 或批处理文件。 在 Windows 搜索栏中输入“环境变量”&#…...
路由等保测评
1.身份鉴别 应对登录的用户进行身份标识和鉴别, 身份标识具有唯一性,身份鉴别信息具有复杂度要求并定期更换。 可以使用“ service password-encryption"命令对存储在配置文件中的所有口令和类似数据进行加密, 以避免攻击者通过读取配…...
C# 反射之动态生成dll/exe
这个可能应该属于反射的高级使用范围了,平常在项目中使用的人估计也不是很多。由于使用反射的话会降低性能,比如之前用到的GetValue、SetValue等之类,但是使用这种方式会大大提高效率,在这里我只想说,都直接写IL指令了…...
Rust 所有权 Slices
文章目录 发现宝藏1. Slice 的基础知识1.1 什么是 Slice?1.2 如何创建 Slice? 2. 处理字符串 Slice2.1 字符串的 Slice2.2 字符串的 Unicode 和切片 3. 在函数中使用 Slice3.1 传递 Slice 给函数3.2 可变 Slice 的函数 4. 复杂示例4.1 处理多维数组的 Sl…...
windows 安全与网络管理问题
问题:当编写的脚本或程序运行的时候,可能被windows阻止访问网络甚至被删除 避免被删除 wini 进入设置界面 -> 选择更新与安全 -> 选择windwos defender -> 点击添加排除项,将指定的文件或目录排除,避免被软件删除 允许…...
基于Python实现一个庆祝国庆节的小程序
功能: 添加互动功能:允许用户选择不同的祝福语或者查询不同的国庆节信息。动态背景音乐:播放国庆节相关的背景音乐。增加节日小测验:提供一些关于国庆节的趣味小测验,让用户参与。增强图形用户界面 (GUI):…...
Anaconda 安装与使用教程
Anaconda 安装与使用教程 介绍 Anaconda 是一个用于科学计算的 Python 和 R 的发行版,它包含了众多流行的科学计算、数据分析、机器学习等领域的库。本教程旨在帮助初学者快速上手 Anaconda,并学会如何使用其管理环境以及安装包。 第一步:…...
时序预测SARIMAX模型
1. 项目背景 本文基于kaggle平台相关竞赛项目,具体连接如下: Time Series Forecasting With SARIMAX 基本信息如内容说明、数据集、已提交代码、当前得分排名以及比赛规则等,如图【1】所示,可以认真阅读。 图 1 2. 数据读取 …...
gin集成jaeger中间件实现链路追踪
1. 背景 新业务线带来新项目启动,需要改进原有项目的基础框架和组件能力,以提升后续开发和维护效率。项目搭建主要包括技术选型、框架搭建、基础服务搭建等。这其中就涉及到链路追踪的内容,结合其中的踩坑情况,用一篇文章来说明完…...
前端层面----监控与埋点
前言: 站在产品的视角,经常会问如下几个问题: 产品有没有用户使用 用户用得怎么样 系统会不会经常出现异常 如何更好地满足用户需求服务用户 当站在技术视角时,经常会问如下几个问题: 系统出现异常的频率如何 异常…...
linux Command
linux Command 1. 系统监控命令 1.1 top top [param] top -H -p pid,查看进程pid下面的子线程。-b以处理模式操作-c显示完整的命令行而不只是显示命令名。-d 屏幕刷新间隔时间。-l 忽略失效过程。-s 保密模式。-S 累积模式。-u 【用户名】 指定用户名。-p 【进程…...
uniapp登录页面( 适配:pc、小程序、h5)
<!-- 简洁登录页面 --> <template><view class"login-bg"><image class"img-a" src"https://zhoukaiwen.com/img/loginImg/2.png"></image><image class"img-b" src"https://zhoukaiwen.com/im…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
进程地址空间(比特课总结)
一、进程地址空间 1. 环境变量 1 )⽤户级环境变量与系统级环境变量 全局属性:环境变量具有全局属性,会被⼦进程继承。例如当bash启动⼦进程时,环 境变量会⾃动传递给⼦进程。 本地变量限制:本地变量只在当前进程(ba…...
Leetcode 3576. Transform Array to All Equal Elements
Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接:3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
【碎碎念】宝可梦 Mesh GO : 基于MESH网络的口袋妖怪 宝可梦GO游戏自组网系统
目录 游戏说明《宝可梦 Mesh GO》 —— 局域宝可梦探索Pokmon GO 类游戏核心理念应用场景Mesh 特性 宝可梦玩法融合设计游戏构想要素1. 地图探索(基于物理空间 广播范围)2. 野生宝可梦生成与广播3. 对战系统4. 道具与通信5. 延伸玩法 安全性设计 技术选…...
rnn判断string中第一次出现a的下标
# coding:utf8 import torch import torch.nn as nn import numpy as np import random import json""" 基于pytorch的网络编写 实现一个RNN网络完成多分类任务 判断字符 a 第一次出现在字符串中的位置 """class TorchModel(nn.Module):def __in…...
让回归模型不再被异常值“带跑偏“,MSE和Cauchy损失函数在噪声数据环境下的实战对比
在机器学习的回归分析中,损失函数的选择对模型性能具有决定性影响。均方误差(MSE)作为经典的损失函数,在处理干净数据时表现优异,但在面对包含异常值的噪声数据时,其对大误差的二次惩罚机制往往导致模型参数…...
JVM虚拟机:内存结构、垃圾回收、性能优化
1、JVM虚拟机的简介 Java 虚拟机(Java Virtual Machine 简称:JVM)是运行所有 Java 程序的抽象计算机,是 Java 语言的运行环境,实现了 Java 程序的跨平台特性。JVM 屏蔽了与具体操作系统平台相关的信息,使得 Java 程序只需生成在 JVM 上运行的目标代码(字节码),就可以…...
安宝特案例丨Vuzix AR智能眼镜集成专业软件,助力卢森堡医院药房转型,赢得辉瑞创新奖
在Vuzix M400 AR智能眼镜的助力下,卢森堡罗伯特舒曼医院(the Robert Schuman Hospitals, HRS)凭借在无菌制剂生产流程中引入增强现实技术(AR)创新项目,荣获了2024年6月7日由卢森堡医院药剂师协会࿰…...
