C++:string类模拟实现

news2025/2/12 1:30:09

C++:string类模拟实现

    • 成员变量
    • 构造和析构
    • 容量相关
      • 1.获取容器大小(_size)和容量(_capacity)
      • 2.扩容(reserve)
      • 3.更改容器大小
    • 修改相关
      • 1.尾插
      • 2.指定位置插入
      • 3.指定位置删除
      • 4.清空
      • 5.交换两个对象
    • 比较相关
    • 访问相关
    • 迭代器相关
    • 查找相关
    • 其它成员函数
      • 1.截取子串
      • 2.取得C格式字符串
      • 3.赋值
    • 非成员函数
    • 完整代码

成员变量

public:
        //类外可能要访问,设计成公有
        static const size_t npos;
 private:
        //指向实际存储字符串的空间
        char* _str;
        //记录容量
        size_t _capacity;
        //记录有效字符,'\0'不算
        size_t _size;
        
//记得类外定义静态变量
const size_t string::npos = -1;

在这里插入图片描述


构造和析构

string(const char* str = "")
    :_capacity(strlen(str))
    ,_size(_capacity)
{
    _str = new char[_capacity + 1];
    strcpy(_str, str);
}

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

~string()
{
    delete[] _str;
    _str = nullptr;
    _size = _capacity = 0;
}



容量相关

1.获取容器大小(_size)和容量(_capacity)

//加const修饰this指针,因为const修饰对象也需要调用这几个接口
size_t size()const
{
    return _size;
}

size_t capacity()const
{
    return _capacity;
}

bool empty()const
{  
    //为空返回true,为假返回false
    return (_size == 0);
}

2.扩容(reserve)

void reserve(size_t n)
{
    //只有n大于容量才进行扩容
    if (n > _capacity)
    {
        //重新开一片空间,拷贝完成后释放原空间
        //修改指针指向,更改容量
        char* tmp = new char[n + 1];
        strcpy(tmp, _str);
        delete[] _str;
        _str = tmp;
        _capacity = n;
    }
}

3.更改容器大小

//设计成半缺省
void resize(size_t n, char c = '\0')
{
    //n > _size,扩容后用c填满容器
    if (n > _size)
    {
        reserve(n);
        for (size_t i = _size; i < _capacity; i++)
        {
            _str[i] = c;
        }
        _str[_capacity] = '\0';
        _size = _capacity;
    }
    else
    {
        //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可
        _str[n] = '\0';
        _size = n;
    }
}

在这里插入图片描述


修改相关

1.尾插

//尾部插入一个字符
void push_back(char c)
{
    //先判断是否扩容
    if (_size == _capacity)
        reserve(_capacity == 0 ? 4 : _capacity * 2);
    //把原'\0'位置修改为新字符,记得补'\0'
    _str[_size] = c;
    _str[_size + 1] = '\0';
    _size++;
}

//+=复用即可
string& operator+=(char c)
{
    push_back(c);
    return (*this);
}

//尾部插入字符串
void append(const char* str)
{
   size_t len = strlen(str);
   //先判断是否扩容
    if (len + _size > _capacity)
        reserve(len + _size);
    //从原'\0'位置开始拷贝
    strcpy(_str + _size, str);
    //更新_size
    _size += len;
}

string& operator+=(const char* str)
{
    //+=复用即可
    append(str);
    return (*this);
}

在这里插入图片描述


2.指定位置插入

// 在pos位置上插入字符c
string& insert(size_t pos, char c)
 {
     //断言,不然可能越界
     assert(pos <= _size);
     if (_size == _capacity)
         reserve(2 * _capacity);
     //pos位置后字符后移一位
     for (int i = _size; i >= (int)pos; i--)        
         _str[i + 1] = _str[i];

     _str[pos] = c;
     _size++;
     return (*this);
 }

 //在pos位置上插入字符串str
 string& insert(size_t pos, const char* str)
 {
     //断言,不然可能越界
     assert(pos <= _size);
     size_t len = strlen(str);
     if ((_size + len) > _capacity)
         reserve(_size + len);
     for (int i = _size; i >= (int)pos; i--)
     {
         _str[i + len] = _str[i];
     }
     for (int i = 0; i < len; i++)
     {
         _str[pos++] = str[i];
     }
     _size += len;
     return (*this);
 }

