C++----模拟实现string

news2025/4/26 11:16:29

模拟实现string,首先我们要知道成员变量有哪些:

    class _string
    {
    private:
		char* _str;
		size_t capacity;//空间有多大
		size_t size;//有效字符多少

		const static size_t npos;
		
	};


const size_t _string::npos=-1;//static在外面定义不需要带static,npos表示最大位置

接着写构造函数,在string中,初始化方式有无参的,有用字符串初始化的,这就要求我们写一个带缺省参数的默认构造函数:

string(const char* str="")
    :capacity(strlen(str)),
    size(capacity)
{
    _str=new char[capacity+1];
    strcpy(_str,str);
}
//为什么用"",因为它代表了\0,用它初始化再合适不过了
//为什么不用'\0'呢?因为这是一个char*,用'\0'就会用他的ASCII码值初始化
//为什么不用nullptr呢?因为在后面可能会用到_str的解引用,解引用空指针要出问题的

接下来写拷贝构造

string(const string& s)
{
    _str=new char[s.capacity+1];
    capacity=s.capacity;
    size=s.size;
    strcpy(_str,s._str);
}

赋值符号重载

//与单纯的拷贝构造不一样,复制重载原string对象一般都会有原始空间,要释放原始空间
const string& operator=(const string& s)
{
    //最重要的一点!一定要检查自赋值,不检查的话会导致空间释放使用未分配的空间
    if(this==&s)
        return *this;


    //并且释放原始空间和开辟新空间是有顺序的,开辟新空间一定要放在前面
    //避免开辟新空间失败导致原来空间也没有了!
    char *new_ptr=new char[s.size+1];
    strcpy(new_ptr,s._str);
    delete[]_str;
    _str=new_str;
	capacity = s.capacity;
	size = s.size;
	return *this; 
}

如果我们要打印string对象的字符串呢?在没有重载流提取符号的情况下:

const char* c_str() const
{
    return _str;
}

开始定义增删查改部分;增:有push_back、append、+=、insert,直接先定义insert,其他的都可以复用insert函数,insert有插入字符版本和字符串版本:

void reserve(size_t n)
{
    if(capacity<n)
    {
        char* new_ptr=new char[n+1];
        strpy(new_ptr,_ptr);
        delete[]_str;
        _str=new_ptr;
        capacity=n;
    }
}


void resize(size_t n,char ch='\0')//给一个缺省参数
{
    //小于size实质上就是删除多余的字符
    if(n<size)
        _str[n]='\0'
    else
    {
        if(n>capacity)
            reserve(n);
        for(int i=size;i<n;i++)
        {
            _str[i]=ch;
        }
        _str[n]='\0';
    }
    size=n;
}


