Skip to content

Commit a32f7c4

Browse files
committed
对 C 语言系统教程的第六章和第七章添加了参考答案
第六章的第三题难度有点高,这个答案我就不写了,交给你来写。 第二题也交给你了。 awa
1 parent a891139 commit a32f7c4

2 files changed

Lines changed: 138 additions & 16 deletions

File tree

documents/vol1-fundamentals/c_tutorials/04-control-flow.md

Lines changed: 33 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
---
22
chapter: 1
33
cpp_standard:
4-
- 11
4+
- 11
55
description: 掌握 C 语言的条件分支、循环、switch 穿透特性与状态机模式,理解 break/continue/goto 的正确用法
66
difficulty: beginner
77
order: 6
88
platform: host
99
prerequisites:
10-
- 位运算与求值顺序
10+
- 位运算与求值顺序
1111
reading_time_minutes: 11
1212
tags:
13-
- host
14-
- cpp-modern
15-
- beginner
16-
- 入门
17-
- 基础
13+
- host
14+
- cpp-modern
15+
- beginner
16+
- 入门
17+
- 基础
1818
title: 控制流:让程序学会选择和重复
1919
---
20+
2021
# 控制流:让程序学会选择和重复
2122

2223
到目前为止我们写的程序都是从第一行一路跑到最后一行。但现实世界的逻辑不是这样的——"如果温度超过阈值就开风扇"、"重复读取传感器数据直到收到停止命令"。控制流语句就是干这个的:让程序根据条件选择不同的执行路径(分支),或者反复执行某段逻辑(循环)。
@@ -36,7 +37,7 @@ title: 控制流:让程序学会选择和重复
3637

3738
我们接下来的所有实验都在这个环境下进行:
3839

39-
- 平台:Linux x86\_64(WSL2 也可以)
40+
- 平台:Linux x86_64(WSL2 也可以)
4041
- 编译器:GCC 13+ 或 Clang 17+
4142
- 编译选项:`-Wall -Wextra -std=c17`
4243

@@ -468,6 +469,30 @@ C++17 引入了 `if constexpr`,它在编译期评估条件,直接把不满
468469

469470
`switch` 实现一个函数,根据月份和是否闰年返回该月的天数。要求利用穿透特性合并同天数的月份。
470471

472+
### 练习 1 参考答案
473+
474+
```c
475+
int month_day(int year, int month) {
476+
switch (month) {
477+
case 1:case 3:case 5:case 7:case 8:case 10:case 12:
478+
return 31;
479+
case 4:case 6:case 9:case 11:
480+
return 30;
481+
case 2:
482+
return is_leap_year(year) ? 29 : 28;
483+
}
484+
}
485+
486+
bool is_leap_year(int year) {
487+
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0) {
488+
return true;
489+
}
490+
else {
491+
return false;
492+
}
493+
}
494+
```
495+
471496
### 练习 2:安全的矩阵搜索
472497
473498
在二维矩阵中查找目标值。找到后用两种方式跳出多层循环:一种用标志变量,一种用 `goto`。

documents/vol1-fundamentals/c_tutorials/05-function-basics.md

Lines changed: 105 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,23 @@
11
---
22
chapter: 1
33
cpp_standard:
4-
- 11
4+
- 11
55
description: 理解 C 函数的声明定义调用机制、值传递本质、指针参数、返回值策略和递归原理,为 C++ 引用传递和函数重载打好基础
66
difficulty: beginner
77
order: 7
88
platform: host
99
prerequisites:
10-
- 指针与数组、const 和空指针
10+
- 指针与数组、const 和空指针
1111
reading_time_minutes: 10
1212
tags:
13-
- host
14-
- cpp-modern
15-
- beginner
16-
- 入门
17-
- 基础
13+
- host
14+
- cpp-modern
15+
- beginner
16+
- 入门
17+
- 基础
1818
title: 函数基础与参数传递
1919
---
20+
2021
# 函数基础与参数传递
2122

2223
到现在为止我们写的代码都塞在 `main` 函数里。但现实世界的程序不会这样——一个项目动辄几万行代码,如果全挤在一个函数里,那基本没法维护。函数就是 C 语言模块化编程的基本单元:把一段逻辑封装起来,给它起个名字,需要的时候调用就行。
@@ -35,7 +36,7 @@ title: 函数基础与参数传递
3536

