一.STL简介
1. 1什么是STL
STL(standard template libaray- 标准模板库 ) : 是 C++ 标准库的重要组成部分 ,不仅是一个可复用的 组件库,而且 是一个包罗数据结构与算法的软件框架 。1.2 STL的六大组件
接下来开始模拟实现STL中的常用string类
三个成员变量
char* _str;
size_t _size;
size_t _capacity;
二.string类的构造
不带参构造,直接在初始化列表初始化即可
string()
:_str[nullptr]
,_size[0]
,_capacity[0]
{}
带参构造,先开空间,再构造
string(const char* str)
//如果还全在初始化列表
:_size(strlen(str))
,_capacity(_size)
,_str(new[_size+1])
{
strcpy(_str,str);
}
初始化列表是按成员变量的顺序进行初始化,会先对_str进行初始化,这样写就会报错
所以带参构造分开来写
string(const char* str)
:_size(strlen(str))
{
_capacity = _size;
_str = new char[_size + 1];
strcpy(_str, str);
}
三.string类的输出
1.传统字符串输出
字符串也可以像数组一样用[ ]和下标进行访问
string s("abc");
for(size_t i=0;i<s.size();i++)
{
cout<<s[i]<<endl;
}
2. 迭代器,auto,范围for
auto关键字
c++11中,auto 不再是一个存储类型 指示符,而是作为一个新的类型指示符来指示编译器, auto 声明的变量必须由编译器在编译时期 推导而得 。 用 auto 声明指针类型时,用 auto 和 auto* 没有任何区别,但用 auto 声明引用类型时则必须加 & 当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际 只对第一个类型进行推导,然后用推导出来的类型定义其他变量 。 auto 不能作为函数的参数,可以做返回值,但是建议谨慎使用。 auto 不能直接用来声明数组。 范围for for 循环后的括号由冒号 “ : ” 分为两部分:第一部分是范围 内用于迭代的变量,第二部分则表示被迭代的范围 ,自动迭代,自动取数据,自动判断结束。 范围 for 可以作用到数组和容器对象上进行遍历 范围 for 的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。 迭代器用法可以看做和指针一样的用法(不等同于指针),所以可以像指针一样解引用来访问字符串里的元素string s("abc");
string::iterator it=s.begin();
for(auto e:it)
{
cout<<*it<<" ";
++it;
}
四.string类对字符串进行修改的相关操作
assign清空然后重新赋值
assign会把原字符串的内容先全清空,然后再赋值为括号里给的字符串
拷贝构造
void string::swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}//传统写法
//s1(s2)
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);
}
赋值
void string::swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}//传统写法
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=(string s)
{
swap(s);
return *this;
}
扩容
void string::reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[] _str;
_str = tmp;_capacity = n;
}
}
尾插
尾插字符
void string::push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
_str[_size] = ch;
++_size;
}
尾插字符串
void string::append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
size_t newCapacity = 2 * _capacity;
if (newCapacity < _size + len)
{
newCapacity = _size + len;
}
reserve(newCapacity);
}
strcpy(_str + _size, str);
_size += len;
}
插入
指定位置插入字符
void string::insert(size_t pos,char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
size_t end = _size + 1;
while (pos < end)
{
_str[end] = _str[end-1];
--end;
}
_str[pos] = ch;
_size++;
}
指定位置插入字符串
void string::insert(size_t pos, const char* str)
{
assert(pos < _size);
size_t len = strlen(str);
if (_size + len > _capacity)
{
size_t newCapacity = 2 * _capacity;
if (_size + len < _capacity)
{
_capacity = _size + len;
}
reserve(newCapacity);
}
size_t end = _size + len;
while (end > pos + len - 1)
{
_str[end] = _str[end - len];
--end;
}
for (size_t i = 0; i < len ; i++)
{
_str[pos + i] = str[i];}
_size += len;
}
删除
删除指定位置后的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 > pos)
{
_str[end - len] = _str[end];
++end;
}
_size -= len;
}
}
查找
查找字符
size_t string::find(char ch, size_t pos)
{
assert(pos < _size);
for (size_t i = 0; 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;
}
}
提取
提取字符串的一部分
string string::substr(size_t pos, size_t len)
{
assert(pos < _size);
if (len > (_size - pos))
{
len = _size - pos;
}
bit::string sub;
sub.reserve(len);
for (size_t i = 0; i < len; i++)
{
sub += _str[pos + i];}
return sub;
}
五.string类对象的容量操作
-
size()
size()
方法返回的是std::string
对象中当前存储的字符数(不包括结尾的空字符'\0'
)。 -
capacity()
capacity()
方法返回的是std::string
对象在不需要重新分配内存的情况下可以存储的字符的最大数量。这通常是一个大于或等于size()
的值,因为std::string
可能会为了效率而预先分配额外的内存空间。
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
size_t size() const
{
return _size;
}
const char* c_str() const
{
return _str;
}
sizeof
运算符:sizeof
运算符返回的是对象或类型在内存中所占用的字节数。对于std::string
对象,sizeof
返回的是std::string
类实例(包括其成员变量,如指向字符数组的指针、大小、容量等)的大小,而不是它实际存储的字符数组的大小。因为std::string
使用动态内存分配来存储字符数据,所以sizeof
不会反映这些数据的大小。