当前位置: 首页 > news >正文

c++ string类 +底层模拟实现

提醒:

本片博客只是小编的听课笔记,介意勿看。

基础

包含在头文件<string>,才能使用string类似函数接口。

string常见构造类

string s1; 
cin>>s1;//无参构造
string s2(s1);//拷贝构造
string s1("jfksa");//传参构造

三种遍历方式

//三种遍历方式
//s.begin()返回第一个字符
//s.end();返回最后一个字符的下一个位置(\0位置)
//一operator【】
for (int i = 0; i < s2.size(); i++) {cout << s2[i];
}
cout << endl;
//二.迭代器iterator
string::iterator it = s2.begin();//it类似于指针,但本质可能和是运算符重载
while (it != s2.end()) {cout << *it;//*it类似于解引用。本质也像是运算符重载it++;
}
cout << endl;
//三。范围for进行遍历
//范围for进行遍历
string s3("llpphh");
for (auto ch : s3) {cout << ch << " ";
}
cout << endl;

迭代器和范围for的去区别

两则底层逻辑相同,但是对于迭代器来讲可以在迭代器中修改变量值(因为底层类似指针可以直接修改对应地址的·1值),而对于范围for来讲,(auto ch: s2)相当于是一个拷贝,修改ch的值并不能修改实参的值,所以需要用引用(auto& ch: s2)才能修改变量的值。

auto

使用价值:方便类型推导

string::ioterator it=    //变量名太长
auto it =    ;  //简化

typeid(变量名).name()//判断变量类型

string迭代器

iterator //正向const_iterator //constreverse_iterator //反向const_reverse_iterator //const 反向

对应案列如下

string s4("hello world");
//正向
string::iterator it1 = s4.begin();
while (it1 != s4.end()) {cout << *it1;it1++;
}
cout << endl;
//反向迭代器
string::reverse_iterator rit = s4.rbegin();
while (rit != s4.rend()) {cout << *rit;rit++;
}
cout << endl;
const string s5("hello world");
//const迭代器
string::const_iterator it2 = s5.begin();
while (it2 != s5.end()) {cout << *it2;it2++;
}
cout << endl;
//const反向迭代器
string::const_reverse_iterator it3 = s5.rbegin();
while (it3 != s5.rend()) {cout << *it3;it3++;
}
cout << endl;

string 容器

size()/length()

//size获取字符长度
string s2("lvpanhao");
cout << s2.size() << endl;//经常用
cout << s2.length() << endl;//不具有通用性

capacity()扩容

s.reverse(n)//提前开n个空间

s.clear()//清除字符串/不清楚容量

s.push_back('x');//尾插字符
s.append("aaaaaaaa");//尾插字符串

insert/头插

s.insert('x'/"hujkf");//可以是字符也可以是字符串

erase//指定位置删除字符

s.erase(pos ,n)//pos位置删除n个字符
s.erase(s.begin());//迭代器版本头删

replace();//替换

replace(pos,n,'%%');//pos的n个位置替换成%%

substr//构建子串、

string s5("lvpanhao");
cout << s5.substr(2, 3) << endl;//下表为2 长度为3的子串

find//查找指定字符/指定字符串

int pos=s.find(' ');//返回找到字符的下标
//把所有空格替换为%
//替换所有空格为%
string s4("hello world I am Lihua");
int pos = s4.find(' ');
while (pos != string::npos) {s4.replace(pos, 1, "%%");pos = s4.find(' ');//每次从头开始找替换为int pod=s.find(' ',pos);//从某个位置开始找字符
}
cout << s4 << endl;

rfind/倒着找

//利用场景
//倒着找文件后缀方法
int pos1 = s6.rfind('.');
cout << s6.substr(pos1) << endl;
string s7("test.cpp.zip");
int pos2 = s7.rfind('.');
cout << s7.substr(pos2) << endl;

ind_first_of("abcd")//查找abcd所在位置

