Skip to content

Latest commit

 

History

History
68 lines (61 loc) · 3.03 KB

5.4.3检查函数正确性的套路.md

File metadata and controls

68 lines (61 loc) · 3.03 KB

5.4.3检查函数正确性的套路

  • 问题:

    • 找到并改正以下C函数中的错误,该函数的本意是从单链表中删除头元素:
    void removeHead(ListElement* head){
    	free(head);// line 1
    	head = head->next;// line 2
    }
    • 考虑4个方面:
      1. 检查数据是否正确进入函数
        1. 变量已声明。不能访问一个未声明的变量。
        2. 变量访问类型正确。不能用X类型去访问Y类型的变量。
        3. 数据足够完整。函数里应该拥有一切被需要的数据。
      2. 检查每一行代码。
        1. 验证每一行代码是否能够正确执行。
        2. 验证每一行代码的结果是否符合预期。
      3. 检查输出结果是否正确。
        1. 确保函数能够更新那些预期将被更新的变量。
        2. 确保函数的输出结果符合预期。
      4. 检查常见错误。
        1. 是否考虑了传入参数为空值的情况。
        2. 是否考虑了操作失败的情况。比如涉及到内存分配和I/O操作。
    • 解题:
      1. 检查数据是否正确进入函数

        1. 在链表中,只要给定头指针,就能访问每一个元素。所以需要的数据都可以访问。
      2. 检查每一行代码

        1. line1释放了head,这样来看是对的

        2. line2为head分配了一个新值head→next,但head已经在line1行被释放。

        3. 为解决此问题,使用一个临时变量来存储head→next,然后释放head,并使用临时变量来更新head

          void removeHead(ListElement* head){
          	ListElement *temp = head->next;// line 1
          	free(head);// line 2
          	head = temp;// line 3
          }
      3. 检查输出结果

        1. 已知:

          1. 在C语言中,所有函数参数按值传递,所以在函数内部中对某个值的修改不会影响到函数外部到原始变量。
          2. 在C语言中,变量不能按引用传递。
          3. 因此,当你需要在函数内部修改函数外部的变量时,需要向函数传递一个指向变量的指针,以便通过该指针来修改变量的值。
          void removeHead(ListElement** head){
          	ListElement *temp = (*head)->next;// line 1
          	free(*head);// line 2
          	*head = temp;// line 3
          }
      4. 检查错误条件

        1. 若head传入的是空,则line 1会出错。
        void removeHead(ListElement** head){
        	if(head && *head){
        		ListElement *temp = (*head)->next;// line 1
        		free(*head);// line 2
        		*head = temp;// line 3
        	}
        }
      现在可以宣布调试完成。