有关C中链接列表的问题。假设,我们有以下结构,它们定义链表中的节点和写得错误的free_list函数,(在我看来)应该导致错误:
typedef struct node *nodeT;
typedef struct node
{
int* elem;
nodeT next;
} *nodeT;
void free_list(nodeT list)
{
nodeT node;
for (node = list; node; node = node->next)
{
free(node->elem);
free(node);
}
}
如上所述,我们将节点定义为 nodeT ,并将一个函数用于释放列表 free_list 。对我来说,明显的错误是里面的 free_list 函数我们没有一个临时指针存储节点值。
然而,当我编译代码(在Linux上),我在其中创建一个包含少量元素的链表时,程序不会崩溃,似乎一切正常。
我的问题是:是否有一种简单的方法可以证明此函数( free_list )写得不好?简单来说,我的意思是设置一些编译器标志(-Wall
没有显示任何错误)或者使用Valgrind
等工具(与memcheck
一起使用),这没有多大帮助)?
更新:根据要求提供测试用例:
int main()
{
nodeT myType;
nodeT tmpPtr;
myType = malloc(sizeof(nodeT));
myType->item = malloc(sizeof(int));
*(myType->item) = 0;
myType->next = malloc(sizeof(nodeT));
tmpPtr = myType->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 1;
tmpPtr->next = malloc(sizeof(nodeT));
tmpPtr = tmpPtr->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 2;
tmpPtr->next = malloc(sizeof(nodeT));
tmpPtr = tmpPtr->next;
tmpPtr->item = malloc(sizeof(int));
*(tmpPtr->item) = 3;
tmpPtr->next = NULL;
free_list(myType);
return 0;
}
这是Valgrind
输出:
valgrind --tool=memcheck ./a.out
...
==4318== Invalid read of size 8
==4318== at 0x400579: free_list (in /home/melon/a.out)
==4318== by 0x40069E: main (in /home/melon/a.out)
==4318== Address 0x51f1048 is 0 bytes after a block of size 8 free'd
==4318== at 0x4C2A82E: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4318== by 0x400574: free_list (in /home/melon/a.out)
==4318== by 0x40069E: main (in /home/melon/a.out)
...
答案 0 :(得分:4)
我不确定你是如何使用valgrind进行测试的,但是使用默认参数它可以很好地检测到这个问题:
==4464== Invalid read of size 8
==4464== at 0x400571: free_list (list.c:15)
==4464== by 0x4005DF: main (list.c:30)
==4464== Address 0x51e0048 is 8 bytes inside a block of size 16 free'd
==4464== at 0x4C2AD3C: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==4464== by 0x40056C: free_list (list.c:18)
==4464== by 0x4005DF: main (list.c:30)
我刚刚将其添加到程序中以使其可测试:
int main() {
nodeT head = malloc(sizeof(struct node));
nodeT node1 = malloc(sizeof(struct node));
head->next = node1;
head->elem = NULL;
node1->next = NULL;
node1->elem = NULL;
free_list(head);
return 0;
}
答案 1 :(得分:1)
在释放内存之前,您可以memset
将节点归零。然后它肯定会崩溃。
答案 2 :(得分:1)
除了代码取消引用指向已释放的内存的指针这一事实之外,您不需要任何其他证据。这是未定义的行为。调用未定义的行为是不好的。
所以有你的证明。