find_last_of("abcd")//倒着找查找不是abcd的全替换

string s8("hello world i love you");
//把aeiou字符改为*
size_t pos3 = s8.find_first_of("aeiou");
while (pos3 != string::npos) {s8.replace(pos3,1,"*");pos3 = s8.find_first_of("aeiou",pos3+1);
}
cout << s8 << endl;

getline()遇到换行才终止

string s1;
getline(cin,s1,)
//自己加终止条件
getLine(cin,s1,‘*‘);//默认遇到*终止

c_str()

相当于一个字符一个字符读取字符串,遇到,‘\0’会终止读取。

字符串匹配

strstr算法

strstr(const char* str1,const char* str2);

str2字串/str1主串

字串str2返回str1中的第一个位置字符

优化拷贝构造(赋值重载)

传统拷贝构造(赋值重载)

//拷贝构造
string& string(const string& s1){//必须先自己申请空间_str=new char[n];strcpy(_str,s1._str);_size=s1.size;_capacity=s1._capacity;
}
//赋值重载
string& string(const string& s1){//必须先自己申请空间delete[] _str;_str=new char[n];strcpy(_str,s1._str);_size=s1.size;_capacity=s1._capacity;
}

现代拷贝构造

//利用交换函数
string& string(const string& s1){
    string tem(s1);
    (this)->swap(tem);
}

最简单拷贝构造/赋值重载

string& string(string s1){//s1是局部变量直接进行交换swap(s1);//this->swap(s1);
}

写时拷贝

对于拷贝构造,对自定义类型完成神拷贝,浅拷贝(一个字节一个字节拷贝)并不能满足,原因如下

1.析构两次

2.修改内容时修改两个指针指向的内容

对于写时拷贝只试用满足原因1,并不能满足条件2(自己进行扩容规深拷贝)

string类模拟实现