在这里插入图片描述


3.指定位置删除

// 删除pos位置上的元素
string& erase(size_t pos, size_t len = npos)
{
    assert(pos <= _size);
    //要删除的字符数大于后面字符,就把pos位置和后面全部删除完
    if (len == npos || pos + len >= _size)
    {
        _size = pos;
        _str[_size] = '\0';
    }
    else
    {
        for (size_t i = pos; i <= pos + _size - len; i++)
        {
            _str[i] = _str[i + len];
        }
        _size -= len;
    }
    return (*this);
}

在这里插入图片描述


4.清空

void clear()
{
     _str[0] = '\0';
     _size = 0;
 }

5.交换两个对象

void swap(string& s)
{
    std::swap(_str, s._str);
    std::swap(_capacity, s._capacity);
    std::swap(_size, s._size);
}



比较相关

//写好< 和 == ,其它复用即可
bool operator<(const string& s)const
{       
    return strcmp(_str, s._str) < 0;
}

bool operator<=(const string& s)const
{
    return (*this) < s || (*this) == s;
}

bool operator>(const string& s)const
{
    return !((*this) <= s);
}

bool operator>=(const string& s)const
{
    return !((*this) < s);
}

bool operator==(const string& s)const
{
    return strcmp(_str, s._str) == 0;
}

bool operator!=(const string& s)const
{
    return !((*this == s));
}



访问相关

char& operator[](size_t index)
{
     assert(index <= _size);
     return _str[index];
}

//函数重载,这个版本专门给const用
 const char& operator[](size_t index)const
{
    assert(index <= _size);
    return _str[index];
}



迭代器相关

//string的迭代器底层是指针
typedef char* iterator;
typedef const 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);
}



查找相关

// 查找字符,返回c在string中第一次出现的位置
size_t find(char c, size_t pos = 0) const
{
    assert(pos < _size);
    for (size_t i = pos; i < _size; i++)
    {
        if (_str[i] == c)
            return i;
    }
    return npos;
}

//查找子串,返回子串s在string中第一次出现的位置
size_t find(const char* s, size_t pos = 0) const
{
    //断言,不然可能越界
    assert(pos < _size);
    //直接调用库函数找到子串位置
    const char* p = strstr(_str + pos, s);
    if (p)
        return p - _str;//指针相减得到指针间元素数量,刚好为下标
    else
        return npos;
}



其它成员函数

1.截取子串

string substr(size_t pos, size_t len = npos)
{
    assert(pos < _size);
    string s;
    size_t end = pos + len;
    //如果len大于后面所剩的字符,就把后面全部截取
    if (len == npos || end >= _size)
    {
        len = _size - pos;
        end = _size;
    }

    s.reserve(len);
    for (size_t i = pos; i < end; i++)
    {
        s += _str[i];
    }
    return s;
}

2.取得C格式字符串

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

3.赋值

//这里使用传值传参,编译器自行完成拷贝,交换两者即可
string& operator=(string s)
{
     swap(s);
     return (*this);
 }



非成员函数

ostream& operator<<(ostream& _cout, const string& s)
{
    _cout << s.c_str() << endl;
    return _cout;
}

istream& operator>>(istream& _cin, string& s)
{
    s.clear();
    //避免多次扩容,以128为一组进行写入
    char tmp[128] = "";
    int i = 0;
    char ch = '0';
    ch = _cin.get();
    while (ch != ' ' && ch != '\n')
    {
        tmp[i++] = ch;
        if (i == 127)
        {
            tmp[i] = '\0';
            s += tmp;
            i = 0;
        }
        ch = _cin.get();
    }

    if (i != 0)
    {
        tmp[i] = '\0';
        s += tmp;
    }
    return _cin;
}



