昨天学习了string类的基本实现,今天学习了完整的简单版实现,特来社区记录。

目录

前言

一、增

1.reserve扩容

2.push_back()插入

3.append()插入

4.+=重载

二、删

1.erase()

三、查

四、迭代器

五、[]重载

总结



前言

本文主要模拟实现string类的增删查改的成员函数。


一、增

由于历史遗留问题,string类实现了push_back(), append()等增加字符或者是字符串的函数,它们或多或少都有一些内容上的重叠功能实现,其中是以+=重载最为实用。

在此类函数实现之前需要判断剩下的capacity够不够放插入的字符串:

1. 插入一个字符,就判断_size+1后与_capacity的大小

2. 插入一个字符串,就判断_size+strlen(str) 后与_capacity的大小

所以需要先实现一个扩容函数来保证没有越界问题。

1.reserve扩容

代码如下(示例):

// 扩容函数
void reserve(size_t n);// s1.reserve(20)
void qyy::string::reserve(size_t n)
{if (n > _capacity){char* tmp = new char[n + 1];if (tmp){strcpy(tmp, _str);_str = tmp;_capacity = n;}}
}

2.push_back()插入

代码如下(示例):

// 声明
void push_back(const char ch);
void push_back(const char* str);
// 定义
void qyy::string::push_back(const char ch)
{if (_size + 1 > _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}// 指向'\0'char* end = _str + _size;*(end + 1) = * end;_str[_size++] = ch;
}
void qyy::string::push_back(const char* str)
{size_t len = strlen(str);// 判断增容if (_size + len > _capacity){reserve(_size + len);}// 指向'\0'char* end = _str + _size;*(end + len) = *end;strncpy(_str+_size, str, len);_size += len;_str[_size] = '\0';
}

3.append()插入

代码如下(示例):

// 定义
void append(const char ch, size_t pos);
void append(const char* str, size_t pos);
//定义
void qyy::string::append(const char ch, size_t pos)
{assert(pos <= _size);// 判断增容if (_size + 1 > _capacity){reserve(_capacity * 2);}char* begin = _str + pos;char* end = _str + _size;while (end > begin){*(end + 1) = *end;end--;}_str[pos] = ch;_str[++_size] = '\0';
}
// 定义
void qyy::string::append(const char* str, size_t pos)
{assert(pos <= _size);size_t len = strlen(str);// 判断增容while (_size + len > _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}char* begin = _str + pos - 1;char* end = _str + _size;while (end > begin){*(end + len) = *end;end--;}strncpy(_str + pos, str, len);_size += len;_str[_size] = '\0';
}

4.+=重载

直接复用push_back() 和 append()即可。

代码如下(示例):

// 声明
string& operator+=(const char ch);
string& operator+=(const char* str);// 定义
string& qyy::string::operator+=(const char ch)
{qyy::string::push_back(ch);return *this;
}
string& qyy::string::operator+=(const char* str)
{qyy::string::append(str, _size);return *this;
}

二、删

1.erase()

删除函数分为两种情况:

1. 要删除的长度小于从要删除的位置开始剩余字符的个数,也就是够删

2. 与1相反,不够删的情况,那就是从pos开始所有的字符全部删干净

代码如下(示例):

// 删
string& erase(size_t pos, size_t len);// 定义
string& qyy::string::erase(size_t pos, size_t len)
{// 剩下的字符个数不够删if (_size - pos < len){_str[pos] = '\0';_size = _capacity = 0;return *this;}// 够删while (len > 0){char* begin = _str + pos;char* end = _str + _size;while (begin < end){*begin = *(begin + 1);begin++;}_size--;len--;}return *this;
}

三、查

函数要实现从pos开始查找给定的字符或者字符串,返回查找到的字符或者字符串位置的下标,找不到那就返回npos。

代码如下(示例):

// 查
size_t find(const char ch, size_t pos);
size_t find(const char* str, size_t pos);// 定义
size_t qyy::string::find(const char ch, size_t pos)
{int i = 0;for (i = 0; i < _size; i++){if (_str[i] == ch){return i;}}if (i == _size){return npos;}
}
size_t qyy::string::find(const char* str, size_t pos)
{const char* ptr = strstr(_str, str);if (ptr)return ptr - _str;elsereturn npos;
}