string.h
#pragma once
#include<iostream>
#include<assert.h>
using namespace std;
namespace lph {class string {public:typedef char* iterator;重载无参函数//string()//	:_str(nullptr)//	,_size(0)//	,_capacity(0)//{}带参数构造//string(const char* str) {//	_size = strlen(str);//	_capacity = _size;//	_str = new char[_size + 1];//	strcpy(_str, str);//}//迭代器begin使用iterator begin() {return _str;}//end使用iterator end() {return _str + _size;}// 全缺省string(const char* str = "") {_size = strlen(str);_capacity = _size;_str = new char[_capacity + 1];strcpy(_str, str);}//输出const char* c_str() {return _str;}//获取size大小size_t size() {return _size;}//获取总空间大小size_t capacity() {return _capacity;}//循环遍历char& operator[](size_t pos) {assert(pos < _size);return _str[pos];}//拷贝构造string(const string& s) {_str = new char[s._capacity+1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;}//赋值重载//s1=s2string& operator=(const string& s) {delete[] _str;_str = new char[s._capacity + 1];strcpy(_str, s._str);_size = s._size;_capacity = s._capacity;return *this;}//扩容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() {delete[] _str;_size = _capacity = 0;}//中间插入void insert(size_t pos, char ch);void insert(size_t pos, const char* str);//删除字符void erase(size_t pos, size_t len);//查找指定字符size_t find(char ch, size_t pos = 0);//查找指定字串size_t find(const char* str, size_t pos);//从某个位置获取多长的字符 string substr(size_t pos, size_t len);private:char* _str;size_t _size;size_t _capacity;};void test1();void test2();void test3();//比较函数实现bool operator<(string& s1, string& s2);bool operator<=(string& s1, string& s2);bool operator>(string& s1, string& s2);bool operator>=(string& s1, string& s2);bool operator==(string& s1, string& s2);bool operator!=( string& s1,  string& s2);}
string.cpp#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"
namespace lph {void test1() {cout << "::test1::" << endl;string s1;string s2("hello world");cout << s1.c_str() << endl;cout << s2.c_str() << endl;cout << s2.size() << endl;cout << s2.capacity() << endl;cout << s2[6] << endl;//普通遍历for (size_t i = 0; i < s2.size(); i++) {cout << s2[i];}cout << endl;//for遍历for (auto ch : s2) {cout << ch;}cout << endl;//迭代器遍历string::iterator it = s2.begin();while (it != s2.end()) {cout << *it;it++;}cout << endl;cout << endl;cout << endl;cout << endl;}void test2() {cout << "::test2::" << endl;string s1("hello world");s1.push_back('x');cout << s1.c_str() << endl;s1 += 'p';cout << s1.c_str() <<endl;string s2("hello world");s2 += " lvpanhao";cout << s2.c_str() <<endl;//头插cout << "::test::" << endl;string s3("hello world");s3.insert(5, 'x');cout << s3.c_str() <<endl;string s4("hello world");s4.insert(5, "@@@@@");cout << s4.c_str() << endl;cout << "::test::" << endl;string s5("hello world");s5.erase(5, 10);cout << s5.c_str() << endl;string s6("hello world");s6.erase(5, 3);cout << s6.c_str() << endl;}void test3() {string s1("hello world");cout << s1.find('o',0) << endl;string s2("hello lvpanhao world");string s= s2.substr(6,8);cout << s.c_str() << endl;string copy(s2);cout << copy.c_str() << endl;string s3=(copy = s);cout << s3.c_str() << endl;string s4("hello");string s5("woshi");cout << (s4 < s5) << endl;cout << (s4 == s5) << endl;cout << (s4 > s5) << endl;//拷贝构造string s6("lvpanhao");string s7("nihao");string s8(s6);cout << s8.c_str() << endl;//赋值重载s6=s7;cout << s6.c_str() << endl;}void string::reserve(size_t n) {if (n > _capacity) {char* tem = new char[n + 1];strcpy(tem, _str);delete[] _str;_str = tem;_capacity = n;}}void string::push_back(char ch) {//扩容if (_size == _capacity) {reserve(_capacity == 0 ? 4 : 2 * _capacity);}_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 (len + _size > _capacity) {reserve(len + _size > 2 * _capacity ? len + _size : 2 * _capacity);}strcpy(_str + _size, str);_size += len;}string& string::operator+=(const char* str) {append(str);return *this;}//中间插入void string::insert(size_t pos, char ch) {if (_size == _capacity) {reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size + 1;while (end >= pos) {_str[end] = _str[end - 1];end--;}_str[pos] = ch;_size+=1;}void string::insert(size_t pos, const char* str) {assert(pos < _size);size_t len = strlen(str);if (_size + len > _capacity) {//扩容reserve(_size + len > 2 * _capacity ? _size + len : 2 * _capacity);}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++] = 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[pos++] = _str[i];}_size -= len;}}//查找指定字符size_t string::find(char ch, size_t pos) {for (size_t i = pos; i < _size; i++) {if (ch == _str[i]) {return i;}}return -1;}//查找指定字串size_t string::find(const char* str, size_t pos) {assert(pos < _size);char* ptr = strstr(_str+pos, str);if (ptr == nullptr) {return -1;}else {return ptr - _str;}}//从某个位置获取多长的字符 string string::substr(size_t pos, 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<(string& s1,  string& s2) {return strcmp(s1.c_str(), s2.c_str())<0;}bool operator<=( string& s1,  string& s2) {return (s1 < s2) || (s1 == s2);}bool operator>( string& s1,string& s2) {return !(s1 <= s2);}bool operator>=(string& s1, string& s2) {return !(s1 < s2);}bool operator==(string& s1,string& s2) {return strcmp(s1.c_str(), s2.c_str()) == 0;}bool operator!=(string& s1,string& s2) {return !(s1 == s2);}//自定义插入ostream& operator<<(ostream& out, string& s) {for (auto ch : s) {out << ch;}return out;}istream& operator>>(istream& ci, string& s) {char ch;//ci >> ch;//遇到空格或换行会默认未字符串ch = ci.get();while (ch != ' ' || ch != '\0') {s += ch;//ci >> ch;ch = ci.get();}return ci;}
}
#define _CRT_SECURE_NO_WARNINGS 1
#include"string.h"int main() {lph::test1();lph::test2();lph::test3();return 0;}

相关文章:

c++ string类 +底层模拟实现

提醒: 本片博客只是小编的听课笔记&#xff0c;介意勿看。 基础 包含在头文件<string>&#xff0c;才能使用string类似函数接口。 string常见构造类 string s1; cin>>s1;//无参构造 string s2(s1);//拷贝构造 string s1("jfksa");//传参构造 三种…...

六十分之三十七——一转眼、时光飞逝

一、目标 明确可落地&#xff0c;对于自身执行完成需要一定的努力才可以完成的 1.第三版分组、激励、立体化权限、智能设备、AIPPT做课 2.8本书 3.得到&#xff1a;头条、吴军来信2、卓克科技参考3 4.总结思考 二、计划 科学规律的&#xff0c;要结合番茄工作法、快速阅读、…...

Shell基础:中括号的使用

在Shell脚本中&#xff0c;中括号&#xff08;[ ... ] 和 [[ ... ]]&#xff09;是一种常见的条件测试结构。它们用于进行文件类型检查、值比较以及逻辑判断。通过了解它们的不同特点和用法&#xff0c;能够帮助你编写更加高效、安全且易读的脚本。本文将详细介绍Shell中单中括…...

《基于Scapy的综合性网络扫描与通信工具集解析》

在网络管理和安全评估中&#xff0c;网络扫描和通信是两个至关重要的环节。Python 的 Scapy 库因其强大的网络数据包处理能力&#xff0c;成为开发和实现这些功能的理想工具。本文将介绍一个基于 Scapy 编写的 Python 脚本&#xff0c;该脚本集成了 ARP 扫描、端口扫描以及 TCP…...

面经--C语言——sizeof和strlen,数组和链表,#include <>和 #include ““ #define 和typedef 内存对齐概述

文章目录 sizeof 和 strlen数组和链表总结 #include <>和 #include ""#define 和typedef内存对齐概述对齐规则示例&#xff1a;结构体的内存对齐分析&#xff1a; 内存对齐的常见规则&#xff1a;填充字节的计算对齐影响的实际例子 sizeof 和 strlen 特性size…...

使用 Kotlin 将 Vertx 和 Springboot 整合

本篇文章目的是将 Springboot 和 Vertx 进行简单整合。整合目的仅仅是为了整活&#xff0c;因为两个不同的东西整合在一起提升的性能并没有只使用 Vertx 性能高&#xff0c;因此追求高性能的话这是在我来说不推荐。而且他们不仅没有提高很多性能甚至增加了学习成本 一、整合流…...

线性回归算法-01

线性回归简介 学习目标 了解线性回归的应用场景知道线性回归的定义 1 线性回归应用场景 房价预测销售额度预测贷款额度预测 2 什么是线性回归 2.1 定义与公式 线性回归(Linear regression)是利用 回归方程(函数)对 一个或多个自变量(特征值)和因变量(目标值)之间关系进行建模…...

洛谷 P1130 红牌 C语言

题目描述 某地临时居民想获得长期居住权就必须申请拿到红牌。获得红牌的过程是相当复杂&#xff0c;一共包括 N 个步骤。每一步骤都由政府的某个工作人员负责检查你所提交的材料是否符合条件。为了加快进程&#xff0c;每一步政府都派了 M 个工作人员来检查材料。不幸的是&…...

虚幻UE5手机安卓Android Studio开发设置2025

一、下载Android Studio历史版本 步骤1&#xff1a;虚幻4.27、5.0、5.1、5.2官方要求Andrd Studio 4.0版本&#xff1b; 5.3、5.4、5.5官方要求的版本为Android Studio Flamingo | 2022.2.1 Patch 2 May 24, 2023 虚幻官网查看对应Andrd Studiob下载版本&#xff1a; https:/…...

线性代数复习笔记

1. 课程学习 1.1 3Blue1Brown 线性代数 2. 基本术语 eigenvector&#xff08;特征向量&#xff09;&#xff1a;线性变换中方向保持不变的向量 可以视作3D旋转矩阵形成的旋转的轴...

你需要更深层次的解放

先谈一谈理性认知中的属性替换原则。简单来说&#xff0c;属性替换就是用简单的问题取代难题。 当人们需要评估属性A时&#xff0c;却发现评估属性B更容易一些&#xff08;A与B之间存在一定的关系&#xff09;&#xff0c;于是就改为评估属性B。这叫做属性替换。 作为一种认知…...

机器学习算法在网络安全中的实践

机器学习算法在网络安全中的实践 本文将深入探讨机器学习算法在网络安全领域的应用实践&#xff0c;包括基本概念、常见算法及其应用案例&#xff0c;从而帮助程序员更好地理解和应用这一领域的技术。"> 序言 网络安全一直是信息技术领域的重要议题&#xff0c;随着互联…...

Qt事件处理:理解处理器、过滤器与事件系统

1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中&#xff0c;所有事件都继承自 QEvent &#xff0c;并且每个事件都有特定的标识符&#xff0c;如&#xff1a;Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息&#xff…...

DeepSeek相关技术整理

相关介绍 2024年12月26日&#xff0c;DeepSeek V3模型发布&#xff08;用更低的训练成本&#xff0c;训练出更好的效果&#xff09;671B参数&#xff0c;激活37B。2025年1月20日&#xff0c;DeepSeek-R1模型发布&#xff08;仅需少量标注数据&#xff08;高质量长cot&#xff…...

DeepSeek 遭 DDoS 攻击背后:DDoS 攻击的 “千层套路” 与安全防御 “金钟罩”

当算力博弈升级为网络战争&#xff1a;拆解DDoS攻击背后的技术攻防战——从DeepSeek遇袭看全球网络安全新趋势 在数字化浪潮席卷全球的当下&#xff0c;网络已然成为人类社会运转的关键基础设施&#xff0c;深刻融入经济、生活、政务等各个领域。从金融交易的实时清算&#xf…...

蓝桥杯之c++入门(二)【输入输出(上)】

目录 前言1&#xff0e;getchar和 putchar1.1 getchar()1.2 putchar() 2&#xff0e;scanf和 printf2.1 printf2.1.1基本用法2.1.2占位符2.1.3格式化输出2.1.3.1 限定宽度2.1.3.2 限定小数位数 2.2 scanf2.2.1基本用法2.2.2 占位符2.2.3 scanf的返回值 2.3练习练习1&#xff1a…...

消息队列应用示例MessageQueues-STM32CubeMX-FreeRTOS《嵌入式系统设计》P343-P347

消息队列 使用信号量、事件标志组和线标志进行任务同步时&#xff0c;只能提供同步的时刻信息&#xff0c;无法在任务之间进行数据传输。要实现任务间的数据传输&#xff0c;一般使用两种方式&#xff1a; 1. 全局变量 在 RTOS 中使用全局变量时&#xff0c;必须保证每个任务…...

算法题(55):用最少数量的箭引爆气球

审题&#xff1a; 本题需要我们找到最少需要的箭数&#xff0c;并返回 思路: 首先我们需要把本题描述的问题理解准确 &#xff08;1&#xff09;arrow从x轴任一点垂直射出 &#xff08;2&#xff09;一旦射出&#xff0c;无限前进 也就是说如果气球有公共区域&#xff08;交集&…...

谭浩强C语言程序设计(4) 8章(下)

1、输入三个字符串按照字母顺序从小到大输出 #include <cstdio> // 包含cstdio头文件&#xff0c;用于输入输出函数 #include <cstring> // 包含cstring头文件&#xff0c;用于字符串处理函数#define N 20 // 定义字符串的最大长度为20// 函数&#xff1a;…...

AlexNet论文代码阅读

论文标题&#xff1a; ImageNet Classification with Deep Convolutional Neural Networks 论文链接&#xff1a; https://volctracer.com/w/BX18q92F 代码链接&#xff1a; https://github.com/dansuh17/alexnet-pytorch 内容概述 训练了一个大型的深度卷积神经网络&#xf…...

CVPR 2025 MIMO: 支持视觉指代和像素grounding 的医学视觉语言模型

CVPR 2025 | MIMO&#xff1a;支持视觉指代和像素对齐的医学视觉语言模型 论文信息 标题&#xff1a;MIMO: A medical vision language model with visual referring multimodal input and pixel grounding multimodal output作者&#xff1a;Yanyuan Chen, Dexuan Xu, Yu Hu…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别

一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

在 Nginx Stream 层“改写”MQTT ngx_stream_mqtt_filter_module

1、为什么要修改 CONNECT 报文&#xff1f; 多租户隔离&#xff1a;自动为接入设备追加租户前缀&#xff0c;后端按 ClientID 拆分队列。零代码鉴权&#xff1a;将入站用户名替换为 OAuth Access-Token&#xff0c;后端 Broker 统一校验。灰度发布&#xff1a;根据 IP/地理位写…...

Matlab | matlab常用命令总结

常用命令 一、 基础操作与环境二、 矩阵与数组操作(核心)三、 绘图与可视化四、 编程与控制流五、 符号计算 (Symbolic Math Toolbox)六、 文件与数据 I/O七、 常用函数类别重要提示这是一份 MATLAB 常用命令和功能的总结,涵盖了基础操作、矩阵运算、绘图、编程和文件处理等…...

成都鼎讯硬核科技!雷达目标与干扰模拟器,以卓越性能制胜电磁频谱战

在现代战争中&#xff0c;电磁频谱已成为继陆、海、空、天之后的 “第五维战场”&#xff0c;雷达作为电磁频谱领域的关键装备&#xff0c;其干扰与抗干扰能力的较量&#xff0c;直接影响着战争的胜负走向。由成都鼎讯科技匠心打造的雷达目标与干扰模拟器&#xff0c;凭借数字射…...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

浅谈不同二分算法的查找情况

二分算法原理比较简单&#xff0c;但是实际的算法模板却有很多&#xff0c;这一切都源于二分查找问题中的复杂情况和二分算法的边界处理&#xff0c;以下是博主对一些二分算法查找的情况分析。 需要说明的是&#xff0c;以下二分算法都是基于有序序列为升序有序的情况&#xf…...

ios苹果系统,js 滑动屏幕、锚定无效

现象&#xff1a;window.addEventListener监听touch无效&#xff0c;划不动屏幕&#xff0c;但是代码逻辑都有执行到。 scrollIntoView也无效。 原因&#xff1a;这是因为 iOS 的触摸事件处理机制和 touch-action: none 的设置有关。ios有太多得交互动作&#xff0c;从而会影响…...

初学 pytest 记录

安装 pip install pytest用例可以是函数也可以是类中的方法 def test_func():print()class TestAdd: # def __init__(self): 在 pytest 中不可以使用__init__方法 # self.cc 12345 pytest.mark.api def test_str(self):res add(1, 2)assert res 12def test_int(self):r…...

C/C++ 中附加包含目录、附加库目录与附加依赖项详解

在 C/C 编程的编译和链接过程中&#xff0c;附加包含目录、附加库目录和附加依赖项是三个至关重要的设置&#xff0c;它们相互配合&#xff0c;确保程序能够正确引用外部资源并顺利构建。虽然在学习过程中&#xff0c;这些概念容易让人混淆&#xff0c;但深入理解它们的作用和联…...