1. 字符串是表示字符序列的类
2. 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作单字节字符字符串的设计特性。
3. string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信息,请参阅basic_string)。
4. string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。
5. 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作
总结:
1. string是表示字符串的字符串类
2. 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
3. string在底层实际是:basic_string模板类的别名,typedef basic_stringstring;
4. 不能操作多字节或者变长字符的序列。
在使用string类时,必须包含#include头文件以及using namespace std;
| 函数名称 | 功能说明 |
| string() | 构造空的string类对象,即空字符串 |
| string(const char* s) | 用C-string来构造string类对象 |
| string(size_t n, char c) | string类对象中包含n个字符c |
| string(const string&s) | 拷贝构造函数 |
- void Teststring()
- {
- string s1; // 构造空的string类对象s1
- string s2("hello bit"); // 用C格式字符串构造string类对象s2
- string s3(s2); // 拷贝构造s3
- }
| 函数名称 | 功能说明 |
| size | 返回字符串有效字符长度 |
| length | 返回字符串有效字符长度 |
| capacity | 返回空间总大小 |
| empty | 检测字符串释放为空串,是返回true,否则返回false |
| clear | 清空有效字符 |
| reserve | 为字符串预留空间** |
| resize | 将有效字符的个数该成n个,多出的空间用字符c填充 |
代码演示
- #define _CRT_SECURE_NO_WARNINGS
-
- #include
- using namespace std;
-
- #include
-
-
- // 测试string容量相关的接口
- // size/clear/resize
- void Teststring1()
- {
- // 注意:string类对象支持直接用cin和cout进行输入和输出
- string s("hello!!!");
- cout << s.size() << endl;
- cout << s.length() << endl;
- cout << s.capacity() << endl;
- cout << s << endl;
-
- // 将s中的字符串清空,注意清空时只是将size清0,不改变底层空间的大小
- s.clear();
- cout << s.size() << endl;
- cout << s.capacity() << endl;
-
- // 将s中有效字符个数增加到10个,多出位置用'a'进行填充
- // “aaaaaaaaaa”
- s.resize(10, 'a');
- cout << s.size() << endl;
- cout << s.capacity() << endl;
-
- // 将s中有效字符个数增加到15个,多出位置用缺省值'\0'进行填充
- // "aaaaaaaaaa\0\0\0\0\0"
- // 注意此时s中有效字符个数已经增加到15个
- s.resize(15);
- cout << s.size() << endl;
- cout << s.capacity() << endl;
- cout << s << endl;
-
- // 将s中有效字符个数缩小到5个
- s.resize(5);
- cout << s.size() << endl;
- cout << s.capacity() << endl;
- cout << s << endl;
- }
-
- //====================================================================================
- void Teststring2()
- {
- string s;
- // 测试reserve是否会改变string中有效元素个数
- s.reserve(100);
- cout << s.size() << endl;
- cout << s.capacity() << endl;
-
- // 测试reserve参数小于string的底层空间大小时,是否会将空间缩小
- s.reserve(50);
- cout << s.size() << endl;
- cout << s.capacity() << endl;
- }
-
- // 利用reserve提高插入数据的效率,避免增容带来的开销
- //====================================================================================
- void TestPushBack()
- {
- string s;
- size_t sz = s.capacity();
- cout << "making s grow:\n";
- for (int i = 0; i < 100; ++i)
- {
- s.push_back('c');
- if (sz != s.capacity())
- {
- sz = s.capacity();
- cout << "capacity changed: " << sz << '\n';
- }
- }
- }
-
- // 构建vector时,如果提前已经知道string中大概要放多少个元素,可以提前将string中空间设置好
- void TestPushBackReserve()
- {
- string s;
- s.reserve(100);
- size_t sz = s.capacity();
-
- cout << "making s grow:\n";
- for (int i = 0; i < 100; ++i)
- {
- s.push_back('c');
- if (sz != s.capacity())
- {
- sz = s.capacity();
- cout << "capacity changed: " << sz << '\n';
- }
- }
- }
-
-
-
-
- //
- // 测试string:
- // 1. 插入(拼接)方式:push_back append operator+=
- // 2. 正向和反向查找:find() + rfind()
- // 3. 截取子串:substr()
- // 4. 删除:erase
- void Teststring5()
- {
- string str;
- str.push_back(' '); // 在str后插入空格
- str.append("hello"); // 在str后追加一个字符"hello"
- str += 'b'; // 在str后追加一个字符'b'
- str += "it"; // 在str后追加一个字符串"it"
- cout << str << endl;
- cout << str.c_str() << endl; // 以C语言的方式打印字符串
-
- // 获取file的后缀
- string file("string.cpp");
- size_t pos = file.rfind('.');
- string suffix(file.substr(pos, file.size() - pos));
- cout << suffix << endl;
-
- // npos是string里面的一个静态成员变量
- // static const size_t npos = -1;
-
- // 取出url中的域名
- string url("http://www.cplusplus.com/reference/string/string/find/");
- cout << url << endl;
- size_t start = url.find("://");
- if (start == string::npos)
- {
- cout << "invalid url" << endl;
- return;
- }
- start += 3;
- size_t finish = url.find('/', start);
- string address = url.substr(start, finish - start);
- cout << address << endl;
-
- // 删除url的协议前缀
- pos = url.find("://");
- url.erase(0, pos + 3);
- cout << url << endl;
- }
-
- int main()
- {
- return 0;
- }
注意:
1. size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一致,一般情况下基本都是用size()。
2. clear()只是将string中有效字符清空,不改变底层空间大小。
3. resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
4. reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于string的底层空间总大小时,reserver不会改变容量大小
| 函数名称 | 功能说明 |
| operator[] | 返回pos位置的字符,const string类对象调用 |
| begin+ end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器 |
| rbegin + rend | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭 代器 |
| 范围for | C++11支持更简洁的范围for的新遍历方式 |
- / string的遍历
- // begin()+end() for+[] 范围for
- // 注意:string遍历时使用最多的还是for+下标 或者 范围for(C++11后才支持)
- // begin()+end()大多数使用在需要使用STL提供的算法操作string时,比如:采用reverse逆置string
- void Teststring3()
- {
- string s1("hello ");
- const string s2("Hello ");
- cout << s1 << " " << s2 << endl;
- cout << s1[0] << " " << s2[0] << endl;
-
- s1[0] = 'H';
- cout << s1 << endl;
-
- // s2[0] = 'h'; 代码编译失败,因为const类型对象不能修改
- }
-
- void Teststring4()
- {
- string s("hello ");
- // 3种遍历方式:
- // 需要注意的以下三种方式除了遍历string对象,还可以遍历是修改string中的字符,
- // 另外以下三种方式对于string而言,第一种使用最多
- // 1. for+operator[]
- for (size_t i = 0; i < s.size(); ++i)
- cout << s[i] << endl;
-
- // 2.迭代器
- string::iterator it = s.begin();
- while (it != s.end())
- {
- cout << *it << endl;
- ++it;
- }
-
- // string::reverse_iterator rit = s.rbegin();
- // C++11之后,直接使用auto定义迭代器,让编译器推到迭代器的类型
- auto rit = s.rbegin();
- while (rit != s.rend())
- cout << *rit << endl;
-
- // 3.范围for
- for (auto ch : s)
- cout << ch << endl;
- }
| 函数名称 | 功能说明 |
| push_back | 在字符串后尾插字符c |
| append | 在字符串后追加一个字符串 |
| operator+= (重点) | 在字符串后追加字符串str |
| c_str(重点) | 返回C格式字符串 |
| find + npos(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 |
| rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 |
| substr | 在str中从pos位置开始,截取n个字符,然后将其返回 |
注意:
1. 在string尾部追加字符时,s.push_back(c) / s.append(1, c) / s += 'c'三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
2. 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
| 函数 | 功能说明 |
| operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
| operator>> | 输入运算符重载 |
| operator<< | 输出运算符重载 |
| getline | 获取一行字符串 |
| relational operators | 大小比较 |
为了防止string类和库函数重名,我们把我们的代码写在命名空间里。
- #pragma once
- #define _CRT_SECURE_NO_WARNINGS
- #include
- using namespace std;
- #include
- #include
- namespace LYL
- {
- class string
- {
- public:
- //迭代器
- typedef char* iterator;
- //const 修饰的迭代器
- typedef const char* const_iterator;
- iterator begin()
- {
- return _str;
- }
- iterator end()
- {
- return _str + _size;
- }
- const_iterator begin() const
- {
- return _str;
- }
- const_iterator end() const
- {
- return _str + _size;
- }
- //构造函数
- string(const char* str = "") :
- _size(strlen(str))
- {
- _capacity = _size == 0 ? 3 : _size;
- _str = new char[_capacity + 1];
- strcpy(_str, str);
- }
- //拷贝构造函数
-
- string(const string& s)
- :_size(s._size),
- _capacity(s._capacity)
- {
- _str = new char[s._capacity + 1];
- strcpy(_str, s._str);
- }
- //运算符重载
- //=运算符重载
- 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;
- }
- //[]运算符重载
- char& operator[](size_t pos) const
- {
- assert(pos < _size);
- return _str[pos];
- }
- char& operator[](size_t pos)
- {
- assert(pos < _size);
- return _str[pos];
- }
-
- //析构函数
- ~string()
- {
- _capacity = 0;
- _size = 0;
- delete[] _str;
- _str = nullptr;
- }
-
- // 不修改成员变量数据的函数,最好都加上const
-
- //函数c_str的实现
- const char* c_str()
- {
- return _str;
- }
-
- //size()函数实现
- size_t size() const
- {
- return _size;
- }
-
- //capacity()函数实现
- size_t capacity() const
- {
- return _capacity;
- }
- bool operator>(const string& s) const
- {
- return strcmp(s._str, this->_str) > 0;
- }
- bool operator==(const string& s)
- {
- return strcmp(s._str, _str) == 0;
- }
- bool operator>=(const string& s)
- {
- return _str > s._str || _str == s._str;
- //return *this > s || *s == this; 这里如果没有用const修饰函数,*this和s的位置就不可以改变,改变了就是权限放大。
- }
- bool operator<(const string& s)
- {
- return !(*this >= s);
- }
- bool operator<=(const string& s)
- {
- return !(*this > s);
- }
- bool operator!=(const string& s)
- {
- return !(*this == s);
- }
-
- //reserve函数实现(开辟空间)
- void reserve(size_t n)
- {
- if (n > _capacity)
- {
- //扩容
- char* tmp = new char[n + 1];
- strcpy(tmp, _str);
- delete[] _str;
- _str = tmp;
- _capacity = n;
- }
- }
-
- //resize函数实现(开除的空间并初始化)
- void resize(size_t n, char ch = '\0')
- {
- if (_size >= n)
- {
- //删除数据----保留前n个数据
- _size = n;
- _str[_size] = '\0';
- }
- else
- {
- if (_capacity < n)
- {
- //空间不够先扩容
- reserve(n);
- }
-
- size_t i = _size;
- while (i < n)
- {
- _str[i] = ch;
- i++;
- }
- _size = n;
- _str[_size] = '\0';
- }
- }
-
- //push_back函数实现
- //在字符串后添加一个字符
- void push_back(char ch)
- {
- if (_size + 1 > _capacity)
- {
- reserve(_capacity * 2);
- }
- _str[_size] = ch;
- _str[_size++] = '\0';
- }
-
- //qppend函数实现
- //在字符串后添加一个字符串
- void append(const char* str)
- {
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_capacity + len);
- }
-
- strcpy(_str + _size, str);
- _size += len;
- }
- string& operator+=(char ch)
- {
- push_back(ch);
- return *this;
- }
-
- string& operator+=(const char* str)
- {
- append(str);
- return *this;
- }
-
- //insert函数实现
- //函数重载,一个插入字符,一个插入字符串
- string& insert(size_t pos, char ch)
- {
- assert(pos <= _size);
- if (_size + 1 > _capacity)
- {
- reserve(2 * _capacity);
- }
- size_t end = _size + 1;
- while (end > pos)
- {
- _str[end] = _str[end - 1];
- end--;
- }
- _str[pos] = ch;
- _size += 1;
- return *this;
- }
- string& insert(size_t pos, const char* str)
- {
- assert(pos <= _size);
- size_t len = strlen(str);
- if (_size + len > _capacity)
- {
- reserve(_size + len);
- }
- //挪动数据
- size_t end = _size + len;
- while (end > pos + len - 1)
- {
- _str[end - pos] = _str[end];
- end--;
- }
- //拷贝数据
- strncpy(_str + pos, str, len);
- _size += len;
- return *this;
- }
- //erase函数实现
- 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);
- _size -= len;
- }
- return *this;
- }
-
- //swap函数实现
- void swap(string& s)
- {
- std::swap(_str, s._str);
- std::swap(_size, s._size);
- std::swap(_capacity, s._capacity);
- }
- //find 函数实现
- //默认从0开始找
- 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;
- }
- }
- return npos;
- }
- //函数重载找子串
- size_t find(const char* str, size_t pos = 0)
- {
- assert(_size > pos);
- //复用strstr
- char* p = strstr(_str + pos, str);
- if (p == nullptr)
- {
- return npos;
- }
- else
- {
- return p - _str;//指针减去指针为两个指针间的距离,也就是下标
- }
- }
-
- void clear()
- {
- _str[0] = '\0';
- _size = 0;
- }
-
- private:
- char* _str;
- size_t _size;
- size_t _capacity;
-
- static const size_t npos;
- //static const size_t nops=-1;
- //static const double dpos = 1.1; //不可以
- };
-
-
- const size_t string::npos = -1; //size_t为无符号整型,这里等于-1相当于等于最大整数
-
- //流提取 <<
- std::ostream& operator<<(std::ostream& out, const string& s)
- {
- for (auto ch : s)
- {
- out << ch;
- }
- return out;
- }
-
- //流插入 >>
- std::istream& operator>>(std::istream& in, string& s)
- {
- s.clear();
- char ch = in.get();
- char buff[128];
- size_t i = 0;
- while (ch != ' ' && ch != '\n')
- {
- buff[i++] = ch;
- if (i == 127)
- {
- buff[127] = '\0';
- s += buff;
- i = 0;
- }
- ch = in.get();
- }
- if (i != 0)
- {
- buff[i] = '\0';
- s += buff;
- }
- return in;
- }
当我们学完string类时就可以使用库函数,这种题就相对
- class Solution {
- public:
- string addStrings(string num1, string num2)
- {
- int carry=0;//进位
- int end1=num1.size()-1;
- int end2=num2.size()-1;
- string s;
-
- while(end1>=0||end2>=0)
- {
- int val1=0;
- if(end1>=0)
- {
- val1=num1[end1]-'0';
- }
- int val2=0;
- if(end2>=0)
- {
- val2=num2[end2]-'0';
- }
- int sum=val1+val2+carry;
- if(sum>9)
- {
- sum-=10;
- carry=1;
- }
- else
- {
- carry=0;
- }
- s.insert(0,1,sum+'0');
- end1--;
- end2--;
- }
- if(carry==1)
- {
- s.insert(0,1,'1');
- }
- return s;
- }
-
- };
-