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类 +底层模拟实现
提醒: 本片博客只是小编的听课笔记,介意勿看。 基础 包含在头文件<string>,才能使用string类似函数接口。 string常见构造类 string s1; cin>>s1;//无参构造 string s2(s1);//拷贝构造 string s1("jfksa");//传参构造 三种…...

六十分之三十七——一转眼、时光飞逝
一、目标 明确可落地,对于自身执行完成需要一定的努力才可以完成的 1.第三版分组、激励、立体化权限、智能设备、AIPPT做课 2.8本书 3.得到:头条、吴军来信2、卓克科技参考3 4.总结思考 二、计划 科学规律的,要结合番茄工作法、快速阅读、…...
Shell基础:中括号的使用
在Shell脚本中,中括号([ ... ] 和 [[ ... ]])是一种常见的条件测试结构。它们用于进行文件类型检查、值比较以及逻辑判断。通过了解它们的不同特点和用法,能够帮助你编写更加高效、安全且易读的脚本。本文将详细介绍Shell中单中括…...

《基于Scapy的综合性网络扫描与通信工具集解析》
在网络管理和安全评估中,网络扫描和通信是两个至关重要的环节。Python 的 Scapy 库因其强大的网络数据包处理能力,成为开发和实现这些功能的理想工具。本文将介绍一个基于 Scapy 编写的 Python 脚本,该脚本集成了 ARP 扫描、端口扫描以及 TCP…...
面经--C语言——sizeof和strlen,数组和链表,#include <>和 #include ““ #define 和typedef 内存对齐概述
文章目录 sizeof 和 strlen数组和链表总结 #include <>和 #include ""#define 和typedef内存对齐概述对齐规则示例:结构体的内存对齐分析: 内存对齐的常见规则:填充字节的计算对齐影响的实际例子 sizeof 和 strlen 特性size…...
使用 Kotlin 将 Vertx 和 Springboot 整合
本篇文章目的是将 Springboot 和 Vertx 进行简单整合。整合目的仅仅是为了整活,因为两个不同的东西整合在一起提升的性能并没有只使用 Vertx 性能高,因此追求高性能的话这是在我来说不推荐。而且他们不仅没有提高很多性能甚至增加了学习成本 一、整合流…...

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

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

虚幻UE5手机安卓Android Studio开发设置2025
一、下载Android Studio历史版本 步骤1:虚幻4.27、5.0、5.1、5.2官方要求Andrd Studio 4.0版本; 5.3、5.4、5.5官方要求的版本为Android Studio Flamingo | 2022.2.1 Patch 2 May 24, 2023 虚幻官网查看对应Andrd Studiob下载版本: https:/…...
线性代数复习笔记
1. 课程学习 1.1 3Blue1Brown 线性代数 2. 基本术语 eigenvector(特征向量):线性变换中方向保持不变的向量 可以视作3D旋转矩阵形成的旋转的轴...
你需要更深层次的解放
先谈一谈理性认知中的属性替换原则。简单来说,属性替换就是用简单的问题取代难题。 当人们需要评估属性A时,却发现评估属性B更容易一些(A与B之间存在一定的关系),于是就改为评估属性B。这叫做属性替换。 作为一种认知…...

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

Qt事件处理:理解处理器、过滤器与事件系统
1. 事件 事件 是一个描述应用程序中、发生的某些事情的对象。 在 Qt 中,所有事件都继承自 QEvent ,并且每个事件都有特定的标识符,如:Qt::MouseButtonPress 代表鼠标按下事件。 每个事件对象包含该事件的所有相关信息ÿ…...
DeepSeek相关技术整理
相关介绍 2024年12月26日,DeepSeek V3模型发布(用更低的训练成本,训练出更好的效果)671B参数,激活37B。2025年1月20日,DeepSeek-R1模型发布(仅需少量标注数据(高质量长cotÿ…...

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

蓝桥杯之c++入门(二)【输入输出(上)】
目录 前言1.getchar和 putchar1.1 getchar()1.2 putchar() 2.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:…...

消息队列应用示例MessageQueues-STM32CubeMX-FreeRTOS《嵌入式系统设计》P343-P347
消息队列 使用信号量、事件标志组和线标志进行任务同步时,只能提供同步的时刻信息,无法在任务之间进行数据传输。要实现任务间的数据传输,一般使用两种方式: 1. 全局变量 在 RTOS 中使用全局变量时,必须保证每个任务…...

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

谭浩强C语言程序设计(4) 8章(下)
1、输入三个字符串按照字母顺序从小到大输出 #include <cstdio> // 包含cstdio头文件,用于输入输出函数 #include <cstring> // 包含cstring头文件,用于字符串处理函数#define N 20 // 定义字符串的最大长度为20// 函数:…...

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

CMake基础:构建流程详解
目录 1.CMake构建过程的基本流程 2.CMake构建的具体步骤 2.1.创建构建目录 2.2.使用 CMake 生成构建文件 2.3.编译和构建 2.4.清理构建文件 2.5.重新配置和构建 3.跨平台构建示例 4.工具链与交叉编译 5.CMake构建后的项目结构解析 5.1.CMake构建后的目录结构 5.2.构…...

蓝牙 BLE 扫描面试题大全(2):进阶面试题与实战演练
前文覆盖了 BLE 扫描的基础概念与经典问题蓝牙 BLE 扫描面试题大全(1):从基础到实战的深度解析-CSDN博客,但实际面试中,企业更关注候选人对复杂场景的应对能力(如多设备并发扫描、低功耗与高发现率的平衡)和前沿技术的…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...

C++ 求圆面积的程序(Program to find area of a circle)
给定半径r,求圆的面积。圆的面积应精确到小数点后5位。 例子: 输入:r 5 输出:78.53982 解释:由于面积 PI * r * r 3.14159265358979323846 * 5 * 5 78.53982,因为我们只保留小数点后 5 位数字。 输…...
AI编程--插件对比分析:CodeRider、GitHub Copilot及其他
AI编程插件对比分析:CodeRider、GitHub Copilot及其他 随着人工智能技术的快速发展,AI编程插件已成为提升开发者生产力的重要工具。CodeRider和GitHub Copilot作为市场上的领先者,分别以其独特的特性和生态系统吸引了大量开发者。本文将从功…...
爬虫基础学习day2
# 爬虫设计领域 工商:企查查、天眼查短视频:抖音、快手、西瓜 ---> 飞瓜电商:京东、淘宝、聚美优品、亚马逊 ---> 分析店铺经营决策标题、排名航空:抓取所有航空公司价格 ---> 去哪儿自媒体:采集自媒体数据进…...

tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...

如何理解 IP 数据报中的 TTL?
目录 前言理解 前言 面试灵魂一问:说说对 IP 数据报中 TTL 的理解?我们都知道,IP 数据报由首部和数据两部分组成,首部又分为两部分:固定部分和可变部分,共占 20 字节,而即将讨论的 TTL 就位于首…...
提升移动端网页调试效率:WebDebugX 与常见工具组合实践
在日常移动端开发中,网页调试始终是一个高频但又极具挑战的环节。尤其在面对 iOS 与 Android 的混合技术栈、各种设备差异化行为时,开发者迫切需要一套高效、可靠且跨平台的调试方案。过去,我们或多或少使用过 Chrome DevTools、Remote Debug…...

从物理机到云原生:全面解析计算虚拟化技术的演进与应用
前言:我的虚拟化技术探索之旅 我最早接触"虚拟机"的概念是从Java开始的——JVM(Java Virtual Machine)让"一次编写,到处运行"成为可能。这个软件层面的虚拟化让我着迷,但直到后来接触VMware和Doc…...