完整代码

#pragma once
#define _CRT_SECURE_NO_WARNINGS 1
#include<iostream>
#include<string.h>
#include<assert.h>
using namespace std;

namespace MyStd
{

    class string
    {
    public:

        typedef char* iterator;
        typedef const char* const_iterator;

        string(const char* str = "")
            :_capacity(strlen(str))
            ,_size(_capacity)
        {
            _str = new char[_capacity + 1];
            strcpy(_str, str);
        }

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

        string& operator=(string s)
        {
            swap(s);
            return (*this);
        }

        ~string()
        {
            delete[] _str;
            _str = nullptr;
            _size = _capacity = 0;
        }

//
       // iterator
        iterator begin()
        {
            return _str;
        }

        iterator end()
        {
            return (_str + _size);
        }

        const_iterator begin()const
        {
            return _str;
        }

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

        // modify
        //尾部插入一个字符
        void push_back(char c)
        {
            //先判断是否扩容
            if (_size == _capacity)
                reserve(_capacity == 0 ? 4 : _capacity * 2);
            //把原'\0'位置修改为新字符,记得补'\0'
            _str[_size] = c;
            _str[_size + 1] = '\0';
            _size++;
        }

        //+=复用即可
        string& operator+=(char c)
        {
            push_back(c);
            return (*this);
        }

        //尾部插入字符串
        void append(const char* str)
        {
           size_t len = strlen(str);
           //先判断是否扩容
            if (len + _size > _capacity)
                reserve(len + _size);
            //从原'\0'位置开始拷贝
            strcpy(_str + _size, str);
            //更新_size
            _size += len;
        }

        string& operator+=(const char* str)
        {
            //+=复用即可
            append(str);
            return (*this);
        }

        void clear()
        {
            _str[0] = '\0';
            _size = 0;
        }

        void swap(string& s)
        {
            std::swap(_str, s._str);
            std::swap(_capacity, s._capacity);
            std::swap(_size, s._size);
        }

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

        /
        // capacity
        //加const修饰this指针,因为const修饰对象也需要调用这几个接口
        size_t size()const
        {
            return _size;
        }

        size_t capacity()const
        {
            return _capacity;
        }

        bool empty()const
        {
            //为空返回true,为假返回false
            return (_size == 0);
        }

        //设计成半缺省
        void resize(size_t n, char c = '\0')
        {
            //n > _size,扩容后用c填满容器
            if (n > _size)
            {
                reserve(n);
                for (size_t i = _size; i < _capacity; i++)
                {
                    _str[i] = c;
                }
                _str[_capacity] = '\0';
                _size = _capacity;
            }
            else
            {
                //n <= _size的情况,直接把下标n的位置改为'\0',修改_size即可
                _str[n] = '\0';
                _size = n;
            }
        }

        void reserve(size_t n)
        {
            //只有n大于容量才进行扩容
            if (n > _capacity)
            {
                //重新开一片空间,拷贝完成后释放原空间
                //修改指针指向,更改容量
                char* tmp = new char[n + 1];
                strcpy(tmp, _str);
                delete[] _str;
                _str = tmp;
                _capacity = n;
            }
        }

        /
        // access
        char& operator[](size_t index)
        {
            assert(index <= _size);
            return _str[index];
        }

        const char& operator[](size_t index)const
        {
            assert(index <= _size);
            return _str[index];
        }


        /
        //relational operators
        //写好< 和 == ,其它复用即可
        bool operator<(const string& s)const
        {       
            return strcmp(_str, s._str) < 0;
        }

        bool operator<=(const string& s)const
        {
            return (*this) < s || (*this) == s;
        }

