主页 > 电脑硬件  > 

string的模拟实现

string的模拟实现

string.h

#define _CRT_SECURE_NO_WARNINGS 1 #pragma once #include<iostream> #include<assert.h> using namespace std; namespace yjc { class string { public: //typedef char* iterator; // 实现迭代器, 原来迭代器就是一个像指针的东西,任何容器都是 using iterator = char*; // 因为string底层的物理结构是连续的,所以直接用指针就可以实现 using const_iterator = const char*; //string(); //string(const char* str); string(const char* str = ""); string(const string& s); string& operator= (const string& s); ~string(); void reserve(size_t n); void push_back(char ch); void append(const char* str); string& operator+=(char ch); string& operator+=(const char* str); void insert(size_t pos, char ch); void insert(size_t pos, const char* str); void erase(size_t pos, size_t len = npos); size_t find(char ch, size_t pos = 0); size_t find(const char* str, size_t pos = 0); string substr(size_t pos, size_t len = npos); void clear() { _str[0] = '\0'; _size = 0; } char& operator[](size_t i) // 可读可写 { assert(i < _size); return _str[i]; } const char& operator[](size_t i) const { assert(i < _size); return _str[i]; } size_t size() const { return _size; } iterator begin() // 迭代器要结合begin和end一起使用 { return _str; } iterator end() { return _str + _size; // 指向的是最后一个位置的下一个位置 } const_iterator begin() const // 实现一个const修饰的迭代器 注意这里的命名,表示不是迭代器不能修改,而是迭代器指向的内容不能修改 { return _str; } const_iterator end() const { return _str + _size; } const char* c_str() const// 隐含的this指针好用 { return _str; } void swap(string& s); private: char* _str; size_t _size; size_t _capacity; public: // static const size_t npos = -1; // 静态成员变量按理来说是类中声明类外定义,但是有const修饰 之后就可在类中定义,而且只有整形才可以, 是一个特殊处理 static const size_t npos; }; void swap(string& s1, string& s2); // 全部重载为全局函数,为了支持字符串和string比较,类中的成员函数有抢位置的问题 bool operator== (const string& lhs, const string& rhs); // 常量字符串可以隐式类型转换为string类型 bool operator!= (const string& lhs, const string& rhs); bool operator> (const string& lhs, const string& rhs); bool operator< (const string& lhs, const string& rhs); bool operator>= (const string& lhs, const string& rhs); bool operator<= (const string& lhs, const string& rhs); ostream& operator<<(ostream& os, const string& str); istream& operator>>(istream& is, string& str); istream& getline(istream& is, string& str, char delim = '\n'); }

string.cpp

