Skip to content

Commit 926230f

Browse files
对 C 语言系统教程的第二章和第三章添加了参考答案 (#108)
* 对C_tutorials 第六章的状态机示例代码添加了注释 * 对C_tutorials 第六章的状态机示例代码添加了注释(修正版) * docs(vol1): refine state machine comments 追加到 PR #104 的 review 修正,纯注释、零逻辑改动: - payload_len / index: 把「几个负载」改成「几个字节」, 代码实际含义如此,负载更像是完整的Payload,跟代码还是具备实际差距 - kStateHeader: 修正为「帧头已收完,接下来等长度字节」, - 顺手修了结构体注释的对齐(payload[64]) * 对C_tutorials 第二章的练习题添加了参考答案 Added example solutions for exercises on data types and overflow in C. * 对C_tutorials 第三章的练习题添加了参考答案 * fix: lint issue --------- Co-authored-by: Charliechen114514 <725610365@qq.com>
1 parent 5878e83 commit 926230f

2 files changed

Lines changed: 142 additions & 7 deletions

File tree

documents/vol1-fundamentals/c_tutorials/02A-data-types-basics.md

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,52 @@ uint8_t z{1000}; // C++ 编译错误!1000 超出 uint8_t 范围
284284

285285
提示:可以用一个宏来减少重复代码。
286286

287+
### 练习 1 参考答案
288+
289+
```c
290+
#include <stdio.h>
291+
#include <stdint.h>
292+
//#include <stddef.h>
293+
294+
int main() {
295+
// 基本类型
296+
printf("sizeof(char) = %zu bytes\n", sizeof(char));
297+
printf("sizeof(short) = %zu bytes\n", sizeof(short));
298+
printf("sizeof(int) = %zu bytes\n", sizeof(int));
299+
printf("sizeof(long) = %zu bytes\n", sizeof(long));
300+
printf("sizeof(long long) = %zu bytes\n", sizeof(long long));
301+
302+
// 定长整数类型 (需包含 <stdint.h>)
303+
printf("sizeof(int8_t) = %zu bytes\n", sizeof(int8_t));
304+
printf("sizeof(uint8_t) = %zu bytes\n", sizeof(uint8_t));
305+
printf("sizeof(int32_t) = %zu bytes\n", sizeof(int32_t));
306+
printf("sizeof(uint32_t) = %zu bytes\n", sizeof(uint32_t));
307+
printf("sizeof(int64_t) = %zu bytes\n", sizeof(int64_t));
308+
309+
// size_t 类型 (需包含<stdio.h>、 <stddef.h> 或 <stdlib.h>)
310+
printf("sizeof(size_t) = %zu bytes\n", sizeof(size_t));
311+
312+
return 0;
313+
}
314+
315+
```
316+
317+
```text
318+
sizeof(char) = 1 bytes
319+
sizeof(short) = 2 bytes
320+
sizeof(int) = 4 bytes
321+
sizeof(long) = 4 bytes
322+
sizeof(long long) = 8 bytes
323+
sizeof(int8_t) = 1 bytes
324+
sizeof(uint8_t) = 1 bytes
325+
sizeof(int32_t) = 4 bytes
326+
sizeof(uint32_t) = 4 bytes
327+
sizeof(int64_t) = 8 bytes
328+
sizeof(size_t) = 8 bytes
329+
```
330+
331+
注意 `sizeof(long)` 这里是 4,但 `sizeof(size_t)` 已经是 8 了,说明这份输出来自 LLP64 环境(比如 64 位 Windows):这种模型下指针 8 字节,`long` 却只有 4。换到 64 位的 Linux 或 macOS(LP64),`long` 就是 8 字节。你在自己机器上看到 `sizeof(long) = 8`,程序没写错,是数据模型的差别。
332+
287333
### 练习 2:溢出观察
288334

289335
分别对有符号 `int` 和无符号 `unsigned int` 做溢出实验:
@@ -306,6 +352,29 @@ int main(void)
306352
307353
编译运行,观察两者的行为差异。然后加上 `-fsanitize=undefined` 选项重新编译,看看有什么变化。
308354
355+
### 练习 2 参考答案
356+
357+
假设该文件名为overflow.c
358+
359+
使用 gcc overflow.c -o overflow && ./overflow 编译运行后,你大概率会看到如下输出:
360+
361+
```text
362+
INT_MAX = 2147483647, INT_MAX + 1 = -2147483648
363+
UINT_MAX = 4294967295, UINT_MAX + 1 = 0
364+
```
365+
366+
使用 gcc -fsanitize=undefined overflow.c -o overflow_ubsan && ./overflow_ubsan 编译运行后,你会看到类似如下的输出:
367+
368+
```text
369+
INT_MAX = 2147483647, INT_MAX + 1 = -2147483648
370+
overflow.c:9:54: runtime error: signed integer overflow: 2147483647 + 1 cannot be represented in type 'int'
371+
UINT_MAX = 4294967295, UINT_MAX + 1 = 0
372+
```
373+
374+
为什么?
375+
实际上 C 标准其实并没有对带有符号的整数的溢出进行定义,也就是说,对INT_MAX进行+1这个操作严格意义上是一个未定义行为。
376+
(只不过溢出很好用,也是大部分编译器都默认支持溢出的。)
377+
309378
## 参考资源
310379

311380
- [cppreference: C 语言整型](https://en.cppreference.com/w/c/language/integer_constant)

documents/vol1-fundamentals/c_tutorials/02B-float-char-const-cast.md

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -316,17 +316,41 @@ C++ 在类型系统上做了大量的安全加固,很多改进直接瞄准了
316316

317317
int main(void)
318318
{
319-
double a = 0.1;
320-
double b = 0.2;
321-
double c = 0.3;
322-
323-
printf("a + b == c? %s\n", (a + b == c) ? "yes" : "no");
324-
printf("a + b = %.20f\n", a + b);
325-
printf("c = %.20f\n", c);
319+
double a_double = 0.1;
320+
double b_double = 0.2;
321+
double c_double = 0.3;
322+
float a_float = 0.1f;
323+
float b_float = 0.2f;
324+
float c_float = 0.3f;
325+
float e_float = 0.3f;
326+
float f_float = 0.4f;
327+
float g_float = 0.7f;
328+
329+
printf("a_double + b_double == c_double? %s\n", (a_double + b_double == c_double) ? "yes" : "no");
330+
printf("a_float + b_float == c_float? %s\n", (a_float + b_float == c_float) ? "yes" : "no");
331+
printf("e_float + f_float == g_float? %s\n", (e_float + f_float == g_float) ? "yes" : "no");
332+
printf("a_double + b_double = %.20f\n", 0.1 + 0.2);
333+
printf("a_float + b_float = %.20f\n", 0.1f + 0.2f);
334+
printf("e_float + f_float = %.20f\n", 0.3f + 0.4f);
335+
printf("c_double = %.20f\n", c_double);
336+
printf("c_float = %.20f\n", c_float);
337+
printf("g_float = %.20f\n", g_float);
326338
return 0;
327339
}
328340
```
329341
342+
```text
343+
a_double + b_double == c_double? no
344+
a_float + b_float == c_float? yes
345+
e_float + f_float == g_float? no
346+
a_double + b_double = 0.30000000000000004441 //0.1 + 0.2
347+
a_float + b_float = 0.30000001192092895508 //0.1f + 0.2f
348+
e_float + f_float = 0.70000004768371582031 //0.3f + 0.4f
349+
c_double = 0.29999999999999998890 //0.3
350+
c_float = 0.30000001192092895508 //0.3f
351+
g_float = 0.69999998807907104492 //0.7f
352+
```
353+
330354
修改代码使用 epsilon 比较来得到正确的结果。
331355

332356
### 练习 2:隐式转换陷阱
@@ -345,6 +369,31 @@ if (target < sizeof(values) / sizeof(values[0])) {
345369

346370
提示:`sizeof` 返回的是什么类型?
347371

372+
373+
### 练习 2 参考答案
374+
375+
```c
376+
int values[] = {1, 2, 3, 4, 5};
377+
int target = -1;
378+
379+
// bug 就在下面这行
380+
if (target < (int)sizeof(values) / (int)sizeof(values[0])) {
381+
printf("target is in range\n");
382+
}
383+
```
384+
385+
或者
386+
387+
```c
388+
int values[] = {1, 2, 3, 4, 5};
389+
int target = -1;
390+
391+
// bug 就在下面这行
392+
if (target < (int)(sizeof(values) / sizeof(values[0]))) {
393+
printf("target is in range\n");
394+
}
395+
```
396+
348397
### 练习 3:const 实战
349398

350399
写一个函数,接收一个字符串,统计其中某个字符出现的次数。函数签名中正确使用 `const`
@@ -357,6 +406,23 @@ if (target < sizeof(values) / sizeof(values[0])) {
357406
size_t count_char(const char* str, char ch);
358407
```
359408
409+
### 练习 3 参考答案
410+
411+
```c
412+
size_t count_char(const char* str, char ch) {
413+
if (str == NULL) { // 警惕空指针
414+
return 0;
415+
}
416+
size_t count = 0;
417+
for (;*str;str++) {
418+
if (*str == ch) {
419+
count++;
420+
}
421+
}
422+
return count;
423+
}
424+
```
425+
360426
## 参考资源
361427

362428
- [cppreference: C 语言隐式转换](https://en.cppreference.com/w/c/language/conversion)

0 commit comments

Comments
 (0)