//插入字符版本
string& insert(size_t pos, char ch)
{
    assert(pos<=size);
    int len=size+1;
    if(len>capacity)
        reserve(len);
    unsigned int end = size+1;

    //unsigned int end = size;
	//while (pos <= end)  //头插有bug,遇到unsigned<=某数要小心,容易最大化
	//{
	//	_str[end + 1] = _str[end];
	//	end--;
	//}

    //\0直接被处理,无需再管\0
	while (pos < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的
	{
	    str[end] = _str[end-1];
		end--;
	}
	_str[pos] = ch;
	size += 1;

	return *this;
}


//插入字符串版本  本质上从挪一个位置到要挪n个位置的区别
string& insert(size_t pos, const char* str)
{
    assert(pos<=size);
    int len=size+len(str);
    if(len>capacity)
        reserve(len);
    unsigned int end = size+len(str);


    //\0直接被处理,无需再管\0
	while (pos+len-1 < end) //有bug,遇到unsigned<=某数要小心,容易最大化,unsigned容易减到-1成最大的
	{
	    str[end] = _str[end-len(str)];
		end--;
	}
	_str[pos] = ch;
	size += 1;

	return *this;
}

append、+=、push_back直接复用:

		string& operator+=(const char* str)
		{
			insert(size,str);
			return *this;
		}

		string& operator+=(char ch)
		{
			insert(size,ch);
			return *this;
		}


		void push_back(const char ch)
		{
			insert(size,ch);
		}

		void append(const char* str)
		{
			insert(size,ch);
		}

查改:

const char& operator[](int pos)const //一般情况不修改对象内容的,都用const修饰,既考虑了const对象调用,又考虑了非const调用,如果有特殊需要可以都实现,调用时会自动识别
{
    assert(pos<size);
    return *(_str+pos);
}

char& operator[](int pos) //用引用返回可以直接修改
{
    assert(pos<size);
    return *(_str+pos);
}

size_t find(char ch, int pos) const
{
    assert(pos<size);
    while(_str[pos]!=ch)
    {
        if(pos>=size)
            break;
        pos++;
    }
    if(pos==size)
        return npos;
    else
        return pos;
}

char* find(const char* str, int pos)
{
    assert(pos<size);
    char* poss=strstr(_str+pos,str)
    return poss;
}

const char* find(const char* str, int pos) const
{
    assert(pos<size);
    char* poss=strstr(_str+pos,str)
    return poss;
}


迭代器的实现

class _string
{
    typedef char* iterator;
    typedef const char* const_iterator;
    //string这种物理内存连续的可以这么定义指针
    //一定要定义const迭代器 要保证权限不会放大,以及后续一致性问题,不能const字符串的指针能修改                字符串,这就扯淡了


    iterator begin()
    {
        return _str;
    }

    const_iterator begin() const
    {
        return _str;
    }

    iterator end()
    {
        return _str+size;
    }

    const_iterator end() const
    {
        return _str+size;
    }
}

//范围for就是用的迭代器,要想支持范围for遍历就必须定义迭代器begin(),end(),一个字符都不能差。

删:

void erase(size_t pos=npos, int n)
{
    assert(pos<size)
    if(pos+n>size)
        _str[pos]='\0';
        size-=n;
    else
    {
        int start=pos;
        int end=n+pos;
        while(start<=end)
        {
            _str[start]=_str[start+n];
            start++;
        }
        size-=n;
    }

}

重载流提取流插入运算符,在类外重载:

ostream& operator<<(ostream& out, const string& s)
{
    for(auto e: s)
        out<<e;
    return out;
}



//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{
    //引入内存池
    char tmp[128]={'\0'};
    ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收
    int i = 0;
    while(ch !=' ' and ch!='\n')
    {
        if(i==128)
            s+=tmp;
            i=0;
            memset(tmp,'\0',128);
        tmp[i++]=ch;
        ch=in.get();
    }
    s+=tmp;
    return in; 
}

这么写,其实有问题,输入时之前的旧内存没有释放掉:

//流输入要考虑的问题就多了,要考虑效率问题,以及普通的in不处理换行符的问题。
istream& operator>>(stream& in, string& s)
{
    s= string();//清空内存
    

    //引入内存池
    char tmp[128]={'\0'};
    ch=in.get();//可以接收换行符,空格符,如果只in>>,不会接收
    int i = 0;
    while(ch !=' ' and ch!='\n')
    {
        if(i==128)
            s+=tmp;
            i=0;
            memset(tmp,'\0',128);
        tmp[i++]=ch;
        ch=in.get();
    }
    s+=tmp;
    return in; 
}

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

基于K8s日志审计实现攻击行为检测

K8s日志审计以一种事件溯源的方式完整记录了所有API Server的交互请求。当K8s集群遭受入侵时&#xff0c;安全管理员可以通过审计日志进行攻击溯源&#xff0c;通过分析攻击痕迹&#xff0c;找到攻击者的入侵行为并还原攻击者的攻击路径&#xff0c;修复安全问题。 在本篇文章中…

【Linux网络编程】应用层协议HTTP(实现一个简单的http服务)

目录 前言 一&#xff0c;HTTP协议 1&#xff0c;认识URL 2&#xff0c;urlencode和urldecode 3&#xff0c;HTTP协议请求与响应格式 二&#xff0c;myhttp服务器端代码的编写 HTTP请求报文示例 HTTP应答报文示例 代码编写 网络通信模块 处理请求和发送应答模块 结…