四、迭代器

迭代器我目前的理解就是一个指针,begin指向空间的开头,end则指向空间的末尾。

代码如下(示例):

typedef char* iterator;
typedef const char* cosnt_iterator;
qyy::string::iterator begin()
{return _str;
}
qyy::string::iterator end()
{return _str + _size;
}

五、[]重载

此运算符的重载使得字符串能像数组一样能够用下标支持随机访问。

代码如下(示例):

// []重载
char operator[](size_t pos);// 定义
char qyy::string::operator[](size_t pos)
{// 读取内容须在字符串中assert(pos < _size);return *(_str + pos);
}

六、流提取、流插入

">>" 和 "<<"的重载很微妙:

如果需要访问私有,为了方便那就不可避免地需要重载为友元函数(比如在日期类中),但是在string中,因为有[](下标)的重载可以访问到字符串的各个元素,所以只用在全局定义即可。(在全局是为了避免存在隐含的this参数使得cout与string对象的参数顺序符合常识,即cout是<<的第一个参数,string对象是<<的第二个参数)

代码如下(示例):

// 声明
std::ostream& operator<<(std::ostream& out, string& s);
std::istream& operator>>(std::istream& in, string& s);// 定义
// cout<<
std::ostream& qyy::operator<<(std::ostream& out, string& s)
{for (auto ch : s){out << ch;}out << '\n';// 不能写:// 这样会在遇到'\0'时终止//out << s.c_str();return out;
}// cin>>
std::istream& qyy::operator>>(std::istream& in, string& s)
{// 必须使用匿名对象去调用成员函数string().clear(s);char ch = in.get();while (ch != ' ' && ch != '\n'){s += ch;ch = in.get();}return in;
}

七、比较大小

与C库的strcmp()实现相同,我自己同时也早了一个轮子。

代码如下(示例):

// 定义
bool operator<(string& s);
bool operator>(string& s);
bool operator==(string& s);
bool operator<=(string& s);
bool operator>=(string& s);// 比较大小
bool qyy::string::operator<(string& s)
{//char* p1 = _str;//char* p2 = s._str;//while (p1 != _str + _size && p2 != s._str + s._size)//{//    if (*p1 == *p2)// {//     p1++;//       p2++;//   }// else if (*p1 < *p2)//    {//     return true;//  }// else if (*p1 > *p2)//    {//     return false;// }//}两个字符串不一样长//if (p1 == _str + _size && p2 != s._str+s._size)//{//    return true;//}//else//{//  return false;//}// 或者直接调用库函数return strcmp(_str, s.c_str()) < 0;
}
bool qyy::string::operator==(string& s)
{return strcmp(_str, s.c_str()) == 0;
}
bool qyy::string::operator<=(string& s)
{return (*this < s || *this == s);
}
bool qyy::string::operator>=(string& s)
{return !(*this < s);
}
bool qyy::string::operator>(string& s)
{return !(*this <= s);
}

八、清空

清空与erase中全部删完的情况相同,且为头删。

代码如下(示例):

// 清空
void clear(string& s); // 定义
void qyy::string::clear(string& s)
{s._str[0] = '\0';s._size = 0;
}

总结

今天系统学习了string类成员函数的详细实现,速度并不是很快,对于数组的控制不是很到位,像书上说的一样:“在这件事上,你总是少了一位。”以后要加强学习,加大代码量练习,再接再厉!