#define _CRT_SECURE_NO_WARNINGS 1 #include"string.h" namespace yjc // 定义多个命名空间,名字相同的会默认合并 { const size_t string::npos = -1; // 走声明和定义分离 void string::reserve(size_t n) { if (n > _capacity) { char* tmp = new char[n + 1]; // 多开一个空间给\0 strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } void string::push_back(char ch) { if (_size == _capacity) { reserve(_capacity == 0? 4: 2 * _capacity); // 使用三目表达式,因为有可能空间是0 } _str[_size] = ch; _size++; } void string::append(const char* str) { size_t len = strlen(str); //size_t newCapacity = _capacity * 2; if (_capacity < _size + len) reserve(_size + len); strcpy(_str + _size, str); _size += len; } string& string::operator+=(char ch) { push_back(ch); return *this; } string& string::operator+=(const char* str) { append(str); return *this; } void string::insert(size_t pos, char ch) { if (_size == _capacity) { reserve(_capacity == 0 ? 4 : 2 * _capacity); // 使用三目表达式,因为有可能空间是0 } // 方法一 //int end = _size; //while (end >= (int)pos) // 注意这里存在整形提升,会导致程序崩溃,所以必须强转int //{ // /*if (end == 0) // { // int i = 0; // }*/ // 手动写一个条件断点,方便调试 // _str[end + 1] = _str[end]; // end--; //} // 方法二 size_t end = _size + 1; while (end > _size) { _str[end] = _str[end - 1]; end--; } _str[pos] = ch; _size++; } void string::insert(size_t pos, const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { size_t newCapacity = 2 * _capacity; if (_size + len > newCapacity) { newCapacity = _size + len; } reserve(newCapacity); } //int end = _size; //while (end >= (int)pos) // 防止整型提升 //{ // _str[end + len] = _str[end]; // --end; //} size_t end = _size + len; while (end > pos +len -1) { _str[end] = _str[end - len]; end--; } for (int i = 0; i < len; i++) { _str[pos + i] = str[i]; } _size += len; } void string::erase(size_t pos, size_t len) { assert(pos < _size); if (len >= _size - pos) { _str[pos] = '\0'; _size = pos; } else { size_t end = pos + len; while (end <= _size) { _str[end - len] = _str[end]; ++end; } _size -= len; } } size_t string::find(char ch, size_t pos) { assert(pos < _size); for (int i = pos; i < _size; i++) { if (_str[i] == ch) return i; } return npos; } size_t string::find(const char* str, size_t pos) { assert(pos < _size); const char* ptr = strstr(_str + pos, str); // 直接调用库函数,是一个暴力匹配的思想,返回第一个匹配的位置 if (ptr == nullptr) { return npos; } else { return ptr - _str; // 返回值是串中的n个元素 } } string string::substr(size_t pos, size_t len) { assert(pos < len); if (len > _size - pos) { len = _size - pos; } yjc::string sub; sub.reserve(len); for (size_t i = 0; i < len; i++) { sub += _str[pos + i]; } return sub; // 这边必须传值返回,调用拷贝构造 } //string::string() // :_str(new char[1] {'\0'}) // 这里注意不能直接给一个空指针,否则程序会崩溃,并且要用数组初始化,为了和析构保持一致 // , _size(0) // , _capacity(0) //{} //string::string(const char* str) // :_size(strlen(str))// 先开空间,再初始化,注意要+1 strlen不计算 \0 的空间 //{ // // 只让_size走初始化列表,避免多次使用strlen,并且不用管定义的顺序 // _str = new char[_size + 1]; // _capacity = _size; // strcpy(_str, str); //} string::string(const char* str)// 直接给一个全缺省的构造函数, 要指定类域 :_size(strlen(str)) { _str = new char[_size + 1]; _capacity = _size; strcpy(_str, str); } //传统写法 //string::string(const string& s) //{ // _str = new char[s._capacity + 1]; // 完成深拷贝 // strcpy(_str, s._str); // _size = s._size; // _capacity = s._capacity; //} //现代写法 string::string(const string& s) { string tmp(s._str); // 调用拷贝构造 swap(tmp); // 复用swap } //string& string::operator= (const string& s) //{ // if (this != &s) // 防止自己给自己赋值 // { // delete[] _str; // _str = new char[s._capacity + 1]; // strcpy(_str, s._str); // _size = s._size; // _capacity = s._capacity; // return *this; // 有连续赋值的情况,所以要有返回值 // } //} //现代写法 string& string::operator= (const string& s) { if (this != &s) { string tmp(s._str); swap(tmp); } return *this; } string::~string() { delete[] _str; _str = nullptr; _size = 0; _capacity = 0; } void string::swap(string& s) { std::swap(_str, s._str); // 直接调用算法库的swap使其改变指针指向就行 std::swap(_size, s._size); std::swap(_capacity, s._capacity); } void swap(string& s1, string& s2) { s1.swap(s2); // 又实现一个全局swap为了实现和算法库的统一,这里的swap相当于是对string的swap的一个封装 // 一共有三个swap,一个算法库的,一个string的,还有一个对string的封装的 } bool operator== (const string& lhs, const string& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) == 0; } bool operator!= (const string& lhs, const string& rhs) { return !(lhs == rhs); } bool operator> (const string& lhs, const string& rhs) { return !(lhs <= rhs); } bool operator< (const string& lhs, const string& rhs) { return strcmp(lhs.c_str(), rhs.c_str()) < 0; } bool operator>= (const string& lhs, const string& rhs) { return !(lhs < rhs); } bool operator<= (const string& lhs, const string& rhs) { return (lhs < rhs || lhs == rhs); } ostream& operator<<(ostream& os, const string& str) { for (int i = 0; i < str.size(); i++) { os << str[i]; } return os; } istream& operator>>(istream& is, string& str) { str.clear(); //方法一 //char ch; is >> ch; // 流提取操作符的默认行为是忽略空格和换行 //ch = is.get(); // get函数会读空格和换行 //方法二 int i = 0; char buff[256]; // 在栈上开空间 char ch = is.get(); while (ch != ' ' && ch != '\n') { //str += ch; buff[i++] += ch; if (i == 255) { buff[i] = '\0'; str += buff; // 一次扩容 i = 0; } ch = is.get(); } if (i > 0) { buff[i] = '\0'; str += buff; } return is; } istream& getline(istream& is, string& str, char delim) { str.clear(); int i = 0; char buff[256]; char ch = is.get(); while (ch != delim) { buff[i++] += ch; if (i == 255) { buff[i] = '\0'; str += buff; // 一次扩容 i = 0; } ch = is.get(); } if (i > 0) { buff[i] = '\0'; str += buff; } return is; } }