        bool operator>(const string& s)const
        {
            return !((*this) <= s);
        }

        bool operator>=(const string& s)const
        {
            return !((*this) < s);
        }

        bool operator==(const string& s)const
        {
            return strcmp(_str, s._str) == 0;
        }

        bool operator!=(const string& s)const
        {
            return !((*this == s));
        }


        // 查找字符,返回c在string中第一次出现的位置
        size_t find(char c, size_t pos = 0) const
        {
            assert(pos < _size);
            for (size_t i = pos; i < _size; i++)
            {
                if (_str[i] == c)
                    return i;
            }
            return npos;
        }

        //查找子串,返回子串s在string中第一次出现的位置
        size_t find(const char* s, size_t pos = 0) const
        {
            //断言,不然可能越界
            assert(pos < _size);
            //直接调用库函数找到子串位置
            const char* p = strstr(_str + pos, s);
            if (p)
                return p - _str;//指针相减得到指针间元素数量,刚好为下标
            else
                return npos;
        }

        string substr(size_t pos, size_t len = npos)
        {
            assert(pos < _size);
            string s;
            size_t end = pos + len;
            //如果len大于后面所剩的字符,就把后面全部截取
            if (len == npos || end >= _size)
            {
                len = _size - pos;
                end = _size;
            }

            s.reserve(len);
            for (size_t i = pos; i < end; i++)
            {
                s += _str[i];
            }
            return s;
        }

        // 在pos位置上插入字符c
        string& insert(size_t pos, char c)
        {
            //断言,不然可能越界
            assert(pos <= _size);
            if (_size == _capacity)
                reserve(2 * _capacity);
            //pos位置后字符后移一位
            for (int i = _size; i >= (int)pos; i--)        
                _str[i + 1] = _str[i];

            _str[pos] = c;
            _size++;
            return (*this);
        }

        //在pos位置上插入字符串str
        string& insert(size_t pos, const char* str)
        {
            //断言,不然可能越界
            assert(pos <= _size);
            size_t len = strlen(str);
            if ((_size + len) > _capacity)
                reserve(_size + len);
            for (int i = _size; i >= (int)pos; i--)
            {
                _str[i + len] = _str[i];
            }
            for (int i = 0; i < len; i++)
            {
                _str[pos++] = str[i];
            }
            _size += len;
            return (*this);
        }

        // 删除pos位置上的元素
        string& erase(size_t pos, size_t len = npos)
        {
            assert(pos <= _size);
            //要删除的字符数大于后面字符,就把pos位置和后面全部删除完
            if (len == npos || pos + len >= _size)
            {
                _size = pos;
                _str[_size] = '\0';
            }
            else
            {
                for (size_t i = pos; i <= pos + _size - len; i++)
                {
                    _str[i] = _str[i + len];
                }
                _size -= len;
            }
            return (*this);
        }
    public:
        //类外可能要访问,设计成公用
        static const size_t npos;
    private:
        //指向实际存储字符串的空间
        char* _str;
        //记录容量
        size_t _capacity;
        //记录有效字符,'\0'不算
        size_t _size;

    };
    ostream& operator<<(ostream& _cout, const string& s)
    {
        _cout << s.c_str() << endl;
        return _cout;
    }

    istream& operator>>(istream& _cin, string& s)
    {
        s.clear();
        //避免多次扩容
        char tmp[128] = "";
        int i = 0;
        char ch = '0';
        ch = _cin.get();
        while (ch != ' ' && ch != '\n')
        {
            tmp[i++] = ch;
            if (i == 127)
            {
                tmp[i] = '\0';
                s += tmp;
                i = 0;
            }
            ch = _cin.get();
        }

        if (i != 0)
        {
            tmp[i] = '\0';
            s += tmp;
        }
        return _cin;
    }
    //静态成员在外部定义
    const size_t string::npos = -1; 
};

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

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

相关文章

