Skip to content

Commit 527e8f5

Browse files
committed
Updated to Chapter 8, Section 7
1 parent ece566d commit 527e8f5

File tree

15 files changed

+1248
-110
lines changed

15 files changed

+1248
-110
lines changed

.vscode/settings.json

+55
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
{
2+
"files.associations": {
3+
"algorithm": "cpp",
4+
"atomic": "cpp",
5+
"bit": "cpp",
6+
"cctype": "cpp",
7+
"charconv": "cpp",
8+
"clocale": "cpp",
9+
"cmath": "cpp",
10+
"compare": "cpp",
11+
"concepts": "cpp",
12+
"cstddef": "cpp",
13+
"cstdint": "cpp",
14+
"cstdio": "cpp",
15+
"cstdlib": "cpp",
16+
"cstring": "cpp",
17+
"ctime": "cpp",
18+
"cwchar": "cpp",
19+
"exception": "cpp",
20+
"format": "cpp",
21+
"initializer_list": "cpp",
22+
"ios": "cpp",
23+
"iosfwd": "cpp",
24+
"iostream": "cpp",
25+
"istream": "cpp",
26+
"iterator": "cpp",
27+
"limits": "cpp",
28+
"locale": "cpp",
29+
"memory": "cpp",
30+
"new": "cpp",
31+
"optional": "cpp",
32+
"ostream": "cpp",
33+
"stdexcept": "cpp",
34+
"streambuf": "cpp",
35+
"system_error": "cpp",
36+
"tuple": "cpp",
37+
"type_traits": "cpp",
38+
"typeinfo": "cpp",
39+
"utility": "cpp",
40+
"vector": "cpp",
41+
"xfacet": "cpp",
42+
"xiosbase": "cpp",
43+
"xlocale": "cpp",
44+
"xlocbuf": "cpp",
45+
"xlocinfo": "cpp",
46+
"xlocmes": "cpp",
47+
"xlocmon": "cpp",
48+
"xlocnum": "cpp",
49+
"xloctime": "cpp",
50+
"xmemory": "cpp",
51+
"xstring": "cpp",
52+
"xtr1common": "cpp",
53+
"xutility": "cpp"
54+
}
55+
}

.vscode/tasks.json

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
"tasks": [
3+
{
4+
"type": "cppbuild",
5+
"label": "C/C++: g++.exe build active file",
6+
"command": "D:\\msys64\\ucrt64\\bin\\g++.exe",
7+
"args": [
8+
"-fdiagnostics-color=always",
9+
"-g",
10+
"${file}",
11+
"-o",
12+
"${fileDirname}\\${fileBasenameNoExtension}.exe"
13+
],
14+
"options": {
15+
"cwd": "D:\\msys64\\ucrt64\\bin"
16+
},
17+
"problemMatcher": [
18+
"$gcc"
19+
],
20+
"group": {
21+
"kind": "build",
22+
"isDefault": true
23+
},
24+
"detail": "Task generated by Debugger."
25+
}
26+
],
27+
"version": "2.0.0"
28+
}

code_in_book/8.1-8.2/Header.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ class valarri { //valarri类定义
1515
private:
1616
int *_p; //私有指针成员_p,用来指向申请的动态内存空间
1717
public:
18-
Arr(int *ptr) : _p{ptr} {} //构造函数,接收一个指针初始化
18+
Arr(int *ptr) : _p {ptr} {} //构造函数,接收一个指针初始化
1919
int*& p() { return _p; } //返回类型是“对指针的引用”,其值为_p
2020
const int* p()const { return _p; } //返回类型是“指向常量的指针”,其值为_p
2121
}_arr {new int[_cap]}; //作为一个中介对象存在,是访问_p成员的窗口

code_in_book/8.3-8.5/Definition.cpp