test.cpp

#define _CRT_SECURE_NO_WARNINGS 1 #include"string.h" // 构造 遍历 void Test1() { //yjc::string s1 = "hello world"; // 要加上命名空间,不然会默认先去库里面找 //cout << s1.c_str() << endl; //s1[0] = 'x'; //for (int i = 0; i < s1.size(); i++) //{ // cout << s1[i]; //} yjc::string s2 = "hello world"; cout << s2.c_str() << endl; yjc::string::iterator it = s2.begin(); //while (it != s2.end()) //{ // cout << *it; // it++; //} while (it != s2.end()) { (*it)--; cout << *it; it++; } cout << endl; for (auto& ch : s2) // 注意这边auto只能识别char,想用引用要自己加, 引用可以减少拷贝 { ch++; } for (auto ch : s2) // 实现了迭代器 就能支持范围for,并且要咱找stl的命名规则命名迭代器 { cout << ch; } cout << endl; const yjc::string s3 = "xxxxxxxx"; for (auto& ch : s3) { // ch++; cout << ch; } } // 插入 void Test2() { yjc::string s1 = "hello world"; cout << s1.c_str() << endl; s1 += 'x'; s1 += "6666"; cout << s1.c_str() << endl; yjc::string s2 = "hello world"; s2.insert(0, 'x'); cout << s2.c_str() << endl; s2.insert(0, "yjcyjcyjcyjc"); cout << s2.c_str() << endl; } void Test3() { yjc::string s1 = "hello world"; s1.erase(6, 2); cout << s1.c_str() << endl; } void Test4() { yjc::string s1 = "hello world"; cout << s1.find(' ') << endl; cout << s1.find("wor") << endl; } void Test5() { yjc::string url = " zhrz.nuc.edu /cas/login?service=https%3A%2F%2Fzhmh.nuc.edu %2Fpersonal-center"; size_t pos1 = url.find(':'); size_t pos2 = url.find('/', pos1 + 3); if (pos1 != string::npos && pos2 != string::npos) { yjc::string domain = url.substr(pos1 + 3, pos2 - pos1 - 3); // 获取域名 cout << domain.c_str() << endl; } } void Test6() { yjc::string s1; //cin >> s1; //cout << s1; getline(cin, s1, '#'); cout << s1; } int main() { Test6(); return 0; }
标签:

string的模拟实现由讯客互联电脑硬件栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“string的模拟实现