交融动画学习

学习抖音&#xff1a; 渡一前端教科频道 利用 filter 的属性实现交融效果 变成 让后利用这个效果实现一个功能 实现代码&#xff1a; <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><style>* {margin: 0;…

c# .net mvc的IHttpHandler奇妙之旅--图片文件请求安全过滤,图片防盗链

在阅读该文章前,请先阅读该文章 c# .net mvc的IHttpHandler奇妙之旅。.net的生命周期和管道你听说过吗?你可以利用他处理业务如:跳转业务页面,文件请求的安全过滤,等等,还有许多神秘业务等着你去发现_橙-极纪元的博客-CSDN博客 该篇文章延续上面文章的第二小节《二、文件…

StarRocks企业级数据库

第1章 StarRocks简介 1.1 StarRocks介绍 StarRocks是新一代极速全场景MPP数据库 StraRocks充分吸收关系型OLAP数据库和分布式存储系统在大数据时代的优秀研究成果&#xff0c;在业界实践的基础上&#xff0c;进一步改进优化、升级架构&#xff0c;并增添了众多全新功能&…

Cadence OrCAD Capture CIS批量替换GND符号的方法

🏡《总目录》   🏡《宝典目录》 目录 1,概述2,方法3,总结1,概述 如下图所示,有时由于绘图是从多个地方复制粘贴而来,一个图纸中会存在多种GND符号。此时比较容易引起GND网络名不同意的问题,为了避免该问题可对其批量替换。 2,方法 第1步:选择需要替换的GND符号…

【Nginx】Nginx的优化和防盗链

nginx版本迭代比较快 *工作中&#xff0c;在发版期&#xff0c;通常先备份文件并备注时间&#xff0c;方便后期故障后回档 例&#xff1a; cp nginx.conf nginx.conf.bak.2023.0805 隐藏版本号的两种方法*** 1.修改配置文件 vim /usr/local/nginx/conf/nginx.conf 在http模…

分享花店行业小程序平台搭建教程

随着移动互联网的快速发展&#xff0c;花店也开始意识到拥有一个专属的小程序能够提升用户体验、增加销售额。那么&#xff0c;如何快速搭建一个漂亮、实用的花店小程序呢&#xff1f;下面就为大家介绍一下具体的步骤。 第一步&#xff0c;使用第三方制作平台。如乔拓云网是一个…

Linux下C语言调用libcurl库获取天气预报信息

一、概述 当前文章介绍如何在Linux&#xff08;Ubuntu&#xff09;下使用C语言调用libcurl库获取天气预报的方法。通过HTTP GET请求访问百度天气API&#xff0c;并解析返回的JSON数据&#xff0c;可以获取指定城市未来7天的天气预报信息。 二、设计思路 【1】使用libcurl库进…

24届近5年南京大学自动化考研院校分析

今天给大家带来的是南京大学控制考研分析 满满干货&#xff5e;还不快快点赞收藏 一、南京大学 学校简介 南京大学是一所历史悠久、声誉卓著的高等学府。其前身是创建于1902年的三江师范学堂&#xff0c;此后历经两江师范学堂、南京高等师范学校、国立东南大学、国立第四中…

数字孪生和元宇宙之间的差别与联系是什么?

元宇宙和数字孪生是两个引人瞩目的概念&#xff0c;它们在虚拟与现实世界的交汇点上呈现出独特的视角和应用。虽然二者都涉及数字化和模拟技术&#xff0c;但在其差异与联系上&#xff0c;我们可以发现深刻的内涵和潜力。 首先&#xff0c;元宇宙是一个更为宽泛的概念&#xf…

嵌入式是大坑吗?

嵌入式不是坑&#xff0c;但里面遍地是坑。一不小心&#xff0c;你就会掉进去。 嵌入式覆盖的范围太广&#xff0c;低端的产品太多。 单片机叫嵌入式&#xff0c;开发板叫嵌入式&#xff0c;摄像头叫嵌入式&#xff0c;手机、平板电脑、通讯基站、无人机、机器人、自动驾驶汽…