+262
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,262 @@
1+
#include "Header.h"
2+
#include <algorithm>
3+
string::string(std::size_t count, char ch)
4+
: _cap {count} //_arr就用默认初值new char[_cap]来初始化足矣
5+
{
6+
for (; _size < count; _size++) //_size已经通过默认初值定为0,无需再赋值
7+
at(_size) = ch; //这里用到了at成员函数,稍后我们会看到其定义
8+
}
9+
string::string(const string &other, std::size_t pos, std::size_t count)
10+
: _cap {other._cap} //当pos和count都取默认值时它充当拷贝构造函数,故_cap要一致
11+
{
12+
if (pos >= other._size) //为了防范pos越界的情况
13+
at(0) = '\0'; //直接把第一个字符变成空字符,什么也不做
14+
else {
15+
if (count == npos //npos的意思是直接截到字符串末尾
16+
|| pos + count > other._size
17+
) //对于pos+count越界或者count==npos的情况
18+
count = other._size - pos; //接下来count的值就合适了
19+
for (; _size < count; _size++)
20+
at(_size) = other.at(_size);
21+
}
22+
}
23+
string::string(const char *s) : _cap {std::strlen(s)} {
24+
for (; _size < _cap; _size++)
25+
at(_size) = s[_size];
26+
}
27+
string::string(const char* s, std::size_t count)
28+
: _cap {std::min(std::strlen(s),count)} //防止count大于strlen(s)
29+
{
30+
for (; _size < _cap; _size++)
31+
at(_size) = s[_size];
32+
}
33+
string::string(std::initializer_list<char> ilist)
34+
: _cap {ilist.size()}
35+
{
36+
for (char ch : ilist) //范围for循环
37+
at(_size++) = ch; //注意自增符号要用后缀
38+
}
39+
string::~string() {
40+
delete[] _arr.p(); //别忘了用delete[]而不是delete
41+
}
42+
char& string::at(std::size_t pos) {
43+
if (pos >= _size)
44+
pos = _size - 1;
45+
return _arr.p()[_size];
46+
}
47+
const char& string::at(std::size_t pos)const {
48+
if (pos >= _size)
49+
pos = _size - 1;
50+
return _arr.p()[_size];
51+
}
52+
string& string::assign(std::size_t count, char ch) {
53+
if (count > _cap) //说明动态内存空间不足
54+
realloc(count, false); //重新分配,这时不需要进行内容复制,故传入false
55+
for (_size = 0; _size < count; _size++)
56+
at(_size) = ch;
57+
return *this;
58+
}
59+
string& string::assign(
60+
const string &str,
61+
std::size_t pos,
62+
std::size_t count
63+
){ //这是一种效率比较低的做法,但是操作非常简单
64+
string tmp {str, pos, count}; //用一个tmp暂存需要的内容
65+
swap(tmp); //将此对象与tmp交换
66+
return *this;
67+
}
68+
string& string::assign(const char *s, std::size_t count) {
69+
std::size_t len {std::strlen(s)}; //防止多次调用std::strlen
70+
if (count > len) //如果count大于len,那就越界了
71+
count = len; //修正count的值
72+
if (count > _cap) //说明动态内存空间不足
73+
realloc(count, false); //这里也不需要保留原内容
74+
for (_size = 0; _size < count; _size++)
75+
at(_size) = s[_size];
76+
return *this;
77+
}
78+
string& string::assign(std::initializer_list<char> ilist) {
79+
string tmp{ilist};
80+
swap(tmp); //故技重施
81+
return *this;
82+
}
83+
void string::reserve(std::size_t new_cap) {
84+
if (new_cap < _size) //防止损失有效内容
85+
new_cap = _size;
86+
realloc(new_cap); //直接使用已有的realloc函数来实现
87+
}
88+
void string::resize(std::size_t count, char ch) {
89+
if (_cap < count) //先保证动态内存空间充足
90+
realloc(count); //这里传入第二个默认参数true,说明原内容需要保留
91+
if (count > _size)
92+
for (; _size < count; _size++)
93+
at(_size) = ch; //从_size位置到count-1全部需要变成ch,注意范围
94+
else
95+
_size = count; //直接截尾即可,所以把_size变成count
96+
}
97+
string& string::append(std::size_t count, char ch) {
98+
if (_size + count > _cap)
99+
realloc(_size+count);
100+
for (; _size < count; _size++)
101+
at(_size) = ch;
102+
return *this;
103+
}
104+
string& string::append(
105+
const string &str,
106+
std::size_t pos,
107+
std::size_t count
108+
) {
109+
if (pos >= str._size) //如果起点都没有意义,那就不用拼接了
110+
return *this; //直接返回
111+
if (pos + count > str._size || count == npos)
112+
count = str._size - pos;
113+
if (_size + count > _cap) //如果内存不够
114+
realloc(_size+count); //那就重新分配内存,保留内容
115+
for(std::size_t i = 0; i < count; i++)
116+
at(_size+i) = str.at(pos+i);
117+
return *this;
118+
}
119+
string& string::append(const char *s, std::size_t count) {
120+
return append(s, 0, count);
121+
//先用构造函数把s转换成string对象,然后调用另一个append重载
122+
}
123+
string& string::append(std::initializer_list<char> ilist) {
124+
return append(string{ilist});
125+
//先用构造函数把s转换成string对象,然后调用另一个append重载,默认参数0, npos
126+
}
127+
string& string::insert(std::size_t pos, std::size_t count, char ch) {
128+
if (_size + count > _cap) //如果容量不够
129+
realloc(_size+count); //扩容
130+
for (std::size_t i = _size - 1; i >= pos; i--)
131+
at(i+count) = at(i); //从后向前,依次把字符后移count位,以留出空间
132+
for (std::size_t i = pos; i < pos+count; i++)
133+
at(i) = ch; //把pos起的count个字符变为ch
134+
_size += count; //最后别忘了更新_size的值!
135+
return *this;
136+
}
137+
string& string::insert(
138+
std::size_t pos,
139+
const string &str,
140+
std::size_t s_pos,
141+
std::size_t count
142+
) {
143+
if (s_pos >= str._size) //如果起始点已经越界
144+
return *this; //那就直接返回
145+
if (s_pos + count > str._size || count == npos)
146+
count = str._size - s_pos; //调整count的值
147+
if (_size + count > _cap)
148+
realloc(_size+count); //必要的扩容
149+
for (std::size_t i = _size - 1; i >= pos; i--)
150+
at(i+count) = at(i); //数据后移
151+
for (std::size_t i = 0; i < count; i++)
152+
at(pos+i) = str.at(s_pos+i);
153+
//从本对象的pos位置起,把str对象的s_pos位置起count个数据依次复制到此处
154+
_size += count; //别忘了更新_size的值
155+
return *this;
156+
}
157+
string& string::insert(std::size_t pos, const char *s, std::size_t count) {
158+
return insert(pos, s, 0, count);
159+
}
160+
string& string::insert(std::size_t pos, std::initializer_list<char> ilist) {
161+
return insert(pos, ilist, 0, ilist.size());
162+
}
163+
string& string::erase(std::size_t pos, std::size_t count) {
164+
if (pos >= _size)
165+
return *this;
166+
if (pos + count > _size || count == npos)
167+
count = _size - pos;
168+
for (std::size_t i = pos; i + count < _size; i++) //注意范围
169+
at(i) = at(i+count);
170+
_size -= count; //记得更新_size
171+
return *this;
172+
}
173+
std::size_t string::copy(
174+
char *dest,
175+
std::size_t count,
176+
std::size_t pos
177+
)const {
178+
if (pos >= _size)
179+
return 0;
180+
if (pos + count > _size || count == npos)
181+
count = _size - pos;
182+
for (std::size_t i = 0; i < count; i++) //把pos起的count个数据复制到字符串中
183+
dest[i] = at(pos+i);
184+
return count;
185+
}
186+
void string::swap(string &str) {
187+
std::swap(_cap, str._cap);
188+
std::swap(_size, str._size);
189+
std::swap(_arr.p(), str._arr.p());
190+
}
191+
std::size_t string::find(char ch, std::size_t pos)const {
192+
for (std::size_t i = pos; i < _size; i++) //从pos位置起开始寻找
193+
if (at(i) == ch) //找到了
194+
return i; //把i作为返回值
195+
//一直到_size处都没找到
196+
return npos; //npos可以表示没找到
197+
}
198+
std::size_t string::find(const string &str, std::size_t pos)const {
199+
for (std::size_t i = pos; i + str._size < _size; i++){
200+
bool equal {true}; //先假设片段[i,i+str._size)与片段str相等
201+
for (std::size_t j = 0; j < _size; j++)
202+
if (at(i+j) != str.at(j)) { //一旦发现一个不相等的字符
203+
equal = false; //标记为不相等
204+
break; //退出循环
205+
} //可以想见,如果这个循环下来没有任何字符不相等,那么它就是我们要找的
206+
if(equal) //euqal为真
207+
return i;
208+
}
209+
//一直到找了一大圈都无果而终
210+
return npos; //没找到
211+
}
212+
std::size_t string::find(
213+
const char *s,
214+
std::size_t pos,
215+
std::size_t count
216+
)const {
217+
return find(string(s, count), pos);
218+
//这里要调用的是string(const char*,std::size_t),不是string(const char*)
219+
}
220+
bool string::operator<(const string &str)const {
221+
return std::lexicographical_compare(
222+
&at(0), &at(_size), &str.at(0), &str.at(str._size)
223+
); //利用std::lexicographical_compare算法,具体的细节就不讲了
224+
}
225+
bool string::operator>(const string &str)const {
226+
return str < *this; //利用已经重载好的小于号
227+
}
228+
bool string::operator<=(const string &str)const {
229+
return !(str < *this); //注意运算符的优先级
230+
}
231+
bool string::operator>=(const string &str)const {
232+
return !(*this < str);
233+
}
234+
bool string::operator!=(const string &str)const {
235+
return (*this < str) || (str < *this);
236+
}
237+
bool string::operator==(const string &str)const {
238+
return !operator!=(str); //进一步利用已经重载好的operator!=
239+
}
240+
int string::compare(const string &str)const {
241+
return -int(*this<str) + int(*this>str); //bool到int类型转换后再计算
242+
}
243+
std::ostream& operator<<(std::ostream &out, const string &str) { //string的友元
244+
for (std::size_t i = 0; i < str._size; i++)
245+
out << str.at(i);
246+
return out; //返回out以便连续输出
247+
}
248+
std::istream& operator>>(std::istream &in, string &str) { //string的友元
249+
char ch;
250+
str.clear(); //先清理str中的已有内容
251+
while (in.get(ch) && std::isspace(ch)) {
252+
//空,什么也不做
253+
} //这个循环的目的在于清理空白字符
254+
if (in)
255+
do { //注意,do-while结构会至少执行一次
256+
str.append(1, ch); //把输入的单个字符加到str的末尾
257+
} while (in.get(ch) && !std::isspace(ch));
258+
//在while中读取下一个字符,并判断它是不是空白字符
259+
if (in && !std::isspace(ch)) //如果这个字符不是空白字符,且属于下一个输入
260+
in.unget(); //把这个字符还回去
261+
return in; //返回in以便连续输入
262+
}

0 commit comments

Comments
 (0)