【发布时间】:2021-02-28 21:11:59
【问题描述】:
我试图弄清楚为什么当我故意避免释放内存时valgrind 没有检测到任何错误。我有这个小程序。它从键盘读取数字并打印消息You've entered <number>!。如果之前读取过该号码,则打印You've already read <number>!。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct node {
int number;
struct node* next;
};
struct node* add(struct node* head, int number) {
struct node* n;
struct node* p;
n = (struct node*)malloc(sizeof(struct node));
n->number = number;
n->next = NULL;
if (head == NULL) {
return n;
}
p = head;
while (p->next != NULL) {
p = p->next;
}
p->next = n;
return head;
}
void clear(struct node* head) {
if (head == NULL) {
return;
}
clear(head->next);
free(head);
}
int already_read(struct node* head, int number) {
struct node* p;
if (head == NULL) {
return 0;
}
p = head;
while (p!=NULL && p->number!=number) {
p = p->next;
}
if (p == NULL) {
return 0;
}
return 1;
}
int main(int argc, char** argv) {
int number;
struct node* head = NULL;
while (scanf("%d", &number) == 1) {
if (already_read(head, number)) {
printf("You've already entered %d!\n", number);
}
else {
head = add(head, number);
printf("You entered %d!\n", number);
}
}
clear(head);
return 0;
}
我使用 gcc 编译它(这个文件在我的系统上称为program.c,所以我使用了命令gcc -Wall -g -o program program.c)。它编译得很好。然后,当我使用 valgrind (valgrind ./program) 运行它时,我输入一些数字以查看程序是否正常工作,然后我使用 CTRL-C 停止它。我没有错误。太好了。
LEAK SUMMARY:
definetely lost: 0 bytes in 0 blocks
indirectly lost: 0 bytes in 0 blocks
possibly lost: 0 bytes in 0 blocks
still reachable: 64 bytes in 4 blocks
suppressed: 0 bytes in 0 blocks
ERROR SUMMARY: 0 errors from 0 context (suppressed: 8 from 6)
然后我回到代码中。我保持原样,除了我将main() 中的行更改为clear(head) 为//clear(head)。所以现在程序不再释放空间了。它有泄漏。我用valgrind 重新编译并再次运行它。我输入与以前相同的输入。而且...我得到相同的错误报告。和上面那个完全一样。我不明白为什么会这样。它不应该报告内存泄漏,因为我没有释放内存吗?我做错了吗?
【问题讨论】:
-
clear(head);出现在return 0;之前,此时所有分配的内存都被释放并自动返回给操作系统。这可能就是 Valgrind 没有报告内存泄漏的原因。 没有。 -
如果您在等待输入时
Ctrl-C则永远不会调用clear(),因此它是否存在无关紧要。如果它确实被调用(例如,如果您以Ctrl-D结束文件),那么它会无限递归并崩溃。 -
如果
clear没有被调用,那么你的内存仍然可以访问。valgrind不会将此视为泄漏;它假定您需要该内存直到程序结束,并且依赖它在退出时自动释放。如果这不是您的理念,那么您可以将“仍然可访问”条目解释为泄漏。 -
顺便说一句,显示的代码无法编译。它在
already_read中缺少p声明。clear函数也没有意义——它会导致堆栈溢出和/或其他未定义的行为,因为它使用相同的指针值无限递归地调用自身。 -
跟进最后一条消息,您需要复制并粘贴您正在编译和运行的确切代码。重新输入的近似值还不够好。