C++之红黑树剖析

博主&#xff1a;拖拉机厂第一代码手 gitee:拖拉机厂第一代码手 已收录到专栏C&#xff0c;点击访问 目录 &#x1f4b4;红黑树简介&#x1f4b5;红黑树的插入操作&#x1f4b6;红黑树的删除操作&#x1f4b7;红黑树的实现&#x1f4b8;红黑树节点的定义&#x1f4b8;红黑树结构…

autoware 之 op_behavior_selector行为选择器状态机代码分析

autoware 1 op_behavior_selector行为选择器状态机代码分析 /这里是整个状态机运行时的结构&#xff1a;/ //停止状态:[#停止状态]//任务完成状态:[#任务完成状态]//转向状态:[*前进状态,#转向状态]//停止信号停止状态:[*停止信号等待状态,#停止信号停止状态]//前进状态 :[*目…

C语言学习系列-->看淡指针(1)

文章目录 一、概述二、指针变量和地址2.1 取地址操作符2.2 指针变量和解引用操作符2.2.1 指针变量2.2.2 拆解指针类型2.2.4 解引用操作符 2.3 指针变量的大小 三、指针变量的意义3.1 指针的解引用指针-整数 四、 const修饰指针五、指针运算5.1 指针- 整数5.2 指针-指针5.3 指针…

OpenText 企业安全 调查 产品简介

关于OpenText OpenText是一家信息软件公司&#xff0c;使企业能够通过市场领先的信息管理解决方案&#xff08;内部或云中&#xff09;获得洞察力。 全球面临的数字风险 市场合力驱动的信息管理 处于风暴中心的信息 →安全漏洞和数据保护 • 防止威胁并将破坏影响降至最低 …

通过PostMan监视提交文件,验证web文件传输

切换文件流,传输文件 找到图片地址 发送请求然后接受 再来一张 哈&#xff0c;谢谢各位同志的阅读&#xff0c;然后呢如果觉得本文对您有所帮助的话&#xff0c;还给个免费的赞捏 Thanks♪(&#xff65;ω&#xff65;)&#xff89;

【二】数据库系统

数据库系统的分层抽象DBMS 数据的三个层次从 数据 到 数据的结构----模式数据库系统的三级模式&#xff08;三级视图&#xff09;数据库系统的两层映像数据库系统的两个独立性数据库系统的标准结构 数据模型从 模式 到 模式的结构----数据模型三大经典数据模型 数据库的演变与发…

给大家推荐9个Linux高效运维命令技巧!

文章目录 前言一、实用的 xargs 命令二、命令或脚本后台运行三、找出当前系统内存使用量较高的进程四、找出当前系统CPU使用量较高的进程五、同时查看多个日志或数据文件六、持续ping并将结果记录到日志七、查看tcp连接状态八、查找80端口请求数最高的前20个IP九、ssh实现端口转…

构建高性能的MongoDB数据迁移工具:Java的开发实践

随着大数据时代的到来&#xff0c;数据迁移成为许多企业和组织必须面对的挑战之一。作为一种非关系型数据库&#xff0c;MongoDB在应用开发中得到了广泛的应用。为了满足数据迁移的需求&#xff0c;我们需要一个高性能、稳定可靠的MongoDB数据迁移工具。下面将分享使用Java开发…

【华秋推荐】新能源汽车中的T-BOX系统,你了解多少?

近几年&#xff0c;新能源汽车产业进入了加速发展的阶段。我国的新能源汽车产业&#xff0c;经过多年的持续努力&#xff0c;技术水平显著提升、产业体系日趋完善、企业竞争力大幅增强&#xff0c;呈现市场规模、发展质量“双提升”的良好局面。同时&#xff0c;通过国家多年来…