3637
我们接下来的所有实验都在这个环境下进行:
3738

38-
- 平台:Linux x86\_64(WSL2 也可以)
39+
- 平台:Linux x86_64(WSL2 也可以)
3940
- 编译器:GCC 13+ 或 Clang 17+
4041
- 编译选项:`-Wall -Wextra -std=c17`
4142

@@ -324,6 +325,40 @@ typedef enum { LOG_DEBUG, LOG_INFO, LOG_WARN, LOG_ERROR } LogLevel;
324325
void log_message(LogLevel level, const char* format, ...);
325326
```
326327
328+
### 练习 1 参考答案
329+
330+
```c
331+
void log_message(LogLevel level, const char* format, ...) {
332+
const char* level_str;
333+
switch (level) {
334+
case LOG_DEBUG:
335+
level_str = "DEBUG";
336+
break;
337+
case LOG_INFO:
338+
level_str = "INFO";
339+
break;
340+
case LOG_WARN:
341+
level_str = "WARN";
342+
break;
343+
case LOG_ERROR:
344+
level_str = "ERROR";
345+
break;
346+
default:
347+
level_str = "UNKNOWN";
348+
break;
349+
}
350+
printf("%s\n", level_str);
351+
352+
va_list log;
353+
va_start(log, format);
354+
355+
vprintf(format, log);
356+
printf("\n");
357+
358+
va_end(log);
359+
}
360+
```
361+
327362
### 练习 2:递归与迭代——二分查找
328363

329364
分别用递归和迭代实现二分查找,比较两者的性能和可读性:
@@ -333,6 +368,49 @@ int binary_search_recursive(const int* arr, size_t len, int target);
333368
int binary_search_iterative(const int* arr, size_t len, int target);
334369
```
335370
371+
### 练习 2 参考答案
372+
373+
```c
374+
int binary_search_recursive(const int* arr, size_t len, int target) {
375+
if (len < 1) {
376+
printf("%d is not found in index\n", target);
377+
return -1;
378+
}
379+
size_t mid = (len - 1) / 2;
380+
381+
if (arr[mid] == target) {return mid;}
382+
if (arr[mid] < target) {
383+
int res = binary_search_recursive(arr + mid + 1, len - mid - 1, target);
384+
return (res == -1) ? -1 : (res + mid + 1);
385+
}
386+
if (arr[mid] > target) {return binary_search_recursive(arr, mid , target);}
387+
return -1;
388+
}
389+
390+
int binary_search_iterative(const int* arr, size_t len, int target) {
391+
if (len < 1) {
392+
printf("%d is not found in index\n", target);
393+
return -1;
394+
}
395+
size_t low = 0;
396+
size_t high = len - 1;
397+
size_t mid = low + (high - low) / 2;
398+
while (low <= high) {
399+
if (arr[mid] == target) {return mid;}
400+
401+
if (arr[mid] < target) {
402+
low = mid + 1;
403+
}
404+
else if (arr[mid] > target) {
405+
high = mid - 1;
406+
}
407+
mid = low + (high - low) / 2;
408+
}
409+
printf("%d is not found in index\n", target);
410+
return -1;
411+
}
412+
```
413+
336414
### 练习 3:多返回值实战
337415

338416
实现一个函数,同时计算数组的最大值和最小值:
@@ -346,6 +424,25 @@ int binary_search_iterative(const int* arr, size_t len, int target);
346424
void find_min_max(const int* data, size_t len, int* min_out, int* max_out);
347425
```
348426
427+
### 练习 3 参考答案
428+
429+
```c
430+
void find_min_max(const int* data, size_t len, int* min_out, int* max_out) {
431+
if (data == NULL || min_out == NULL || max_out == NULL || len < 1) {
432+
return;
433+
}
434+
*min_out = *max_out = data[0];
435+
for (size_t i = 1; i < len; i++) {
436+
if (data[i] < *min_out) {
437+
*min_out = data[i];
438+
}
439+
if (data[i] > *max_out) {
440+
*max_out = data[i];
441+
}
442+
}
443+
}
444+
```
445+
349446
## 参考资源
350447

351448
- [cppreference: 函数声明](https://en.cppreference.com/w/c/language/function_declaration)

0 commit comments

Comments
 (0)