@@ -27,9 +27,9 @@ std::swap(a, b);
2727
2828> {{ icon.tip }} 只需要 `#include <utility>` 就可以使用!
2929
30- ## RAII 地分配一段内存空间
30+ ## 安全地分配一段内存空间
3131
32- 小彭老师:不要让我看到 new 和 delete。
32+ 小彭老师:不要出现 new 和 delete,不安全 。
3333
3434同学:我想要**分配一段内存空间**,你不让我 new,我还能怎么办呢?
3535
@@ -80,6 +80,63 @@ std::wstring utf8_to_wstring(std::string const &s) {
8080}
8181```
8282
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+
83140## 读取整个文件到字符串
84141
85142``` cpp
@@ -130,7 +187,7 @@ struct Student {
130187Student stu{"小彭老师", 24, 123};
131188```
132189
133- 这被称为**聚合初始化** (aggergate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
190+ 这被称为**聚合初始化** (aggregate initialize)。只要你的类没有自定义构造函数,没有 private 成员,都可以用 `{}` 聚合初始化。
134191
135192好消息:C++20 中,聚合初始化也支持 `()` 了,用起来就和传统的 C++98 构造函数一样!
136193
0 commit comments