【c++】string类的模拟实现(下)相关推荐

  1. String类的模拟实现

    目录: 一.经典String类的问题 1,浅拷贝 2,深拷贝 二.现代写法版的string类 三.传统String类的模拟实现 1.迭代器 2.operator[] 3.size() 4.c_str( ...

  2. C++关于string类的模拟实现

    文章目录 一.string类的模拟实现 1.成员变量 2.构造函数 (1)无参构造函数 (2)有参构造函数 3.c_str函数 4.operator[] 5.深浅拷贝问题 (1)浅拷贝 (2)深拷贝 ...

  3. 内存分布malloc/calloc/realloc/free/new/delete、内存泄露、String模板、浅拷贝与深拷贝以及模拟string类的实现

    内存分布 一.C语言中的动态内存管理方式:malloc/calloc/realloc和free 1.malloc: 从堆上获得指定字节的内存空间,函数声明:void *malloc (int n); ...

  4. 冰冰学习笔记:string类的简单模拟

    欢迎各位大佬光临本文章!!! 还请各位大佬提出宝贵的意见,如发现文章错误请联系冰冰,冰冰一定会虚心接受,及时改正. 本系列文章为冰冰学习编程的学习笔记,如果对您也有帮助,还请各位大佬.帅哥.美女点点支 ...

  5. C++STL详解(一)string类的使用及其模拟实现

    文章目录 1. 为什么有string类 2. 什么是string类 3. string的常用接口 构造函数 赋值重载 遍历: 下标+[] operator[]和at对比 迭代器 范围for(C++11 ...

  6. 『C++』string类模拟实现

    深拷贝与浅拷贝 首先来看一段代码 #include <iostream> #include <string.h> #include <assert.h>class ...

  7. C++---string类接口整理与深浅拷贝

    string:是表示字符串序列的类,不能操作多字节或者变长字符序列 在使用string类时,必须包含#include头文件以及using namespace std; 常见的接口整理 常见的strin ...

  8. 《C++中STL引入和string类常用接口+自我实现-》

    前言 在这篇博客里将详细说说C++中的STL,通过这篇我们可以学习到什么是STL,以及STL的六大组件,STL具有的缺陷,最后看看string类及面试会让模拟实现string类的操作. 文章目录 前言 ...

  9. Learning C++ No.11【string类实现】

    引言: 北京时间:2023/2/19/8:48,昨天更新了有关进程状态的博客,然后在休息的时候,打开了腾讯视屏,然后看到了了一个电视剧,导致上头,从晚上6点看到了10点,把我宝贵的博客时间给搞没了,伤 ...

最新文章

  1. 周长相等的正方形面积一定相等_必考单元:三年级下册面积计算公式+知识点+测试卷(附答案),重点内容,收藏练习!...
  2. 《刺杀小说家》读后感
  3. java float f1=0.5_Java Math类静态float copySign(float f1,float f2)与示例
  4. jquery 实现 点击把数据移动右侧 点击再次移回到左侧
  5. 22 | 哈希算法(下):哈希算法在分布式系统中有哪些应用?
  6. 计算机网络(十五)-数据链路层-CSMA/CA协议
  7. 数学老师从没这么教过,乘法竖式中进位可以是多位(附Python实现与测试源码)...
  8. Web前端笔记(8) 管后台理页面
  9. Android仿人人客户端(v5.7.1)——项目框架新做的调整描述(项目中基类java源码)...
  10. 一个树杈y图片_鬼脸纹:黄花梨树上一个树杈,反映到主干上时,会形成一个疖痕...
  11. c语言进程池原理及实现
  12. IOS免越狱安装历史版本APP软件
  13. 检查mysql被挂马_对付数据库被挂马有绝招
  14. 列表 元组 字典的概念及其案例
  15. 圣诞献礼 | AI、微服务、DevOps、企业架构文章合集
  16. 什么是 ECC 内存?(memory with ECC)
  17. 【javaScript案例】之搜索的数据显示
  18. python爬虫百度地图_零基础掌握百度地图兴趣点获取POI爬虫(python语言爬取)(基础篇)...
  19. 【数据压缩】作业1-1:对浊音、清音、爆破音进行音频分析
  20. 罪恶黑名单第一季/全集The Blacklist迅雷下载

热门文章

  1. 幼儿园初级职称计算机考试,幼儿园教师考试
  2. “金蝶KIS记账王”双11五折特惠
  3. python图片批量处理(水印、重命名)
  4. Linux设置开机自启
  5. SQuirreL SQL Client (小松鼠) 数据库连接工具
  6. android usb麦克风阵列,语音设备 SDK 麦克风阵列建议
  7. 在线考试防作弊js代码
  8. android开机动画不播放,android 设置activity启动退出动画 | 解决设置activity 动画不生效问题...
  9. PTA 1032 挖掘机技术哪家强 (c语言)
  10. 1262: 魔法宝石 (“玲珑杯”河南工业大学ACM程序设计大赛)