string类对象的修改操作
函数名 | 功能 |
push_back | 在字符串末尾插入字符c |
append | 在字符串后追加一个字符串 |
operator+= | 在字符串后追加字符串 |
c_str | 返回C字符串 |
find+npos | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
substr | 在字符串pos位置开始,截取n个字符,然后将其返回 |
在上面学习扩容原理以及介绍push_back这里不加赘述
append
功能简单来说就是在字符串后面追加字符或者字符串
实现如下
void test() { string s1("hello crush"); string s2("!!!"); //在字符串s1后面追加字符串s2 s1.append(s2); cout << s1 << endl; }
其实对于 append函数的使用很少,一般使用 operator+=,两者在功能上相似,并且后者相对简单且容易理解
替换上面的代码
void test() { string s1("hello crush"); string s2("!!!"); //在字符串s1后面追加字符串s2 s1 += s2; cout << s1 << endl; }
区分assign和replace
assign的功能是先将原有的字符串清空在进行替换;replace的功能是在原有字符串的基础上在某个位置计算一定的长度进行替换
实例如下
void test() { string s1("hello world hello world"); string s2("hello world hello world"); s1.assign("hello crush", 5); cout << s1 << endl; s2.replace(6, 5, "crush"); cout << s2 << endl; }
find
功能简单来说就是,默认从第一个位置开始向后找某个字符,找到之后返回该字符所在的位置;若没有找到,则返回npos
示例如下
void test() { string s("hello crush hello crush"); cout << s << endl; //将' '替换成20% size_t pos = s.find(' '); while (pos != string::npos) { s.replace(pos, 1, "20%"); pos = s.find(' ',pos+3); } cout << s << endl; }
c_str
功能:将字符串转换成C格式字符串并返回
读取文件
void test() { string file("test.cpp"); //将string格式的字符串转换成C格式的字符串,以便进行读取 FILE* fout = fopen(file.c_str(), "r"); assert(fout); char ch = fgetc(fout); while (ch != EOF) { cout << ch; ch = fgetc(fout); } fclose(fout); }
string类非成员函数
函数名 | 功能 |
operator+ | |
operator>> | 输入运算符重载 |
operator<< | 输出运算符重载 |
getline | 获取一行字符串 |
relational operators | 大小比较 |
string类的模拟实现
传统写法
namespace myj { class string { friend ostream& operator<<(ostream& out,string& s); friend istream& operator>>(istream& in, string& s); public: typedef char* iterator;//迭代器 iterator begin() { return _str; } iterator end() { return _str + _size; } //构造函数 string(const char* str = "") { _size = strlen(str); _capacity = _size; _str = new char[_capacity + 1]; strcpy(_str, str); } //s2(s1) 拷贝构造 string(const string& s) { _str = new char[s._capacity + 1]; _capacity = s._capacity; _size = s._size; strcpy(_str, s._str); } //s1=s3 赋值重载 string& operator=(const string& s) { if (this != &s) { char* tmp = new char[s._capacity + 1]; strcpy(tmp, s._str); delete[] _str; _str = tmp; _size = s._size; _capacity = s._capacity; } return *this; } //析构函数 ~string() { delete[] _str; _str = nullptr; _size = _capacity = 0; } //转换成C格式字符串,便于自定义类型的输出 const char* c_str() { return _str; } //string的长度 size_t size() { return _size; } //string的容量 size_t capacity() { return _capacity; } //重载[] char& operator[](size_t pos) { assert(pos < _size); return _str[pos]; } //预留空间 void reserve(size_t n) { if (n > _capacity) { //深拷贝 char* tmp = new char[n + 1]; strcpy(tmp, _str); delete[] _str; _str = tmp; _capacity = n; } } //调整大小,三种可能 void resize(size_t n, char ch = '\0') { if (n > _size) { //如果n>_capacity,将会进行扩容 reserve(n); for (size_t i = _size; i < n; i++) { _str[i] = ch; } _size = n; _str[_size] = '\0'; } else { _str[n] = '\0'; _size = n; } } //尾插 void push_back(char ch) { if (_size == _capacity) { size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newcapacity); } _str[_size] = ch; _size++; _str[_size] = '\0'; } //追加字符串 void append(const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } strcpy(_str + _size, str); _size += len; } //重载+= string& operator+=(const char* str) { append(str); return *this; } //字符插入 string& insert(size_t pos, char ch) { assert(pos <= _size); if (_size == _capacity) { size_t newcapacity = _capacity == 0 ? 4 : _capacity * 2; reserve(newcapacity); } size_t end = _size + 1; while (end > pos) { _str[end] = _str[end - 1]; end--; } _str[pos] = ch; _size++; return *this; } //字符串插入 string& insert(size_t pos, const char* str) { size_t len = strlen(str); if (_size + len > _capacity) { reserve(_size + len); } size_t end = _size + len; while (end > pos + len - 1) { _str[end] = _str[end - len]; end--; } strncpy(_str + pos, str, len); _size += len; return *this; } //消除字符 string& erase(size_t pos, size_t len = npos) { assert(pos < _size); if (len == npos || pos + len >= _size) { _str[pos] = '\0'; _size = pos; } else { strcpy(_str + pos, _str + pos + len); } return *this; } //查找字符 size_t find(char ch, size_t pos = 0) { assert(pos < _size); while (pos < _size) { if (_str[pos] = ch) { return pos; } pos++; } return npos; } //查找字符串 size_t find(const char* str, size_t pos = 0) { assert(pos < _size); const char* ptr = strstr(_str + pos, str); if (ptr == nullptr) { return npos; } else { return ptr - _str; } } //清楚string内容 void clear() { _size = 0; _str[0] = '\0'; } private: char* _str; size_t _size; size_t _capacity; const static size_t npos = -1; }; //流提取 ostream& operator<<(ostream& out,string& s) { for (size_t i = 0; i < s.size(); i++) { out << s[i]; } return out; } //流插入 istream& operator>>(istream& in, string& s) { s.clear(); char buff[128] = { '\0' }; size_t i = 0; char ch = in.get(); while (ch != ' ' && ch != '\n') { if (i == 127) { s += buff; i = 0; } buff[i++] = ch; ch = in.get(); } if (i > 0) { buff[i] = '\0'; s += buff; } return in; } }
现代写法
主要是对拷贝构造和赋值重载进行改进,并不是为了提高效率,而是方便理解
拷贝构造
void swap(string& s) { std::swap(_str, s._str); std::swap(_size, s._size); std::swap(_capacity, s._capacity); } //s1(s2) string(const string& s) :_str(nullptr) ,_size(0) ,_capacity(0) { string tmp(s._str); swap(tmp); }
思路:
将s2进行初始化;
创建临时变量string tmp拷贝构造s1;
交换tmp和s1的内容;
区分两个函数
string成员函数 swap(s1,s2);
进行三次深拷贝,交换s1和s2整体
s1.swap(s2);
只改变s1和s2中指针指向的内容
赋值重载
这里便可以利用上面**s1.swap(s2);**的思想
//s1=s2 string& operator=(const string& s) { if (this != &s) { string tmp(s); swap(tmp); } return *this; }