C++:string类模拟实现

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,为假返回falsereturn (_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位置上插入字符串strstring& 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;//指针相减得到指针间元素数量,刚好为下标elsereturn 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;}//// iteratoriterator 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,为假返回falsereturn (_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;}}/// accesschar& 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;//指针相减得到指针间元素数量,刚好为下标elsereturn 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位置上插入字符cstring& 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位置上插入字符串strstring& 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.hqwc.cn/news/62608.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录一次使用python调用java代码

Python调用Java代码的主要原理是通过使用Java虚拟机&#xff08;JVM&#xff09;和相关的库/工具实现的。 在Python中&#xff0c;可以使用以下几种方式来调用Java代码&#xff1a; 使用subprocess模块&#xff1a;可以通过subprocess模块来启动一个子进程&#xff0c;并在子进…

深入浅出 Typescript

TypeScript 是 JavaScript 的一个超集&#xff0c;支持 ECMAScript 6 标准&#xff08;ES6 教程&#xff09;。 TypeScript 由微软开发的自由和开源的编程语言。 TypeScript 设计目标是开发大型应用&#xff0c;它可以编译成纯 JavaScript&#xff0c;编译出来的 JavaScript …

echart图案例

效果 代码&#xff1a; index.vue <template><div class"pageBox"><div class"oneLineBox"><div class"fourColorImgBox"><div class"titleBox">企业风险四色图</div><div class"conte…

Scrum敏捷模型的三个角色!如何在线绘制Scrum敏捷模型图?

1. 什么是Scrum敏捷模型&#xff1f; Scrum是一种敏捷开发方法&#xff0c;用于管理和组织软件开发项目。它强调团队的自组织和迭代式开发&#xff0c;通过不断的反馈和调整来快速交付高质量的软件产品。 Scrum敏捷模型将项目分解为一系列短期的迭代周期&#xff0c;每一个…

ffmpeg命令行是如何打开vf_scale滤镜的

前言 在ffmpeg命令行中&#xff0c;ffmpeg -i test -pix_fmt rgb24 test.rgb&#xff0c;会自动打开ff_vf_scale滤镜&#xff0c;本章主要追踪这个流程。 通过gdb可以发现其基本调用栈如下&#xff1a; 可以看到&#xff0c;query_formats&#xff08;&#xff09;中创建的v…

【遍历】非递归法 二叉树的前中后序遍历

文章目录 非递归法前序遍历后序遍历中序遍历 递归法DFS 非递归法 通过栈Stack来模拟递归。 前序遍历 LeetCode 144 前序遍历&#xff1a;1 2 3 定义&#xff1a;存放答案的List、栈Stack 将root入栈出栈&#xff1a;node&#xff0c;为null则舍弃将node放入list将node.r…

安全测试中常见的业务安全问题

“在测试过程中&#xff0c;特殊的操作往往容易触发异常场景&#xff0c;而这些异常场景也很容易引起安全问题&#xff01;” 常见的安全漏洞就不多说了&#xff0c;这里主要介绍常见的业务安全问题及修复建议。 01 刷短信 问题描述&#xff1a; 当发送短信的请求接口只需要…

股票自动交易接口开发原理及源码分享

股票自动交易接口的开发原理涉及多个方面&#xff0c;主要包括以下几个步骤&#xff1a; 1. 数据接口获取&#xff1a;通过连接到证券交易所或第三方数据提供商的API&#xff0c;获取实时市场数据&#xff0c;包括股票报价、交易成交量、买卖盘口等信息。 2. 策略定义&#x…

田间农业数字管理系统-高标准农田建设

政策背景 2019年11月&#xff0c;国务院办公厅印发的《国务院办公厅关于切实加强高标准农田建设提升粮食安全保障能力的意见》明确提出&#xff0c;到2022年&#xff0c;全国要建成10亿亩高标准农田。 2021年9月16日&#xff0c;由农业农村部印发的《全国高标准农田建设规划&a…

Ajax 笔记(二)—— Ajax 案例

笔记目录 2. Ajax 综合案例2.1 案例一-图书管理2.1.1 渲染列表2.1.2 新增图书2.1.3 删除图书2.1.4 编辑图书 2.2 案例二-背景图的上传和更换2.2.1 上传2.2.2 更换 2.3 案例三-个人信息设置2.3.1 信息渲染2.3.2 头像修改2.2.3 信息修改2.3.4 提示框 Ajax 笔记&#xff1a; Ajax…

创新零售,京东重新答题?

继新一轮组织架构调整后&#xff0c;京东从低价到下沉动作不断。 新成立的创新零售部在京东老将闫小兵的带领下悄然完成了整合。近日&#xff0c;京喜拼拼已改名为京东拼拼&#xff0c;与七鲜、前置仓等业务共同承载起京东线上线下加速融合的梦想。 同时&#xff0c;拼拼的更…

JVM系统优化实践(24):ZGC(一)

您好&#xff0c;这里是「码农镖局」CSDN博客&#xff0c;欢迎您来&#xff0c;欢迎您再来&#xff5e; 截止到目前&#xff0c;算上ZGC&#xff0c;Java一共有九种类型的GC&#xff0c;它们分别是&#xff1a; 1、Serial GC 串行/作用于新生代/复制算法/响应速度优先/适用于单…