短视频+直播商城系统源码全解析:音视频流、商品组件逻辑剖析

时下&#xff0c;无论是依托私域流量运营的品牌方&#xff0c;还是追求用户粘性与转化率的内容创作者&#xff0c;搭建一套完整的短视频直播商城系统源码&#xff0c;已成为提升用户体验、增加商业变现能力的关键。本文将围绕三大核心模块——音视频流技术架构、商品组件设计、…

STM32定时器---基本定时器

目录 一、定时器的概述 二、时基单元 三、基本定时器的的时序 &#xff08;1&#xff09;预分频器时序 &#xff08;2&#xff09;计数器时序 四、基本定时器的使用 一、定时器的概述 在没有定时器的时候&#xff0c;我们想要延时往往都是写一个Delay函数&#xff0c;里面…

大模型微调 - transformer架构

什么是Transformer Transformer 架构是由 Vaswani 等人在 2017 年提出的一种深度学习模型架构&#xff0c;首次发表于论文《Attention is All You Need》中 Transformer 的结构 Transformer 编码器&#xff08;Encoder&#xff09; 解码器&#xff08;Decoder&#xff09; …

Sentinel数据S2_SR_HARMONIZED连续云掩膜+中位数合成

在GEE中实现时&#xff0c;发现简单的QA60是无法去云的&#xff0c;最近S2地表反射率数据集又进行了更新&#xff0c;原有的属性集也进行了变化&#xff0c;现在的SR数据集名称是“S2_SR_HARMONIZED”。那么&#xff1a; 要想得到研究区无云的图像&#xff0c;可以参考执行以下…

HTMLCSS模板实现水滴动画效果

.container 类&#xff1a;定义了页面的容器样式。 display: flex&#xff1a;使容器成为弹性容器&#xff0c;方便对其子元素进行布局。justify-content: center 和 align-items: center&#xff1a;分别使子元素在水平和垂直方向上居中对齐。min-height: 100vh&#xff1a;设…

【数据可视化艺术·应用篇】三维管线分析如何重构城市“生命线“管理?

在智慧城市、能源管理、工业4.0等领域的快速发展中&#xff0c;地下管线、工业管道、电力通信网络等“城市血管”的复杂性呈指数级增长。传统二维管理模式已难以应对跨层级、多维度、动态变化的管线管理需求。三维管线分析技术应运而生&#xff0c;成为破解这一难题的核心工具。…

【MinerU】:一款将PDF转化为机器可读格式的工具——RAG加强(Docker版本)

目录 创建容器 安装miniconda 安装mineru CPU运行 GPU加速 多卡问题 创建容器 构建Dockerfile文件 开启ssh服务&#xff0c;设置密码为1234等操作 # 使用官方 Ubuntu 24.04 镜像 FROM ubuntu:24.04# 安装基础工具和SSH服务 RUN apt-get update && \apt-get ins…

Appium自动化开发环境搭建

自动化 文章目录 自动化前言 前言 Appium是一款开源工具&#xff0c;用于自动化iOS、Android和Windows桌面平台上的本地、移动web和混合应用程序。原生应用是指那些使用iOS、Android或Windows sdk编写的应用。移动网页应用是通过移动浏览器访问的网页应用(appum支持iOS和Chrom…

C++学习-入门到精通-【1】C++编程入门,输入/输出和运算符

C学习-入门到精通-【1】C编程入门&#xff0c;输入/输出和运算符 C编程入门&#xff0c;输入/输出和运算符 C学习-入门到精通-【1】C编程入门&#xff0c;输入/输出和运算符第一个C程序&#xff1a;输出一行文本算术运算 第一个C程序&#xff1a;输出一行文本 // 文本打印程序…

面向高性能运动控制的MCU:架构创新、算法优化与应用分析

