2.2 有参构造函数
string(const char* str)
:_size(strlen(str))
,_capacity(strlen(str))
{
_str = new char[_capacity + 1];
strcpy(_str, str);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
先确定str
有效字符串长度,再决定申请多大空间,最后将str中内容拷贝给该对象
2.3 全缺省构造函数
【瑕疵版本】:
string(const char *str = nullptr)
:_size(strlen(str))
,_capacity(strlen(str))
{
_str = new char[_capacity + 1];
strcpy(_str, str);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
不足在于:当缺省值为nullptr时,strlen计算大小会报错,strlen会对参数部分解引用操作。同时这里strlen函数调用多次,效率降低。
【完善版本】:
string(const char *str="")
:_size(strlen(str))
{
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
缺省值给""
空字符串,编译器会自动填充\0
,达到了无参的要求。无参调用时,调用strlen()函数计算大小为0。虽然缺省值可以直接给\0
,但是没有必要,会导致有两个\0
存在。
小结:在实践中推荐只保留一个全缺省构造函数。
三、析构函数
~string()
{
delete[]_str;
_size = _capacity = 0;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
清空_str
指向动态空间中的资源,delete[] _str会调用析构函数和free释放空间。
四、交换函数Swap
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
void swap(string& x,string &y)
{
x.swap(y);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
这里实现了在string类外和string类中的交换函数swap,但是类外的本质还是调用类中的swap。虽然算法库有swap函数模板,但是需要走深拷贝,代价很大,这里需要重现实现swap函数。
实现一个成员函数,通过交换属性(值拷贝),代价较少。虽然本质还是调用算法库中库函数,但是使用方式不同,付出的代价也不同。
小结:在使用swap函数时,需要根据自己的需求来使用,不然会弄巧成拙的
五、拷贝构造函数
5.1 传统写法
string(const string& s)
{
_str = new char[s._capacity + 1];
strcpy(_str, s._str);
_size = s._size;
_capacity = s._capacity;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

具体流程:_str指向空,该对象没有被实例化。先开辟一块跟被拷贝对象等大的空间,再将数据拷贝一份。拷贝构造是将其他对象数据,拷贝到新的对象中。这本身是不影响被拷贝对象。
5.2 现代写法
string(const string& str)
{
string ss(str._str);
swap(ss);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

具体流程:_ str指向空,该对象没有被实例化。先调用string ss(str. _str)
构造函数,得到一份str._str
相同数据跟_str交换。相当于就是 _str和打工仔ss进行交互,完成拷贝操作。
这不采用string ss(s)
拷贝构造,在拷贝构造中调用拷贝构造,本身就是闭环。
小结:
- 无论是现代写法还是传统写法,在效率上是一样的,主要在于书写行数的关系
- 现代写法和传统写法参数相同,不能构成函数重载,只能选择一个使用
六、operator[] (下标方括号)
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
具体分析:
- 首先operator[]是调用函数,并且有两个函数重载
- 其次operator[]是个大进步,对于检查越界的情况
- 如果是数组的话,很难检查是否有越界情况发生(越界检查是一种抽查,在容易越界的地方,放几个值,看这个值是否被修改)。越界读的话,很难发现越界,是很危险的
- operator[]实现中,有assert判断是否出现有越界的情况。
- 关于
const char& operator[](size_t pos) const
情况,是为了对于被const修饰对象,也可以访问其元素,并且仅限于读权限
七、operator=(赋值运算符重载)
7.1 传统写法
string& operator=(const string& str)
{
char* tmp = new char[str._capacity + 1];
strcpy(tmp, str._str);
delete[]_str;
_str = tmp;
_size = str._size;
_capacity = str._capacity;
return *this
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

具体说明:
赋值操作是发生于两个对象已经创建完毕,对此被赋值对象自然存在一块空间,需要等着被清除资源。这里赋值拷贝不能影响到赋值对象,可以采用使用一个临时变量进行中间过程交换,开辟跟被拷贝对象等大的空间,将数据拷贝,将_str指向旧空间释放,指向tmp指向空间完成赋值。
tmp是函数内部声明的自动变量(局部变量),出作用域会自动销毁,但是指向堆上分配的内存不会因为tmp的销毁而释放,导致_str指向那块空间不会被回收,顺便完成了tmp指向空间为空操作。
7.2 现代写法
string& operator=(const string& s)
{
string ss(s);
swap(ss);
return *this;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

这里不用担心ss对象指向空间没有得到释放,ss对象属于局部对象,出了函数作用域就会调用析构函数和销毁。
7.3 现代写法优化
string& operator=(string ss)
{
swap(ss);
return *this;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
相对于上面的现代写法,这里在传参的过程中完成了拷贝构造。
小结:
- 无论是现代写法还是传统写法,在效率上是一样的,主要在于书写行数的关系
- 现代写法和传统写法参数相同,不能构成函数重载,只能选择一个使用
八、Size(获得字符串长度)
size_t size(const string& s) const
{
return s._size;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
九、Capacity(获得容量大小)
size_t capacity(const string& s) const
{
return s._capacity;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
十、resever
void reserve(size_t n)
{
if (n > _capacity)
{
char* tmp = new char[n + 1];
strcpy(tmp, _str);
delete[]_str;
_str = tmp;
_capacity = n;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- reserve只有在所需空间超过当前容量才起到扩容作用
- 让打工仔tmp开辟满足条件的空间,_str在进行拷贝、销毁、转化指向
- 这里需要改动_capacity就行, _size代表是有效个数
十一、resize
void resize(size_t n, char ch = '\0')
{
if (n <= _size)
{
_str[n] = '\0';
_size = n;
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_str[n] = '\0';
_size = n;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
说明:
- 使用resize需要考虑三种情况,但是模拟实现可以只考虑两种情况
- 提前使用reserve开辟好空间,避免扩容操作,将两种情况处理成一种情况
- 当n小于等于当前大小,需要使用
\0
的形式截断字符串 - 当n大于等当前容量,就是按照ch完成填充新开辟空间
十二、insert
12.1 任意位置插入字符
【瑕疵版本】:
void insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
size_t end = _size;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}
_str[pos] = ch;
++_size;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
不足之处:从代码的逻辑来看,感觉是没啥问题。如果选择在首位置插入数据,end进行–操作变成负数。由于end类型为size_t 无符号整数会导致end为最大值,循环不会停下。
【尝试调正】:那么将end设置为符号整型,就可以保证它可以为负数
int end = _size;
while (end >= pos)
{
_str[end + 1] = _str[end];
--end;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
但是end和pos是不同类型的变量,在进行比较时,编译器会执行整型提升,size__t隐式转化为int类型再比较。
【最终方案】:
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
让end指向结尾下一个位置。在数据移动的时候,解决了首位置插入end等于pos移动导致死循环的问题。
12.2 任意位置插入字符串
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (len + _size > _capacity)
{
reserve(_size + len);
}
size_t end = _size + len;
while (end > pos + len)
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, str, len);
_size += len;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20

具体流程:先提前判断插入字符串长度是否会超过当前容量,这里同上面一致将元素移动备份,将待插入元素进行覆盖操作。需要注意插入在首位置死循环的问题,同样采取上面的解决办法:向后移动N位预留空间。代码逻辑可以参考中两张图片理解。
十三、push_back
void push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 4 : 2 * _capacity);
}
_str[_size] = ch;
++_size;
_str[_size] = '\0';
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- 插入单个字符时,需要判断空间是否充足
- 跟顺序表的尾插差不多
- 实现任意位置插入,直接内部调用insert也是可以的
十四、append
void append(const char* str)
{
size_t len = strlen(str);
if (_size + len > _capacity)
{
reserve(_size + len);
}
strcpy(_str + _size, str);
_size += len;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- 当然可以选择一开始直接扩容
- 插入字符串时,需要判断空间是否充足
- 跟顺序表的尾插差不多
- 实现任意位置插入,直接内部调用insert也是可以的
十五、operator +=
string& operator+=(char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
十六、find
16.1 寻找字符
size_t find(char ch, size_t pos = 0) const
{
assert(pos < _size);
for (size_t i = pos; i < _size; i++)
{
if (_str[i] == ch)
return i;
}
return npos;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- 从任意位置遍历,找到返回该位置索引
- 没有找到就返回npos(-1)
- const修饰函数,仅限于读权限
16.2 寻找字符串
size_t find(const char* sub, size_t pos = 0) const
{
assert(pos < _size);
const char* p = strstr(_str + pos, sub);
if (p)
{
return p - _str;
}
else
{
return npos;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- strstr匹配所需字符串,返回匹配到字符串第一个位置
- 如果为空,表示不存在
- 如果找到了,利用指针-指针,得到下标位置索引
十七、substr
string substr(size_t pos = 0, size_t len = npos)
{
string sub;
if (len >= _size - pos)
{
for (size_t i = pos; i < _size; i++)
{
sub += _str[i];
}
}
else
{
for (size_t i = pos; i < pos + len; i++)
{
sub += _str[i];
}
}
return sub;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
说明:
- substr功能是返回从指定位置开始len长度的字符串
- 先创建string空对象用于接收截取字符串
- 当
len == npos
或len >= _size - pos
,代表了从pos位置到尾的字符串截取。 - 尽量书写
len >= _size - pos
,而不是len + pos >= _size
这种,是为了防止len + pos
超过类型最大值范围
十八、clear
void clear()
{
_size = 0;
_str[_size] = '\0';
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
清空资源,不释放空间
十九、erase
void erase(size_t pos = 0, size_t len = npos)
{
assert(pos <= _size);
if (pos > _size - len || len==npos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

具体说明:如果长度大于从指定位置到结束位置的长度,只需要在pos位置设置结束标识符。不然的话,就是将需要清空位置被后面的内容覆盖就行。如果对于strcpy这块逻辑不明白,可以回顾下strcpy使用方法。
二十、运算符重载
bool operator==(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret == 0;
}
bool operator<(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret < 0;
}
bool operator<=(const string& s1, const string& s2)
{
return s1 < s2 || s1 == s2;
}
bool operator>(const string& s1, const string& s2)
{
return !(s1 <= s2);
}
bool operator>=(const string& s1, const string& s2)
{
return !(s1 < s2);
}
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
说明:跟类和对象实现日期Date是一样的,具体有需要点击该连接日期类
二十一、实现迭代器
21.1 可读可修改
typedef char* iterator;
iterator begin()
{
return _str;
}
iterator end()
{
return _str + _size;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
22.2 可读不可修改
typedef const char* iterator;
const_iterator begin() const
{
return _str;
}
const_iterator end() const
{
return _str + _size;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
- 迭代器是一个像指针的东西,可以是指针,也可以不是指针,具体还需要看底层实现
- 这里使用指针实现迭代器,返回第一个位置和最后一个位置的下一个位置。
二十三、模拟实现流插入和流提取
23.1 operator<<(流插入)
#include
using namespace std;
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
说明:
operator
是C++标准库中的一个类,用于输出数据流,位于标准命名空间std中。对此需要引用std命名空间访问。out << ch;
重载的<<
运算符用于将字符ch
写入输出流out
是C++标准库中重载
23.2 operator>>(流提取)
istream& operator>>(istream& in, string& s)
{
s.clear();
char ch;
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;
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
具体流程:首先clear先清空对象中的资源,这里需要考虑char类型的最大值为128,创建个数组用于输入到类中,使用operator+=将得到的字符串输入到对象中。
流提取是将从键盘中读取的数据存储到s对象中,至于返回类型为istream&
是为支持连续流提取操作cin >> s >> s2
。string中getline接口模拟实现是一样的就不展开.
头文件:string.h
#pragma once
#include
#include
using namespace std;
namespace bit
{
class string
{
public:
typedef char* iterator;
typedef const char* const_iterator;
iterator begin()
{
return _str;
}
const_iterator begin() const
{
return _str;
}
iterator end()
{
return _str + _size;
}
const_iterator end() const
{
return _str + _size;
}
string(const char *str="")
:_size(strlen(str))
{
_capacity = _size;
_str = new char[_capacity + 1];
strcpy(_str, str);
}
string& operator=(const string& 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& operator=(const string& s)
{
string ss(s._str);
swap(ss);
return *this;
}
string& operator=(string ss)
{
swap(ss);
return *this;
}
size_t size(const string& s) const
{
return s._size;
}
size_t capacity(const string& s) const
{
return s._capacity;
}
char& operator[](size_t pos)
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
assert(pos < _size);
return _str[pos];
}
const char& operator[](size_t pos) const
{
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 <= _capacity)
{
_str[n] = '\0';
_size = n;
}
else
{
reserve(n);
for (size_t i = _size; i < n; i++)
{
_str[i] = ch;
}
_str[n] = '\0';
_size = n;
}
}
void push_back(char ch)
{
if (_size == _capacity)
{
reserve(_capacity == 0 ? 2 : 2 * _capacity);
}
_str[_size] = ch;
_size++;
_str[_size] = '\0';
}
void append(const char* str)
{
size_t len = strlen(str);
reserve(_capacity+len);
strncpy(_str + _size, str, len);
_size = _size + len;
}
void swap(string& s)
{
std::swap(_str, s._str);
std::swap(_size, s._size);
std::swap(_capacity, s._capacity);
}
string& operator+=(const char ch)
{
push_back(ch);
return *this;
}
string& operator+=(const char* str)
{
append(str);
return *this;
}
void insert(size_t pos, char ch)
{
assert(pos <= _size);
if (_size == _capacity)
{
reserve(_capacity == 0 ? 2 : 2 * _capacity);
}
size_t end = _size + 1;
while (end > pos)
{
_str[end] = _str[end - 1];
--end;
}
_str[pos] = ch;
++_size;
}
void insert(size_t pos, const char* str)
{
assert(pos <= _size);
size_t len = strlen(str);
if (len + _size > _capacity)
{
reserve(_size + len);
}
size_t end = _size + len;
while (end > pos + len)
{
_str[end] = _str[end - len];
--end;
}
strncpy(_str + pos, str, len);
_size += len;
}
void erase(size_t pos, size_t len = npos)
{
assert(pos <= _size);
if (pos + len > _size || len==npos)
{
_str[pos] = '\0';
_size = pos;
}
else
{
strcpy(_str + pos, _str + pos + len);
_size -= len;
}
}
size_t find(char ch, size_t pos = 0) const
{
assert(pos <= _size);
for (size_t i = 0; i < pos; i++)
{
if (_str[i] == ch)
return i;
}
return npos;
}
size_t find(char* sub, size_t pos = 0) const
{
assert(pos <= _size);
const char* p = strstr(_str + pos, sub);
if (p == nullptr)
return npos;
else
return p - _str;
}
string substr(size_t pos = 0, size_t len = npos)
{
assert(pos <= _size);
string sub;
if (pos > _capacity - len || len==npos)
{
for (size_t i = pos; i <_size; i++)
{
sub += _str[i];
}
}
else
{
for (size_t i = pos; i < pos + len; i++)
{
sub += _str[i];
}
}
return sub;
}
const char* c_str() const
{
return _str;
}
void clear()
{
_size = 0;
_str[_size] = '\0';
}
private:
char* _str;
size_t _size;
size_t _capacity;
static const size_t npos;
};
static const size_t nops = -1;
void swap(string& x,string &y)
{
x.swap(y);
}
bool operator==(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret == 0;
}
bool operator<(const string& s1, const string& s2)
{
int ret = strcmp(s1.c_str(), s2.c_str());
return ret < 0;
}
bool operator<=(const string& s1, const string& s2)
{
return s1 < s2 || s1 == s2;
}
bool operator>(const string& s1, const string& s2)
{
return !(s1 <= s2);
}
bool operator>=(const string& s1, const string& s2)
{
return !(s1 < s2);
}
bool operator!=(const string& s1, const string& s2)
{
return !(s1 == s2);
}
ostream& operator<<(ostream& out, const string& s)
{
for (auto ch : s)
{
out << ch;
}
return out;
}
iostream& operator>>(iostream& in, string& s)
{
s.clear();
char buff[128];
char ch;
ch=in.get();
size_t i = 0;
while (ch != '\n' && ch != ' ')
{
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;
}
istream& getline(istream in, string& s)
{
s.clear();
char buff[128];
char ch;
ch = in.get();
size_t i = 0;
while (ch != '\n' && ch != ' ')
{
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;
}
}
class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
class="hide-preCode-box">
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
- 188
- 189
- 190
- 191
- 192
- 193
- 194
- 195
- 196
- 197
- 198
- 199
- 200
- 201
- 202
- 203
- 204
- 205
- 206
- 207
- 208
- 209
- 210
- 211
- 212
- 213
- 214
- 215
- 216
- 217
- 218
- 219
- 220
- 221
- 222
- 223
- 224
- 225
- 226
- 227
- 228
- 229
- 230
- 231
- 232
- 233
- 234
- 235
- 236
- 237
- 238
- 239
- 240
- 241
- 242
- 243
- 244
- 245
- 246
- 247
- 248
- 249
- 250
- 251
- 252
- 253
- 254
- 255
- 256
- 257
- 258
- 259
- 260
- 261
- 262
- 263
- 264
- 265
- 266
- 267
- 268
- 269
- 270
- 271
- 272
- 273
- 274
- 275
- 276
- 277
- 278
- 279
- 280
- 281
- 282
- 283
- 284
- 285
- 286
- 287
- 288
- 289
- 290
- 291
- 292
- 293
- 294
- 295
- 296
- 297
- 298
- 299
- 300
- 301
- 302
- 303
- 304
- 305
- 306
- 307
- 308
- 309
- 310
- 311
- 312
- 313
- 314
- 315
- 316
- 317
- 318
- 319
- 320
- 321
- 322
- 323
- 324
- 325
- 326
- 327
- 328
- 329
- 330
- 331
- 332
- 333
- 334
- 335
- 336
- 337
- 338
- 339
- 340
- 341
- 342
- 343
- 344
- 345
- 346
- 347
- 348
- 349
- 350
- 351
- 352
- 353
- 354
- 355
- 356
- 357
- 358
- 359
- 360
- 361
- 362
- 363
- 364
- 365
- 366
- 367
- 368
- 369
- 370
- 371
- 372
- 373
- 374
- 375
- 376
- 377
- 378
- 379
- 380
- 381
- 382
- 383
- 384
- 385
- 386
- 387
- 388
- 389
- 390
- 391
- 392
- 393
- 394
- 395
- 396
- 397
- 398
- 399
- 400
- 401
- 402
- 403
- 404
- 405
- 406
- 407
- 408
- 409
- 410
- 411
- 412
- 413
- 414
- 415
- 416
- 417
- 418
- 419
- 420
- 421
- 422
- 423
- 424
- 425
- 426
- 427
- 428
- 429
- 430
- 431
- 432
- 433
- 434
- 435
- 436
- 437
- 438
- 439
- 440
- 441
- 442
- 443
- 444
- 445
- 446
- 447
- 448
- 449
- 450
- 451
- 452
- 453
- 454
- 455
- 456
- 457
- 458
- 459
- 460
- 461
- 462
- 463
- 464
- 465
- 466
- 467
- 468
- 469
- 470
- 471
- 472
- 473
- 474
- 475
- 476
- 477
- 478
- 479
- 480
- 481
- 482
- 483
- 484
- 485
- 486
- 487
- 488
- 489
- 490
- 491
- 492
- 493
- 494
- 495
- 496
- 497
- 498
- 499
- 500
- 501
- 502
- 503
- 504
- 505
- 506
- 507
- 508
以上就是本篇文章的所有内容,在此感谢大家的观看!这里是店小二呀C++笔记,希望对你在学习C++语言旅途中有所帮助!

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/2302_79177254/article/details/141189352","extend1":"pc","ab":"new"}">>
评论记录:
回复评论: