@@ -27,9 +27,9 @@ std::swap(a, b);
27
27
28
28
> {{ icon.tip }} 只需要 `#include <utility>` 就可以使用!
29
29
30
- ## RAII 地分配一段内存空间
30
+ ## 安全地分配一段内存空间
31
31
32
- 小彭老师:不要让我看到 new 和 delete。
32
+ 小彭老师:不要出现 new 和 delete,不安全 。
33
33
34
34
同学:我想要**分配一段内存空间**,你不让我 new,我还能怎么办呢?
35
35
@@ -80,6 +80,63 @@ std::wstring utf8_to_wstring(std::string const &s) {
80
80
}
81
81
```
82
82
83
+ ## 地板除与天花板除
84
+
85
+ 众所周知,C语言中 ` int ` 相除 ` / ` ,得到的结果也是 ` int ` ,如果除法产生了余数,那么只会保留整数部分。
86
+
87
+ 例如 ` 14 / 5 ` ,本来应该得到 2.8。但是因为 C 语言的除法返回 ` int ` ,结果会自动向下取整,导致得到 2。
88
+
89
+ ``` cpp
90
+ int a, b;
91
+ int c = a / b;
92
+ ```
93
+
94
+ 等价于
95
+
96
+ ``` cpp
97
+ int c = floor((float )a / b);
98
+ ```
99
+
100
+ 如果 ` a ` 除以 ` b ` 除不尽,那么会找到比他大的第一个整数作为结果,这就是** 地板除 (floor div)** 。
101
+
102
+ C 语言默认的就是地板除。
103
+
104
+ 如果我想要的是向上取整,该怎么写?
105
+
106
+ 最原始的写法是先转成浮点数来除,然后ceil函数向上取整:
107
+
108
+ ``` cpp
109
+ int c = ceil((float )a / b);
110
+ ```
111
+
112
+ 但是浮点数不仅低效,还有糟糕的浮点数精度误差!对于很大的整数(大于 $2^{23}$)会产生错误的结果。
113
+
114
+ 更合理的写法是先把 ` a ` 加上 ` b - 1 ` ,然后再下取整地除以 ` b ` :
115
+
116
+ ``` cpp
117
+ int c = (a + b - 1 ) / b;
118
+ ```
119
+
120
+ 这样就能产生一个向上取整的除法了。
121
+
122
+ 如果 ` a ` 除以 ` b ` 除不尽,那么会找到比他大的第一个整数作为结果,这就是** 天花板除 (ceil div)** 。
123
+
124
+ 试试看:14 除以 5,应该得到 2.8;如果用地板除,会得到 2;如果用天花板除,会得到 3。
125
+
126
+ ``` cpp
127
+ 14 / 5 = 2
128
+ (14 + 5 - 1 ) / 5 = (14 + 4 ) / 5 = 18 / 5 = 3
129
+ ```
130
+
131
+ 试试看:10 除以 5,应该得到 2;那么无论是地板除还是天花板除,都应该得到 2。
132
+
133
+ ``` cpp
134
+ 10 / 5 = 2
135
+ (10 + 5 - 1 ) / 5 = (10 + 4 ) / 5 = 14 / 5 = 2
136
+ ```
137
+
138
+ 这就是 C 语言中实现天花板除的业界公认标准方式。
139
+
83
140
## 读取整个文件到字符串
84
141
85
142
``` cpp
@@ -130,7 +187,7 @@ struct Student {
130
187
Student stu{"小彭老师", 24, 123};
131
188
```
132
189
133
- 这被称为**聚合初始化** (aggergate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
190
+ 这被称为**聚合初始化** (aggregate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
134
191
135
192
好消息:C++20 中,聚合初始化也支持 `()` 了,用起来就和传统的 C++98 构造函数一样!
136
193
0 commit comments