摘要&#xff1a;现代工业自动化、汽车电子以及商业航天等领域对运动控制MCU的性能要求不断提升。本文以国科安芯的MCU芯片AS32A601为例&#xff0c;从架构创新、算法优化到实际应用案例&#xff0c;全方位展示其在高性能运动控制领域的优势与潜力。该MCU以32位RISC-V指令集为基…

某地农产品交易中心钢网架自动化监测项目

1. 项目简介 本项目规划建设现代物流产业园&#xff0c;新建6万平方米仓库&#xff0c;具体为新建3栋钢构仓库2万平方米&#xff0c;2栋砖混结构仓库1万平方米&#xff0c;3栋交易中心2万平方米&#xff0c;改造现有3栋3层砖混结构仓库1万平方米&#xff0c;配备智能化仓库物流…

【无人机】无人机位置估计出现偏差的原因分析

目录 #0、原因分析 #1、过度振动的测定 #2、确定过度陀螺仪偏差 #3、偏航精度差的测定 #4、确定 GPS 精度差 #5、确定 GPS 数据丢失 #6、气压计地面效应补偿 #0、原因分析 位置背离的最常见原因是&#xff1a; 参考&#xff1a;Using the ECL EKF | PX4 Guide (v1.15)…

element-plus(vue3)表单el-select下拉框的远程分页下拉触底关键字搜索实现

一、基础内核-自定义指令 1.背景 2.定义 3.使用 4.注意 当编辑时需要回显&#xff0c;此时由于分页导致可能匹配不到对应label文本显示&#xff0c;此时可以这样解决 二、升级使用-二次封装组件 三、核心代码 1.自定义指令 定义 ----------------selectLoadMoreDirective.…

轻松完成视频创作,在线视频编辑器,无需下载软件,功能多样实用!

小白工具的在线视频编辑https://www.xiaobaitool.net/videos/edit/ 功能丰富、操作简便&#xff0c;在线裁剪或编辑视频工具&#xff0c;轻松完成视频创作能满足多种视频编辑需求。 格式支持广泛&#xff1a;可编辑超百种视频格式&#xff0c;基本涵盖常见和小众视频格式&#…

豆瓣图书数据采集与可视化分析(三)- 豆瓣图书数据统计分析

文章目录 前言一、数据读取与保存1. 读取清洗后数据2. 保存数据到CSV文件3. 保存数据到MySQL数据库 二、不同分类统计分析1. 不同分类的图书数量统计分析2. 不同分类的平均评分统计分析3. 不同分类的平均评价人数统计分析4. 不同分类的平均价格统计分析5. 分类综合分析 三、不同…

c++进阶——类与继承

文章目录 继承继承的基本概念继承的基本定义继承方式继承的一些注意事项 继承类模板 基类和派生类之间的转换继承中的作用域派生类的默认成员函数默认构造函数拷贝构造赋值重载析构函数默认成员函数总结 不能被继承的类继承和友元继承与静态成员多继承及其菱形继承问题继承模型…

复杂地形越野机器人导航新突破!VERTIFORMER:数据高效多任务Transformer助力越野机器人移动导航

作者&#xff1a; Mohammad Nazeri 1 ^{1} 1, Anuj Pokhrel 1 ^{1} 1, Alexandyr Card 1 ^{1} 1, Aniket Datar 1 ^{1} 1, Garrett Warnell 2 , 3 ^{2,3} 2,3, Xuesu Xiao 1 ^{1} 1单位&#xff1a; 1 ^{1} 1乔治梅森大学计算机科学系&#xff0c; 2 ^{2} 2美国陆军研究实验室&…

Jsp技术入门指南【十】IDEA 开发环境下实现 MySQL 数据在 JSP 页面的可视化展示,实现前后端交互

Jsp技术入门指南【十】IDEA 开发环境下实现 MySQL 数据在 JSP 页面的可视化展示&#xff0c;实现前后端交互 前言一、JDBC 核心接口和类&#xff1a;数据库连接的“工具箱”1. 常用的 2 个“关键类”2. 必须掌握的 5 个“核心接口” 二、创建 JDBC 程序的步骤1. 第一步&#xf…