马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
×
一、前言
C++ 为了更安全、简单的使用字符串,对 C语言 中的字符串和相干函数举行封装,实现了 string 类。接下来将会实现 string 与一部门常用的函数。
参考:legacy.cplusplus.com网站的 string
具体实现:
- string部门构造函数、析构函数、赋值运算符重载。
- Iterator 中的 begin、end。
- Capacity 中的 size、resize、capacity、reserve、clear、empty。
- Element access 中的 operator[]。
- Modifiers 中的 operator+=、append、push_back、insert、erase、swap、pop_back 。
- String operations 中的 c_str、find。
- Non-member function overload 中的 relational operators、operator>>、operator<<。
二、string 的成员变量
在 string.h 中:
- namespace my
- {
- class string
- {
- public:
- static const size_t npos = -1;
- private:
- char* _str;
- size_t _capacity;
- size_t _size;
- };
- }
复制代码
- npos 体现的是 string 的竣事位子,具体可参考:C++中string::npos的一些用法总结
- _str 字符指针用来存储 在堆上开辟的 字符串数据的 地点。
- _capacity 体现容器空间巨细,由于 C语言 字符串末端隐蔽了一个 ’ \0 ',则真实存储字符的容量为 _capacity - 1。
- _size 体现当前字符串巨细(不含 ’ \0 ')。
三、string 的紧张部门实现
思量到代码复用,实现并不按照上述分列次序,且只罗列一部门紧张的功能。
reserve
参考:std::string::reserve
C++ 对 string reserve函数规定:
- 当 原空间巨细 小于 需求巨细 时, 对原空间扩容到需求巨细或其以上。
- 当 原空间 大于或便是 需求 时,非须要的缩减空间调解。
这里实现的空间增长为严格的 2 倍扩容,对于 序号 2 的情况接纳直接忽视。
在 string.cpp 中:
- void my::string::reserve(size_t n)
- {
- if (n + 1 <= _capacity) // 考虑末尾 '\0'
- {
- return;
- }
- size_t newCapacity = _capacity == 0 ? MY_STRING_INIT_CAPACITY : _capacity * 2;
- // n 仍然大于newCapacity时继续扩容
- // newCapacity <= n 等价 newCapacity < n + 1
- while (newCapacity <= n)
- {
- newCapacity <<= 1;
- }
- char* str1 = nullptr; // str1存储原空间地址
- std::swap(str1, _str);
- _str = new char[newCapacity]; // _str 新开空间后拷贝
- // _size >= _capacity 只出现在初始化时(这时 _size == _capacity == 0)
- // 以防止超出 _capacity 的非法内存访问
- memcpy(_str, str1, sizeof(char) * (_size >= _capacity ? _capacity : _size + 1));
- _capacity = newCapacity;
- delete[] str1;
- }
复制代码 Iterator
这里迭代器只对原生 char* 举行封装。
参考:std::string::begin
参考:std::string::end
这里只实现部门。
在 my::string 中:
- typedef char* iterator;
- iterator begin()
- {
- return _str;
- }
- iterator end()
- {
- return _str + _size;
- }
复制代码 operator[]
参考:std::string: perator[]
在 my::string 类中
- char& operator[](size_t index)
- {
- return *(_str + index);
- }
- const char& operator[](size_t index) const
- {
- return *(_str + index);
- }
复制代码 insert
这里只实现两个。
参考:std::string::insert
在 string.cpp 中:
- // 在 pos 位置上插入 字符ch / 字符串str,并返回该string
- my::string& my::string::insert(size_t pos, char ch)
- {
- assert(pos <= _size);
- reserve(++_size);
- // 将 pos 原位置与之后字符向后移动一步,再用 ch 覆盖 pos 当前原字符
- for (size_t end = _size; end >= pos + 1; --end)
- {
- _str[end] = _str[end - 1];
- }
- _str[pos] = ch;
- return *this;
- }
- my::string& my::string::insert(size_t pos, const char* str)
- {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (len != 0)
- {
- reserve(_size += len);
- // 将 pos 原位置与之后字符向后移动len步,再用 str 覆盖 pos 和之后原字符串
- for (size_t end = _size; end >= pos + len; --end)
- {
- _str[end] = _str[end - len];
- }
- strncpy(_str + pos, str, len);
- }
- return *this;
- }
复制代码 erase
这里只实现一个。
参考:std::string::erase
在 string.cpp 中:
- // 删除 pos ~ pos + len 位置上的元素,并返回该 string
- my::string& my::string::erase(size_t pos, size_t len)
- {
- assert(pos < _size);
- if (len > _size) // len 默认值为 npos, 此时不能加,会溢出
- {
- len = _size;
- }
- // 若后面还有数据需移动
- for (size_t end = pos; end < _size - len; ++end)
- {
- _str[end] = _str[end + len];
- }
- _size = (_size - pos <= len ? pos : _size - len);
- _str[_size] = '\0'; // '\0' 需单独处理
- return *this;
- }
复制代码 find
这里只实现两个。
参考:std::string::find
在 string.cpp 中:
- // 返回 ch 在 string 中第一次出现的位置
- size_t my::string::find(char ch, size_t pos) const
- {
- assert(pos <= _size);
- size_t index = pos;
- while (index < _size)
- {
- if (_str[index] == ch)
- {
- break;
- }
- ++index;
- }
- return index == _size ? npos : index;
- }
- // 返回子串 str1 在 string 中第一次出现的位置
- size_t my::string::find(const char* str1, size_t pos) const
- {
- size_t len1 = strlen(str1);
- assert(pos + len1 <= _size);
- size_t index = pos;
- while (index + len1 <= _size)
- {
- if (strncmp(_str + index, str1, len1) == 0)
- {
- break;
- }
- ++index;
- }
- return index + len1 <= _size ? index : npos;
- }
复制代码 resize
参考:std::string::resize
在 my::string 中:
- void resize(size_t n, char ch = '\0')
- {
- if (n > _size)
- {
- reserve(n);
- for (int i = _size + 1; i < n; ++i)
- {
- _str[i] = ch;
- }
- }
- _str[_size = n] = '\0';
- }
复制代码 构造、析构、赋值重载
参考:std::string::string
参考:std::string::~string
参考:std::string: perator=
在 my::string 中:
- string(const char* str1 = "")
- :_str(nullptr)
- ,_size(0)
- ,_capacity(0)
- {
- size_t len1 = strlen(str1);
- reserve(len1);
- memcpy(_str, str1, sizeof(char) * (len1 + 1));
- _size = len1;
- }
- string(const string& str1)
- :_str(nullptr)
- ,_size(0)
- ,_capacity(0)
- {
- reserve(str1.capacity());
- memcpy(_str, str1._str, sizeof(char) * (str1._size + 1));
- _size = str1._size;
- }
- ~string()
- {
- if (_str != nullptr)
- {
- delete[] _str;
- _str = nullptr;
- }
- _size = _capacity = 0;
- }
- void swap(string& str1)
- {
- std::swap(_str, str1._str);
- std::swap(_size, str1._size);
- std::swap(_capacity, str1._capacity);
- }
- string& operator=(string str1)
- {
- swap(str1);
- return *this;
- }
复制代码 四、string 源代码
在 string.h 中:
- #pragma once#define _CRT_SECURE_NO_WARNINGS 1#include <iostream>#include <cassert>#define MY_STRING_INIT_CAPACITY 4namespace my{ class string { friend std::ostream& operator<<(std::ostream& cout, const my::string& str1); friend std::istream& operator>>(std::istream& cin, my::string& str1); public: typedef char* iterator; public: string(const char* str1 = "")
- :_str(nullptr)
- ,_size(0)
- ,_capacity(0)
- {
- size_t len1 = strlen(str1);
- reserve(len1);
- memcpy(_str, str1, sizeof(char) * (len1 + 1));
- _size = len1;
- }
- string(const string& str1)
- :_str(nullptr)
- ,_size(0)
- ,_capacity(0)
- {
- reserve(str1.capacity());
- memcpy(_str, str1._str, sizeof(char) * (str1._size + 1));
- _size = str1._size;
- }
- ~string()
- {
- if (_str != nullptr)
- {
- delete[] _str;
- _str = nullptr;
- }
- _size = _capacity = 0;
- }
- void swap(string& str1)
- {
- std::swap(_str, str1._str);
- std::swap(_size, str1._size);
- std::swap(_capacity, str1._capacity);
- }
- string& operator=(string str1)
- {
- swap(str1);
- return *this;
- }
- //----------------------------------------------------------- iterator begin() { return _str; } iterator end() { return _str + _size; } //----------------------------------------------------------- void push_back(char ch) { insert(_size, ch); } void pop_back() { erase(_size - 1, 1); } string& operator+=(char ch) { return insert(_size, ch); } void append(const char* str1) { insert(_size, str1); } string& operator+=(const char* str1) { return insert(_size, str1); } void clear() { _str[_size = 0] = 0; } const char* c_str() const { return _str; } //----------------------------------------------------------- size_t size() const { return _size; } size_t capacity() const { return _capacity - 1; } bool empty() const { return _size == 0; } void resize(size_t n, char ch = '\0')
- {
- if (n > _size)
- {
- reserve(n);
- for (int i = _size + 1; i < n; ++i)
- {
- _str[i] = ch;
- }
- }
- _str[_size = n] = '\0';
- }
- void reserve(size_t n); //----------------------------------------------------------- char& operator[](size_t index)
- {
- return *(_str + index);
- }
- const char& operator[](size_t index) const
- {
- return *(_str + index);
- }
- //----------------------------------------------------------- bool operator<(const string& str1) { return strcmp(c_str(), str1.c_str()) < 0; } bool operator>(const string& str1) { return strcmp(c_str(), str1.c_str()) > 0; } bool operator==(const string& str1) { return strcmp(c_str(), str1.c_str()) == 0; } bool operator<=(const string& str1) { return !(*this > str1); } bool operator>=(const string& str1) { return !(*this < str1); } bool operator!=(const string& str1) { return !(*this == str1); } //----------------------------------------------------------- size_t find(char ch, size_t pos = 0) const; size_t find(const char* str1, size_t pos = 0) const; string& insert(size_t pos, char ch); string& insert(size_t pos, const char* str); string& erase(size_t pos = 0, size_t len = npos); static const size_t npos = -1; private: char* _str; size_t _capacity; size_t _size; };}
复制代码 在 string.cpp 中:
- #include "string.h"void my::string::reserve(size_t n)
- {
- if (n + 1 <= _capacity) // 考虑末尾 '\0'
- {
- return;
- }
- size_t newCapacity = _capacity == 0 ? MY_STRING_INIT_CAPACITY : _capacity * 2;
- // n 仍然大于newCapacity时继续扩容
- // newCapacity <= n 等价 newCapacity < n + 1
- while (newCapacity <= n)
- {
- newCapacity <<= 1;
- }
- char* str1 = nullptr; // str1存储原空间地址
- std::swap(str1, _str);
- _str = new char[newCapacity]; // _str 新开空间后拷贝
- // _size >= _capacity 只出现在初始化时(这时 _size == _capacity == 0)
- // 以防止超出 _capacity 的非法内存访问
- memcpy(_str, str1, sizeof(char) * (_size >= _capacity ? _capacity : _size + 1));
- _capacity = newCapacity;
- delete[] str1;
- }
- // 返回c在string中第一次出现的位置size_t my::string::find(char ch, size_t pos) const{ assert(pos <= _size); size_t index = pos; while (index < _size) { if (_str[index] == ch) { break; } ++index; } return index == _size ? npos : index;}// 返回子串str1在string中第一次出现的位置size_t my::string::find(const char* str1, size_t pos) const{ size_t len1 = strlen(str1); assert(pos + len1 <= _size); size_t index = pos; while (index + len1 <= _size) { if (strncmp(_str + index, str1, len1) == 0) { break; } ++index; } return index + len1 <= _size ? index : npos;}// 在 pos 位置上插入 字符ch / 字符串str,并返回该string
- my::string& my::string::insert(size_t pos, char ch)
- {
- assert(pos <= _size);
- reserve(++_size);
- // 将 pos 原位置与之后字符向后移动一步,再用 ch 覆盖 pos 当前原字符
- for (size_t end = _size; end >= pos + 1; --end)
- {
- _str[end] = _str[end - 1];
- }
- _str[pos] = ch;
- return *this;
- }
- my::string& my::string::insert(size_t pos, const char* str)
- {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (len != 0)
- {
- reserve(_size += len);
- // 将 pos 原位置与之后字符向后移动len步,再用 str 覆盖 pos 和之后原字符串
- for (size_t end = _size; end >= pos + len; --end)
- {
- _str[end] = _str[end - len];
- }
- strncpy(_str + pos, str, len);
- }
- return *this;
- }
- // 删除 pos ~ pos + len 位置上的元素,并返回该 string
- my::string& my::string::erase(size_t pos, size_t len)
- {
- assert(pos < _size);
- if (len > _size) // len 默认值为 npos, 此时不能加,会溢出
- {
- len = _size;
- }
- // 若后面还有数据需移动
- for (size_t end = pos; end < _size - len; ++end)
- {
- _str[end] = _str[end + len];
- }
- _size = (_size - pos <= len ? pos : _size - len);
- _str[_size] = '\0'; // '\0' 需单独处理
- return *this;
- }
- std::ostream& my::operator<<(std::ostream& out, const my::string& str1){ out << str1.c_str(); return out;}std::istream& my::operator>>(std::istream& in, my::string& str1){ str1.clear(); // 缓冲 char buf[100] = { 0 }; char ch = in.get(); int i = 0; while (ch != ' ' && ch != '\n') { buf[i++] = ch; if (i >= 99) { str1 += buf; i = 0; } ch = in.get(); } if (i > 0) { buf[i] = '\0'; str1 += buf; } return in;}
复制代码 |