cpp—string类的模拟实现
- string类的模拟实现
- string.h
- test.cpp
string类的模拟实现
相信大家看完我的这篇有关string使用的博客(C++中的string类使用,看我这一篇就够了!)之后对于string类的基本使用有了一定的了解,
因此这篇我们来看看string类底层是如何实现的!
在这之前我们需要了解的基本知识有
C++快速入门,看我这一篇就够了!
cpp – 构造函数与析构函数
cpp–拷贝构造函数详解
cpp–赋值运算符重载,浅显易懂!
cpp–初始化列表,超详细,一看就会!
cpp–内存管理(new/delete的用法),超详细讲解,一看就会!
C++中的string类使用,看我这一篇就够了!
string.h
#pragma once
#include <assert.h>namespace s
{class string{public:typedef char* iterator;typedef const char* const_iterator;iterator begin(){return _str;}iterator end(){int length = _size;return _str + length;}const iterator begin() const{return _str;}const iterator end() const{return _str + _size;}string(const char* str = ""):_size(strlen(str)),_capacity(_size){_str = new char[_capacity + 1];strcpy(_str, str);}//string(const string& s)//深拷贝构造函数//{// _str = new char[s._capacity + 1];// strcpy(_str, s._str);// _size = s._size;// _capacity = s._capacity;//}void swap(string& s){std::swap(_str, s._str);std::swap(_size, s._size);std::swap(_capacity, s._capacity);}//深拷贝构造函数的现代写法string(const string& s):_str(nullptr), _size(0), _capacity(0){string tmp(s._str);swap(tmp);}/*string& operator=(const string& s){if (this != &s){char* tmp = new char[s._capacity + 1];strcpy(tmp, _str);delete[] _str;_str = tmp;_size = s._size;_capacity = s._capacity;}return *this;}*/string& operator=(string tmp){swap(tmp);return *this;}char* c_str(){return _str;}size_t capacity(){return _capacity;}size_t size(){return _size;}//bool operator<(const string& str) const//{// size_t i = 0;// //逐个字符比较,直到其中一个字符串结束// while (i < _size && str._str[i] != '\0')// {// if (_str[i] > str._str[i])// {// return false;// }// else if (_str[i] < str._str[i])// {// return true;// }// i++;// }// if (i == _size && str._str[i] != '\0')// {// return true;// }// return false;//}bool operator<(const string& str) const{//size_t i = 0; 逐个字符比较,直到其中一个字符串结束//while (i < _size && i < str._size)//{// if (_str[i] < str._str[i])// {// return true;// }// else if (_str[i] > str._str[i])// {// return false;// }// i++;//} 如果前面字符都相等,比较字符串长度//return _size < str._size;//使用库函数return strcmp(_str, str._str) < 0;}bool operator==(const string& s){return strcmp(_str, s._str) == 0;}bool operator<=(const string& s){return (*this < s) || (*this == s);}bool operator>(const string& s){return !(*this <= s);}bool operator>=(const string& s){return (*this == s) || (*this > s);}char& operator[](size_t pos){assert(pos < _size);return _str[pos];}string& operator+=(char ch){push_back(ch);return *this;}string& operator+=(const char* str){append(str);return *this;}void clear(){_str[0] = '\0';_size = 0;}void reserve(size_t n){if (n > _capacity){char* tmp = new char[n + 1];strcpy(tmp,_str);delete[] _str;_str = tmp;_capacity = n;}}void push_back(char ch){if (_size == _capacity){reserve(_capacity == 0 ? 4 : _capacity * 2);}_str[_size] = ch;_size += 1;_str[_size] = '/0';}void append(const char* str){int length = strlen(str)+_size;if(_capacity<length)reserve(length);strcpy(_str + _size, str);_size += strlen(str);}/*void insert(size_t pos, char ch) //方法一{assert(pos <= _size);if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size+1;for (size_t i = end;i > pos;i--){_str[i] = _str[i-1];}_str[pos] = ch;_size++;_str[_size] = '\0';}*/void insert(size_t pos, char ch) //方法二{assert(pos <= _size);if (_capacity == _size){reserve(_capacity == 0 ? 4 : 2 * _capacity);}size_t end = _size;for (int i = (int)end;i >= (int)pos;i--){_str[i+1] = _str[i];}_str[pos] = ch;_size++;_str[_size] = '\0';}void insert(size_t pos, const char* str){int length = strlen(str);if (_size + length > _capacity){reserve(_size+length);}for (int i = (int)_size; i >= (int)pos; i--){_str[i + length] = _str[i];}strncpy(_str+pos, str, length);_size += length;}//strcpy:会复制整个源字符串,直到遇到字符串结束符 '\0',// 它不会对复制的字符数量进行额外的限制。// 如果目标字符串的空间不足以容纳源字符串,会导致缓冲区溢出,// 这是一种非常危险的情况,可能会引发程序崩溃或安全漏洞//strncpy:可以指定最多复制的字符数量 n。// 如果源字符串的长度小于 n,则会将源字符串全部复制到目标字符串,// 并且在目标字符串后面填充 '\0' 直到复制的字符总数达到 n;// 如果源字符串的长度大于等于 n,则只会复制 n 个字符,// 不会自动添加字符串结束符 '\0',// 这可能导致目标字符串不是以 '\0' 结尾的有效字符串string substr(size_t pos, size_t len = npos){string s;size_t end = pos + len;if (pos + len >= _size || len == npos){len = _size - pos;end = _size;}s.reserve(len);for (size_t i = pos;i < pos + len;i++){s += _str[i];}return s;}void erase(size_t pos, size_t len = npos){assert(pos < _size);if (pos + len >= _size || len == npos){_str[pos] = '\0';_size = pos;}else{int end = pos + len;for (int i = pos+len; i <= _size; i++){_str[i-len] = _str[i];}_size -= len;_str[_size] = '\0';}}void resize(int n, char ch = '\0'){if (n > _size){reserve(n);while (_size < n){_str[_size] = ch;++_size;}_str[_size] = '\0';}else if (n <= _size){_str[n] = '\0';_size = n;}}size_t find(char ch, int pos = 0){while (pos < _size){if (ch == _str[pos]){return pos;}++pos;}return npos;}size_t find(const char* sub, int pos = 0){const char* p = strstr(_str + pos, sub);//返回sub在字符串中第一次出现的位置if (p){return p - _str;}else{return npos;}}const static size_t npos;private:char* _str;size_t _size;size_t _capacity;};const size_t string::npos = -1;istream& operator>>(istream& in, string& s){s.clear();char buff[129];size_t i = 0;char ch;ch = in.get();while (ch != ' ' && ch != '\n'){buff[i++] = ch;if (i == 128){buff[i] = '\0';s += buff;i = 0;}ch = in.get();}if (i != 0){buff[i] = '\0';s += buff;}return in;}ostream& operator<<(ostream& out, const string& s){for (auto ch : s){out << ch;}return out;}void test_string1(){string s1("hello world");cout << s1.c_str() << endl;string s2;cout << s2.c_str() << endl;cout << s1.size() << endl;cout << s2.size() << endl;cout << s1.capacity() << endl;cout << s2.capacity() << endl;for (size_t i = 0; i < s1.size();i++){cout << s1[i] ;}cout << endl;string::iterator it = s1.begin();while (it != s1.end()){cout << *it << " ";++it;}cout << endl;for (auto& ch : s1){cout << ch << " ";}}void test_string2(){string s1("hello world");cout << s1.c_str() << endl;s1.push_back(' ');s1.append("hello boy");cout << s1.c_str() << endl;}void test_string3(){string s1("hello world");cout << s1.c_str() << endl;s1.insert(0, '%');//在头插时可能出现的问题//在将元素后移的 for 循环中,for (size_t i = end; i >= pos; i--) // 会导致无限循环。因为 size_t 是无符号整数类型,// 当 i 减到 0 后再减 1 会变成一个很大的正数(发生下溢),// 而不是负数,所以循环条件 i >= pos 始终为真。// 可以将循环变量改为有符号整数类型,或者从后往前移动元素cout << s1.c_str() << endl;s1.insert(0, "##############################");cout << s1.c_str() << endl;}void test_string4(){string s1("hello worad");string s2("hello worsld");cout << (s1 < s2) << endl;s1[0] = 'z';cout << (s1 >= s2) << endl;cin >> s1>>s2;cout << s1 <<s2<< endl;}void test_string5(){string s1("hello world");s1.insert(5, "abc");s1.insert(0, "xxx");cout << s1 << endl;s1.erase(0, 3);cout << s1 << endl;s1.erase(5, 100);cout << s1 << endl;}void test_string6(){string s1("hello world");cout << s1 << endl;s1.resize(5);cout << s1 << endl;s1.resize(25, 'x');cout << s1 << endl;}void test_string7(){string s1("test.cpp.tar.zip");//size_t i = s1.find('.');//size_t i = s1.rfind('.');//string s2 = s1.substr(i);//cout << s2 << endl;string s3("https://legacy.cplusplus.com/reference/string/string/rfind/");//string s3("ftp://www.baidu.com/?tn=65081411_1_oem_dg");// 协议// 域名// 资源名string sub1, sub2, sub3;size_t i1 = s3.find(':');if (i1 != string::npos)sub1 = s3.substr(0, i1);elsecout << "没有找到i1" << endl;size_t i2 = s3.find('/', i1 + 3);if (i2 != string::npos)sub2 = s3.substr(i1 + 3, i2 - (i1 + 3));elsecout << "没有找到i2" << endl;sub3 = s3.substr(i2 + 1);cout << sub1 << endl;cout << sub2 << endl;cout << sub3 << endl;}void test_string8(){string s1("hello world");string s2 = s1;cout << s1 << endl;cout << s2 << endl;string s3("xxxxxxxxxxxxxxx");s1 = s3;cout << s3 << endl;}void test_string9(){string s1("hello world");cin >> s1;cout << s1 << endl;}
}
test.cpp
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
using namespace std;
#include "string.h"
int main()
{s::test_string9();return 0;
}