|
| 1 | +# 5.4.3检查函数正确性的套路 |
| 2 | + |
| 3 | +- 问题: |
| 4 | + - 找到并改正以下**C函数**中的错误,该函数的本意是从单链表中删除头元素: |
| 5 | + |
| 6 | + ```c |
| 7 | + void removeHead(ListElement* head){ |
| 8 | + free(head);// line 1 |
| 9 | + head = head->next;// line 2 |
| 10 | + } |
| 11 | + ``` |
| 12 | + |
| 13 | + - 考虑4个方面: |
| 14 | + 1. 检查数据是否正确进入函数 |
| 15 | + 1. 变量已声明。不能访问一个未声明的变量。 |
| 16 | + 2. 变量访问类型正确。不能用X类型去访问Y类型的变量。 |
| 17 | + 3. 数据足够完整。函数里应该拥有一切被需要的数据。 |
| 18 | + 2. 检查每一行代码。 |
| 19 | + 1. 验证每一行代码是否能够正确执行。 |
| 20 | + 2. 验证每一行代码的结果是否符合预期。 |
| 21 | + 3. 检查输出结果是否正确。 |
| 22 | + 1. 确保函数能够更新那些预期将被更新的变量。 |
| 23 | + 2. 确保函数的输出结果符合预期。 |
| 24 | + 4. 检查常见错误。 |
| 25 | + 1. 是否考虑了传入参数为空值的情况。 |
| 26 | + 2. 是否考虑了操作失败的情况。比如涉及到内存分配和I/O操作。 |
| 27 | + - 解题: |
| 28 | + 1. 检查数据是否正确进入函数 |
| 29 | + 1. 在链表中,只要给定头指针,就能访问每一个元素。所以需要的数据都可以访问。 |
| 30 | + 2. 检查每一行代码 |
| 31 | + 1. line1释放了head,这样来看是对的 |
| 32 | + 2. line2为head分配了一个新值head→next,但head已经在line1行被释放。 |
| 33 | + 3. 为解决此问题,使用一个临时变量来存储head→next,然后释放head,并使用临时变量来更新head |
| 34 | + |
| 35 | + ```c |
| 36 | + void removeHead(ListElement* head){ |
| 37 | + ListElement *temp = head->next;// line 1 |
| 38 | + free(head);// line 2 |
| 39 | + head = temp;// line 3 |
| 40 | + } |
| 41 | + ``` |
| 42 | + |
| 43 | + 3. 检查输出结果 |
| 44 | + 1. 已知: |
| 45 | + 1. 在C语言中,所有函数参数按值传递,所以在函数内部中对某个值的修改不会影响到函数外部到原始变量。 |
| 46 | + 2. 在C语言中,变量不能按引用传递。 |
| 47 | + 3. 因此,当你需要在函数内部修改函数外部的变量时,需要向函数传递一个指向变量的指针,以便通过该指针来修改变量的值。 |
| 48 | + |
| 49 | + ```c |
| 50 | + void removeHead(ListElement** head){ |
| 51 | + ListElement *temp = (*head)->next;// line 1 |
| 52 | + free(*head);// line 2 |
| 53 | + *head = temp;// line 3 |
| 54 | + } |
| 55 | + ``` |
| 56 | + |
| 57 | + 4. 检查错误条件 |
| 58 | + 1. 若head传入的是空,则line 1会出错。 |
0 commit comments