
string的构造函数一大堆,用常用的去实现就可以了,蓝色的就是最常用的之一。

operator[]有两个版本,意义是不一样的,普通对象调用第一个,能读能写,const对象调用第二个,只能读。
end()指向的是有效字符的下一个位置。
范围for识别成迭代器,并且名字都不能变,iterator就是迭代器,begin()和end()名字都不能变。
整型提升是小的范围向大的范围提升。
流插入和流提取是允许拷贝的。
常规情况下,流插入和c_str()是没有差别的,有一种情况下是有差别的,c_str()是返回C型的字符串,c型字符串是怎么打印的呢,相当于打印的是一个内置类型,内置类型也就相当于打印的const char* ,const char*打印的原则是遇到“\0”就终止了,而流插入的重载,不管\0,跟\0没有关系,它用范围for或者size()的长度去走,长度是多长,实际就要打印多长。
C语言的字符数组,以\0为终止算长度,string不看\0,以size为终止算长度。
下面是string的模拟实现源代码:
string.h #include<iostream> #include<assert.h> using namespace std; namespace bit { class string { public: typedef char* iterator; typedef const char* const_iterator; //迭代器也要写两个版本,一个普通对象用,一个const对象用 iterator begin() { return _str; } iterator end() { return _str + _size; } const_iterator begin() const { return _str; } const_iterator end() const { return _str + _size; } //string 的构造函数不能用字符串直接去初始化,必须要开空间尽可能用初始化列表去初始化。 //string(const char* str) // :_str(new char[strlen(str) + 1]) // ,_size(strlen(str)) // //capacity不包含\0,一般不包含,因为capacity指的是能包含多少个有效字符,\0不是有效字符 // ,_capacity(strlen(str)) //{ // strcpy(_str, str); //} //无参默认构造 //下面这样写不行,如果这样写,_str是空指针,相当于c_str对空指针解引用,程序就会崩溃 //string() // :_str(nullptr) // ,_size(0) // ,_capacity(0) //{} //这样写才是对的 //string() // :_str(new char[1]) // , _size(0) // , _capacity(0) //{ // _str[0] = '\0'; //} //下面是无参和有参初始化合并后的 //string(const char* str = '\0')1. //string(const char* str = nullptr)2. //1和2都是错的 //string(const char* str = "\0")可以这样写,但是没必要,这个地方有两个\0 //下面是最优写法 string(const char* str = "")//虽然为空,但是有标识字符\0 :_str(new char[strlen(str) + 1]) ,_size(strlen(str)) //capacity不包含\0,一般不包含,因为capacity指的是能包含多少个有效字符,\0不是有效字符 ,_capacity(strlen(str)) { memcpy(_str, str, _size + 1); } //拷贝构造的传统写法 //string(const string& s) //{ // _str = new char[s._capacity + 1]; // memcpy(_str, s._str, s._size + 1); // _size = s._size; // _capacity = s._capacity; //} //拷贝构造的现代写法 string(const string& s) :_str(nullptr) ,_size(0) ,_capacity(0) { string tmp(s._str); swap(tmp); } //下面两个函数建议加const const char* c_str()const { return _str; } //遍历string size_t size()const { return _size; } //operator[]有两个版本,意义是不一样的,普通对象调用第一个,能读能写,const对象调用第二个,只能读。 char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } const char& operator[](size_t pos)const { assert(pos < _size); return _str[pos]; } //增删查改 //这里的扩容逻辑用reserve就可以 void reserve(size_t n) { cout << "reserve->" << n << endl; if (n > _capacity) { char* tmp = new char[n + 1]; //strcpy(tmp, _str); memcpy(tmp, _str, _size + 1); delete[] _str; _str = tmp; _capacity = n; } } void push_back(char ch) { if (_size == _capacity) { //二倍扩容 reserve(_capacity == 0 ? 4 : _capacity * 2); } _str[_size++] = ch; _str[_size] = '\0'; } void append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { //至少扩容到_size + len reserve(_size + len); } //strcpy(_str + _size, str); memcpy(_str + _size, str, len + 1); _size += len; } string& operator+=(const char str) { push_back(str); return *this; } string& operator+=(const char* str) { append(str); return *this; } void insert(size_t pos, size_t n, char ch) { assert(pos <= _size); if (_size + n > _capacity) { //至少扩容到_size + len reserve(_size + n); } //挪动数据 size_t end = _size; while (end >= pos && end != npos) { _str[end + n] = _str[end]; end--; } for (size_t i = 0; i < n; i++) { _str[pos + i] = ch; } _size += n; } void insert(size_t pos, const char* str) { assert(pos <= _size); size_t len = strlen(str); if (_size + len > _capacity) { //至少扩容到_size + len reserve(_size + len); } //挪动数据 size_t end = _size; while (end >= pos && end != npos) { _str[end + len] = _str[end]; end--; } for (size_t i = 0; i < len; i++) { _str[pos + i] = str[i]; } _size += len; } ~string() { if(_str) { delete[] _str; _str = nullptr; _size = _capacity = 0; } } void erase(size_t pos, size_t len = npos) { assert(pos <= _size); if (len == npos || len + pos >= _size) { _str[pos] = '\0'; _size = pos; _str[_size] = '\0'; } else { size_t end = pos + len; while (pos <= _size) { _str[pos++] = _str[end++]; } _size -= len; } } size_t find(char ch, size_t pos = 0) { assert(pos < _size); for (size_t i = pos; i < _size; i++) { if (_str[i] == ch) { return i; } } //没有找到的话,返回的都是npos return npos; } size_t find(const char* str, size_t pos = 0) { assert(pos < _size); //暴力匹配 const char* ptr = strstr(_str + pos, str); if (ptr) { return ptr - _str; } else { return npos; } } string substr(size_t pos = 0, size_t len = npos) { size_t n = len; if (len == npos || len + pos > _size) { n = _size - pos; } string tmp; tmp.reserve(n); for (size_t i = pos; i < pos + n; i++) { tmp += _str[i]; } return tmp; } void resize(size_t n, char ch = '\0') { if (n < _size) { _size = n; _str[_size] = '\0'; } else { reserve(n); for (size_t i = _size; i < n; i++) { _str[i] = ch; } _size = n; _str[_size] = '\0'; } } void clear() { _str[0] = '\0'; _size = 0; } bool operator<(const string& s) const { //size_t i1 = 0; //size_t i2 = 0; //while (i1 < _size && i2 < _size) //{ // if (_str[i1] < s._str[i2]) // { // return true; // } // else if (_str[i1] > s._str[i2]) // { // return false; // } // else // { // i1++; // i2++; // } //} if (i1 == _size && i2 != s._size) { return true; } else { return false; } //return i1 == _size && i2 != s._size; //下面的代码也可以实现 int ret = memcmp(_str, s._str, _size < s._size ? _size : s._size); return ret == 0 ? _size < s._size : ret < 0; } bool operator==(const string& s) const { return _size == s._size && memcmp(_str, s._str, _size) == 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 !(*this == s); } ///传统写法 //string& operator=(const string& s) //{ // if (this == &s) // { // char* tmp = new char[s._capacity + 1]; // memcpy(tmp, s._str, s._size + 1); // delete[] _str; // _str = tmp; // _size = s._size; // _capacity = s._capacity; // } // return *this; //} //上面的代码用现代的写法 void swap(string& s) { std::swap(_str, s._str); std::swap(_size,s._size); std::swap(_capacity,s._capacity); } //string& operator=(const string& s) //{ // if (this != &s) // { // string tmp(s); // swap(tmp); // } // return *this; //} string& operator=(string tmp) { swap(tmp); return *this; } private: char* _str; size_t _size; size_t _capacity; public: static size_t npos;//静态成员变量不走初始化列表,它不属于某一个类,而是属于整个类 //下面这个可以不用定义,但本质还是缺省值 //const static size_t npos = -1; //const static的整型是可以的,double不可以 //const static double x = 1.1; const static double x; }; ostream& operator<<(ostream& out, const string& s) { //for (size_t i = 0; i < s.size(); i++) //{ // out << s[i]; //} for (auto ch : s) { cout << ch; } return out; } istream& operator>>(istream& in, string& s) { s.clear(); char ch = in.get(); //char ch; //in >> ch; //处理缓冲区前面的空格或者换行 while (ch == ' ' || ch == '\n') { ch = in.get(); } char buff[128]; int i = 0; while (ch != ' ' && ch != '\n') { buff[i++] = ch; if (i == 127) { buff[i] = '\0'; s += buff; i = 0; } //in >> ch; ch = in.get(); } if (i != 0) { buff[i] = '\0'; s += buff; } return in; } size_t string::npos = -1; const double string::x = 1.1; }; //ostream& operator<<(ostream& out, const bit::string& s) //{ // //for (size_t i = 0; i < s.size(); i++) // //{ // // out << s[i]; // //} // for (auto ch : s) // { // cout << ch; // } // return out; //}
text.cpp #include"string.h" void test_string1() { bit::string s1("hello world"); cout << s1.c_str() << endl; bit::string s2; cout << s2.c_str() << endl; for (size_t i = 0; i < s1.size(); i++) { ++s1[i]; --s1[i]; } for (size_t i = 0; i < s1.size(); i++) { cout << s1[i]; } cout << endl; const bit::string s3("hello world"); s3[0]; //iterator要指定类域,如果没有指定会去全局去找iterator这个东西 bit::string::const_iterator it = s3.begin(); while (it != s3.end()) { cout << *it; it++; } cout << endl; for (auto e : s3) { cout << e; } } void test_string2() { bit::string s1("hello world"); cout << s1.c_str() << endl; //s1.push_back(' '); //s1.push_back('#'); //s1.push_back('%'); //s1.append("hello lsw"); //s1.append("hello xsq"); //cout << s1.c_str() << endl; s1 += ' '; s1 += '#'; s1 += '%'; s1 += "hello world"; cout << s1.c_str() << endl; } void test_string3() { bit::string s1("hello world"); cout << s1.c_str() << endl; s1.insert(0, 3, '#'); cout << s1.c_str() << endl; bit::string s2("helloworld"); s2.insert(5, "%%%%%"); cout << s2.c_str() << endl; } void test_string4() { bit::string s1("hello world"); cout << s1.c_str() << endl; s1.erase(5, 3); cout << s1.c_str() << endl; s1.erase(5, 30); cout << s1.c_str() << endl; s1.erase(2); cout << s1.c_str() << endl; } void test_string5() { // 2118 bit::string url = "ftp://www.baidu.com/?tn=65081411_1_oem_dg"; size_t pos1 = url.find("://"); if (pos1 != bit::string::npos) { bit::string protocol = url.substr(0, pos1); cout << protocol.c_str() << endl; } size_t pos2 = url.find('/', pos1 + 3); if (pos2 != bit::string::npos) { bit::string domain = url.substr(pos1 + 3, pos2 - (pos1 + 3)); bit::string uri = url.substr(pos2 + 1); cout << domain.c_str() << endl; cout << uri.c_str() << endl; } } void test_string6() { bit::string s("hello world"); //s.resize(8); //cout << s.c_str() << endl; //s.resize(13, 'x'); //cout << s.c_str() << endl; //s.resize(20, 'y'); s.resize(8); cout << s << endl; s.resize(13, 'x'); cout << s << endl; s.resize(20, 'y'); cout << s << endl; bit::string ss("hello world"); ss += '\0'; ss += "!!!!!!!!"; cout << ss.c_str() << endl; cout << ss << endl; bit::string copy(ss); cout << ss << endl; cout << copy << endl; copy += "xxxxxxxxxxxxxx"; cout << copy << endl; } void test_string7() { bit::string s; cin >> s; cout << s << endl; cin >> s; cout << s << endl; } void test_string8() { //bit::string s1("bbb"); //bit::string s2("aaa"); //cout << (s1 < s2) << endl; bit::string s1("hello"); bit::string s2("hello"); cout << (s1 < s2) << endl; cout << (s1 > s2) << endl; cout << (s1 == s2) << endl << endl; bit::string s3("hello"); bit::string s4("helloxxx"); cout << (s3 < s4) << endl; cout << (s3 > s4) << endl; cout << (s3 == s4) << endl << endl; bit::string s5("helloxxx"); bit::string s6("hello"); cout << (s5 < s6) << endl; cout << (s5 > s6) << endl; cout << (s5 == s6) << endl << endl; } void test_string9() { bit::string s1("hello"); bit::string s2(s1); cout << s1 << endl; cout << s2 << endl; bit::string s3("xxxxxxxxxxxxx"); s1 = s3; cout << s1 << endl; cout << s3 << endl; } int main() { test_string9(); return 0; }