C 二叉树示例 Valgrind 分析
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct node { char *question; //提问 struct node *no; //不是嫌犯,创建一个新的节点 struct node *yes; //是嫌犯,创建一个新的节点 }node; //判断用户输入的是不是yes int yes_no(char *question){ char answer[3]; //自定义指定长度的字符数组 printf("%s?(y/n):",question); fgets(answer,3,stdin); //从字符输入设备标准输入流中获取输入的字符保存到字符数组中 return answer[0] == 'y'; //返回是不是‘y’是y返回1 不是返回0 } //创建一个节点 node *create(char *question){ node *n = malloc(sizeof(node)); //创建节点,分配内存 n->question = strdup(question); //持久化复制数据 n->no = NULL; n->yes = NULL; return n; } //释放堆里面创建的空间 void release(node *n){ if(n){ if(n->no){ release(n->no); //还存在节点重新调用release } if(n->yes){ release(n->yes);//还存在节点 重新调用release } if(n->question){ free(n->question);//地址固定 直接free } free(n);//释放当前节点创建的空间 } } int main(int argc,char ** argv){ char question[80]; char suspect[20]; node *start_node = create("Does suspect have the mustache?"); start_node->no = create("Loretta Barnsworth"); start_node->yes = create("Vinny the Spoon"); node *current; //是yes创建的节点 还是no创建的节点 do{ current = start_node; while(1){ //loop if(yes_no(current->question)){ if(current->yes){ current = current->yes; }else{ printf("SUSPECT IDENTIFIED\n"); break; //确认嫌疑人退出循环 } }else if(current->no){ current = current->no; }else{ printf("Who's the suspect?"); fgets(suspect,20,stdin); node *yes_node = create(suspect); current->yes = yes_node; //make the no-node a copy of this question node *no_node = create(current->question); printf("Give me a question that is TRUE for %s but for %s?",suspect,current->question); fgets(question,80,stdin); current->question = strdup(question); break; } } }while(yes_no("Run again")); release(start_node); return 0; }
Valgrind 程序分析如下:
==28885== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==28885== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==28885== Command: ./2019031102 ==28885== Does suspect have the mustache??(y/n):n Loretta Barnsworth?(y/n):n Who's the suspect?wangpeng Give me a question that is TRUE for wangpeng but for Loretta Barnsworth?caf Run again?(y/n):n ==28885== ==28885== HEAP SUMMARY: ==28885== in use at exit: 62 bytes in 3 blocks //62字节的数据保留在堆上 ==28885== total heap usage: 11 allocs, 8 frees, 221 bytes allocated //11次分配内存 8次释放 总共分配了221字节的数据 ==28885== ==28885== 19 bytes in 1 blocks are definitely lost in loss record 2 of 3 ==28885== at 0x4C28BBD: malloc (vg_replace_malloc.c:296) ==28885== by 0x4EBA889: strdup (in /usr/lib64/libc-2.17.so) ==28885== by 0x40074D: create (in /home/learn/c/2019031102) ==28885== by 0x40081B: main (in /home/learn/c/2019031102) ==28885== ==28885== 43 (24 direct, 19 indirect) bytes in 1 blocks are definitely lost in loss record 3 of 3 ==28885== at 0x4C28BBD: malloc (vg_replace_malloc.c:296) ==28885== by 0x40073D: create (in /home/learn/c/2019031102) ==28885== by 0x4008F3: main (in /home/learn/c/2019031102) ==28885== ==28885== LEAK SUMMARY: ==28885== definitely lost: 43 bytes in 2 blocks ==28885== indirectly lost: 19 bytes in 1 blocks ==28885== possibly lost: 0 bytes in 0 blocks ==28885== still reachable: 0 bytes in 0 blocks ==28885== suppressed: 0 bytes in 0 blocks ==28885== ==28885== For counts of detected and suppressed errors, rerun with: -v ==28885== ERROR SUMMARY: 2 errors from 2 contexts (suppressed: 6 from 6)
分析问题:
1.有几条数据留在了堆上?
二条
2.哪条数据留在了堆上?
strdup ,create
3.哪一行或哪几行代码导致了泄漏?
296
4.如何修复泄漏?
//创建了不是嫌疑人的节点 但是没有添加到新的二叉树节点里面去 导致数据留在了堆上
current->no = no_node;
//current->question 已经存在 没有释放 重新释放就可以了
free(current->question);
修复问题后
[root@VM_0_9_centos c]# valgrind --leak-check=full ./2019031102 ==32000== Memcheck, a memory error detector ==32000== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. ==32000== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info ==32000== Command: ./2019031102 ==32000== Does suspect have the mustache??(y/n):n Loretta Barnsworth?(y/n):n Who's the suspect?n^H Give me a question that is TRUE for n but for Loretta Barnsworth?n Run again?(y/n):n ==32000== ==32000== HEAP SUMMARY: ==32000== in use at exit: 0 bytes in 0 blocks ==32000== total heap usage: 11 allocs, 11 frees, 213 bytes allocated ==32000== ==32000== All heap blocks were freed -- no leaks are possible ==32000== ==32000== For counts of detected and suppressed errors, rerun with: -v ==32000== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 6)
Valgrind 如何拦截malloc()和free()?
malloc()和free()包含在C标准库中,而valgrind有一个库,里面
有它自己的malloc()与free()。当用valgrind运行程序时,程序会使用
valgrind的函数,而不是C标准库中的函数。
为什么编译器在编译代码时不默认包含调试信息?
因为调试信息会使可执行文件变大,同时也可能让程序变得更
慢。
valgrind这个名字的由来是什么?
valgrind是英灵殿 ① 入口的名字,而valgrind(程序)为你打开
了一扇通向计算机堆的大门。
注释:① 北欧神话中,死亡之神奥丁用来款待阵亡将士英灵的殿
堂。
valgrind可以检查存储器泄漏。valgrind通过拦截对malloc()与free()的调用来工作。
程序在停止运行时,valgrind会打印留在堆上数据的详细信息。
编译代码时,如果在可执行文件中加上调试信息,valgrind可以提供更多信息。
多次运行程序可以缩小泄漏的范围。
valgrind可以告诉你源文件的哪行代码把数据放到了堆上。
valgrind可以用来检验泄漏是否已修复