`

《算法之美》の链表问题のremoveHead中的缺陷

 
阅读更多

问题:

发现并修复下面C/C++函数中的缺陷,该函数是想从一个单向链表中删除头元素。

void removeHead(Node *head)

{

delete head;

head = head->next;

}

解答:缺陷发现策略:对于拿到的任何函数,考虑下面4个常见的问题:

1)检查数据是否正确地进入了该函数;

2)检查函数的每一行是否能正确工作;

3)检查该函数的输出数据是否正确;

4)检查常见的错误情况,如以指针为参数的函数在传入空指针时会失败。

函数释放了head之后,有对head进行引用,错误;我们试着将这两行颠倒位置,就会导致head之后的元素被删除,而不是head。因此正确的方法是利用一个临时变量:

void removeHead(Node *head)

{

Node *tmp = head->next;

delete head;

head = tmp;

}

现在我们进行上面策略的第三步,即确保函数返回正确的值,可以看出,这个函数尽管没有显式地返回值,但却有隐式的返回值。这个函数支持对head指针进行更新。在C语言中,所有参数都是按值传递的,所以函数会得到每一个参数的本地拷贝,而对本地拷贝的任何修改都不会对函数体之外产生影响。即上面代码第三行对head赋的任何新值都不会有效。要修复这个缺陷,我们需要一种能修改调用代码中head指针的方法。在C语言中,变量不能按引用传递,所以解决方案就是传递一个我们想修改的变量的指针,也就是head指针的指针,改动后,代码如下:

void removeHead(Node **head)

{

Node *tmp = (*head)->next;

delete *head;

*head = tmp;

}

接下来,我们检查边界条件。在只有1个元素的链表中,这个函数能正常工作,它删除了这个元素并将head指针设为了NULL。在0个元素的链表中,这个链表本身就是一个NULL指针,因此,head指针是NULL,上面代码中第一行错误地引用了NULL指针。因此,应该检查head指针是否为NULL,最终完善的函数如下:

void removeHead(Node **head)

{

Node *tmp;

if( !(*head) )

{

tmp = (*head)->next;

delete *head;

*head = tmp;

}

}

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics