string
string为C++STL中的重要容器,是表示字符串的字符串类
其中有一些用来操作字符串的接口
不能操作多字节或者变长字符的序列
常用接口:
构造:
string(); // 构造空串
string(const char* s); // 用C-string构造string类对象
string(size_t n, char c); // string类对象中包含n个字符c
string(const string& s); // 拷贝构造
string(const string& s, size_t n); // 用s的前n个字符构造
容量:
size_t size() const; // 返回字符串有效长度
size_t length() const; // 返回字符串有效长度
size_t capacity() const; // 返回容量大小
bool empty() const; // 检测是否为空串
void clear(); // 清空有效字符
void resize(size_t n, char c); // 将有效字符改为n个,多余用c填充
void resize(size_t n); // 将有效字符改为n个,多余用0填充
void reserve(size_t res_arg = 0); // 增容
注:
- size()与length()底层实现原理相同,size()与其他容器的接口保持一致
- clear()只清空有效数据,不改变底层空间大小
- reserve()为string预留空间,不改变有效空间的大小,当reserve的参数小于底层空间大小时,不改变容量
访问:
char& operator[](size_t pos); //返回pos位置字符
const char& operator[](size_t pos) const; // const接口
修改:
void push_back(char c); // 尾插字符c
string& append(const char* s); // 追加字符串
string& operator+=(const string& str); // 追加str对象
// +=重载了追加 字符、字符串、字符串对象
const char* c_str() const; // 返回c格式字符串
size_t find(char c, size_t pos = 0); // 在字符串pos开始找c,返回该字符的下标
size_t rfind(char c, size_t pos = npos);
string substr(size_t pos = 0, size_t n = npos);// 从pos位置开始,截取n个字符,返回为新string对象
string类非成员函数:
operator+(); // 效率较低
operator>>(); // 输入运算符重载
operator<<(); // 输出运算符重载
getline(); // 获取一行字符,以'\n'作为结束
深浅拷贝:
浅拷贝(值拷贝):只拷贝数值,不拷贝资源
深拷贝:拷贝数据,拷贝资源浅拷贝带来的问题:二次释放
手写一个string类:
// 传统写法
#include <iostream>
#include <string.h>
class String
{
public:
String(const char* str = "")
:_size(0)
{
if (str == nullptr)
{
_str = "";
return;
}
_size = strlen(str);
_str = new char[_size + 1];
strcpy(_str, str);
}
String(const String& s)
{
_str = new char[s.Size() + 1];
strcpy(_str, s._str);
_size = s.Size();
}
~String()
{
if (_str != nullptr)
{
delete[] _str;
_str = nullptr;
_size = -1;
}
}
String& operator=(String& s)
{
if (this != &s)
{
char* pstr = new char[s.Size() + 1];
strcpy(pstr, s._str);
delete[] _str;
_str = pstr;
_size = s.Size();
}
return *this;
}
const int Size() const
{
return _size;
}
public:
// 可不写,为了验证深拷贝的正确性
friend std::ostream& operator<<(std::ostream& _cout, const String& s);
friend std::istream& operator>>(std::istream& _cin, String& s);
private:
char* _str;
int _size;
};
std::ostream& operator<<(std::ostream& _cout, const String& s)
{
_cout << s._str << std::endl;
return _cout;
}
std::istream& operator>>(std::istream& _cin, String& s)
{
_cin >> s._str;
return _cin;
}
// 现代写法
class String {
public:
String(char* str = "") :_str(nullptr) {
if (_str == nullptr)
{
_str = "";
}
_str = new char[strlen(str) + 1];
strcpy(_str, str);
}
String(const String& s) :_str(nullptr) {
String tmp(s._str);
std::swap(_str, tmp._str);
}
~String() {
if (_str != nullptr)
{
delete[] _str;
_str = nullptr;
}
}
String& operator=(String s) {
std::swap(_str, s._str);
return *this;
}
private:
friend std::ostream& operator<<(std::ostream& _cout, const String& s);
friend std::istream& operator>>(std::istream& _cin, String& s);
private:
char* _str;
};
std::ostream& operator<<(std::ostream& _cout, const String& s)
{
_cout << s._str << std::endl;
return _cout;
}
std::istream& operator>>(std::istream& _cin, String& s)
{
_cin >> s._str;
return _cin;
}
string类的模拟实现:
// 直接贴代码了,可以找具体的接口看实现
// 没有讲的必要,会用就行
#include <string.h>
#include <assert.h>
#include <string>
#include <iostream>
class String {
public:
typedef char* Iterator;
public:
// 构造
String(const char* str = "")
{
// 构造string类对象时,如果传递nullptr指针,认为程序非法,此处断言下
if (nullptr == str)
{
assert(false);
return;
}
_size = strlen(str);
if (_size == 0)
_capacity = 1;
else
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
String(const String& s)
: _str(new char[s._capacity])
, _capacity(s._capacity)
, _size(s._size)
{
strcpy(_str, s._str);
}
~String() {
if (_str != nullptr)
{
// delete[] _str;
_str = nullptr;
_size = 0;
}
}
String& operator= (String s) {
if (this != &s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
return *this;
}
// 迭代器 Iterator
Iterator begin() {
return _str;
}
Iterator end() {
return _str + _size;
}
const Iterator begin() const {
return _str;
}
const Iterator end() const {
return _str + _size;
}
// modify
void push_back(char c) {
if (_size == _capacity)
{
reserve(_capacity * 2);
}
_str[_size] = c;
_str[++_size] = '\0';
}
void append(char c, size_t n) {
for (size_t i = 0; i < n; ++i)
{
push_back(c);
}
}
String& operator+=(char c) {
push_back(c);
return *this;
}
void append(const char* str) {
for (size_t i = 0; i < strlen(str); ++i)
{
push_back(*(str + i));
}
push_back('\0');
}
String& operator+= (const char* str) {
append(str);
return *this;
}
String& operator+= (const String& s) {
append(s._str);
return *this;
}
// 增容
void reserve(size_t new_capacity) {
if (new_capacity > _capacity)
{
char* new_str = new char[new_capacity + 1];
strcpy(new_str, _str);
delete[] _str;
_str = new_str;
_capacity = new_capacity;
}
}
// capacity
int size() const {
return _size;
}
size_t capacity() const {
return _capacity;
}
bool empty() const {
return _size == 0 ? true : false;
}
void Resize(size_t newSize, char c = char()) {
if (newSize > _size)
{
if (newSize > _capacity)
{
reserve(newSize);
}
memset(_str + _size, c, newSize - _size);
}
_size = newSize;
_str[newSize] = '\0';
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
const char* c_str() const
{
return _str;
}
void Swap(String& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
// access
char& operator[] (size_t index) {
return _str[index];
}
const char& operator[] (size_t index) const {
return _str[index];
}
bool operator<(const String& s) {
int i = 0;
for (auto& e : s)
{
if (_str[i] < e)
{
return true;
}
else if (_str[i] > e)
{
return false;
}
++i;
}
return false;
}
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);
}
bool operator==(const String& s) {
int i = 0;
for (auto& e : s)
{
if (_str[i] != e)
{
return false;
}
}
return true;
}
bool operator!=(const String& s) {
return !(*this == s);
}
size_t find(char c, size_t pos = 0) const {
for (size_t i = pos; i < _size; ++i)
{
if (_str[i] == c)
{
return i;
}
}
return nops;
}
String substr(size_t pos, size_t n) {
String tmp;
for (size_t i = 0; i < n; ++i)
{
tmp.push_back(_str[pos + i]);
}
tmp[pos + n] = '\0';
return tmp;
}
String& insert(size_t pos, char c) {
//pos的位置需要有效
if (_size == _capacity)
{
reserve(_capacity * 2);
}
for (size_t i = _size; i > pos; --i)
{
_str[i] = _str[i - 1];
}
++_size;
_str[pos] = c;
// 需要将最后一个元素设置为'\0',否则会越界
_str[_size] = '\0';
return *this;
}
String& insert(size_t pos, const char* str) {
size_t len = strlen(str);
if ((len + _size) >= _capacity)
{
reserve((_capacity + len) * 2);
}
for (size_t i = pos; i < pos + len; ++i)
{
_str[i + len] = _str[i];
}
for (size_t i = pos; i < pos + len; ++i)
{
_str[i] = str[i - pos];
}
_size += len;
return *this;
}
String& erase(size_t pos, size_t len) {
for (size_t i = pos; i < pos + len; ++i)
{
_str[i] = _str[i + len];
}
_size -= len;
return *this;
}
private:
friend std::ostream& operator<< (std::ostream& _cout, const String& s);
friend std::istream& operator>> (std::istream& _cin, String& s);
private:
char* _str;
size_t _size;
size_t _capacity;
static int nops;
};
int String::nops = -1;
std::ostream& operator<< (std::ostream& _cout, const String& s) {
_cout << s._str << std::endl;
return _cout;
}
std::istream& operator>> (std::istream& _cin, String& s) {
_cin >> s._str;
return _cin;
}