首页 > 技术文章 > C 二叉树示例 Valgrind 分析

wpgraceii 2019-03-11 11:05 原文

#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可以用来检验泄漏是否已修复

推荐阅读