内存泄漏与C中的嵌套结构类型和复制函数

时间:2015-02-27 11:56:16

标签: c struct nested malloc free

我遇到嵌套结构及其专用复制功能的问题。类型的结构如下:

  1. 程序中有一个Data个实例
  2. 每个Problem实例都包含指向Data实例
  3. 的指针
  4. 每个Bigproblem实例都有自己的Problem实例。
  5. 因此,当复制BigProblem实例时,也会生成Problem实例的副本。代码如下:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    // types
    
    struct Data {
        int n;
        int *x;
    };
    typedef struct Data data_t;
    
    struct Problem {
        data_t *data;
        int m;
        int *y;
    };
    typedef struct Problem problem_t;
    
    struct BigProblem {
        problem_t *prob;
        int p;
        int *z;
    };
    typedef struct BigProblem big_t;
    
    // functions
    
    data_t init_data(int s)
    {
        data_t dat;
        dat.n = s;
        dat.x = calloc(s, sizeof(int));
        return dat;
    }
    
    problem_t init_problem(data_t *dat)
    {
        problem_t prob;
        prob.data = dat;
        prob.m = 5;
        prob.y = calloc(prob.data->n, sizeof(int));
        return prob;
    }
    
    problem_t copy_problem(problem_t *prob)
    {
        int i;
        problem_t probc;
        probc.data = prob->data;
        probc.m = prob->m;
        probc.y = calloc(prob->data->n, sizeof(int));
        for (i=0; i<prob->data->n; i++)
            probc.y[i] = prob->y[i];
        return probc;
    }
    
    big_t init_bigproblem(problem_t *prob)
    {
        big_t bigprob;
        bigprob.prob = prob;
        bigprob.p = 3;
        bigprob.z = calloc(prob->m, sizeof(int));
        return bigprob;
    }
    
    big_t copy_bigproblem(big_t *bigprob)
    {
        int i;
        big_t bigprobc;
        problem_t probc = copy_problem(bigprob->prob);
        bigprobc.prob = &probc;
        bigprobc.p = bigprob->p;
        bigprobc.z = calloc(bigprob->prob->m, sizeof(int));
        for (i=0; i<bigprob->prob->m; i++)
            bigprobc.z[i] = bigprob->z[i];
        return bigprobc;
    }
    
    void free_data(data_t *dat)
    {
        free(dat->x);
    }
    
    void free_problem(problem_t *prob)
    {
        free(prob->y);
    }
    
    void free_bigproblem(big_t *bigprob)
    {
        free(bigprob->z);
        free_problem(bigprob->prob);
    }
    
    int main(int argc, char **argv)
    {
        data_t mydata = init_data(10);
        problem_t myproblem = init_problem(&mydata);
        big_t mybigprob = init_bigproblem(&myproblem);
    
        big_t big_copy = copy_bigproblem(&mybigprob);
    
        free_bigproblem(&mybigprob);
        free_bigproblem(&big_copy);
        free_data(&mydata);
    
        return 0;
    }
    

    我怀疑问题与copy_bigproblem中的这些行有关:

        problem_t probc = copy_problem(bigprob->prob);
        bigprobc.prob = &probc;
    

    但我无法确切地指出这里究竟出了什么问题。 Valgrind建议在prob中释放free_bigproblem变量时会出现问题,但如果正确复制Problem实例则不会发生这种情况。 Valgrind输出在这里:

    ==10384== Memcheck, a memory error detector
    ==10384== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al.
    ==10384== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info
    ==10384== Command: ./typedeftest
    ==10384== 
    ==10384== Conditional jump or move depends on uninitialised value(s)
    ==10384==    at 0x4C2B1B6: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==10384==    by 0x4007D4: free_problem (typedeftest.c:97)
    ==10384==    by 0x400801: free_bigproblem (typedeftest.c:103)
    ==10384==    by 0x400879: main (typedeftest.c:115)
    ==10384==  Uninitialised value was created by a stack allocation
    ==10384==    at 0x4007B9: free_problem (typedeftest.c:96)
    ==10384== 
    ==10384== Invalid free() / delete / delete[] / realloc()
    ==10384==    at 0x4C2B200: free (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==10384==    by 0x4007D4: free_problem (typedeftest.c:97)
    ==10384==    by 0x400801: free_bigproblem (typedeftest.c:103)
    ==10384==    by 0x400879: main (typedeftest.c:115)
    ==10384==  Address 0x400f610 is in the Text segment of /usr/lib/ld-2.21.so
    ==10384==    at 0x400F610: _dl_fini (in /usr/lib/ld-2.21.so)
    ==10384== 
    ==10384== 
    ==10384== HEAP SUMMARY:
    ==10384==     in use at exit: 40 bytes in 1 blocks
    ==10384==   total heap usage: 5 allocs, 5 frees, 160 bytes allocated
    ==10384== 
    ==10384== 40 bytes in 1 blocks are definitely lost in loss record 1 of 1
    ==10384==    at 0x4C2C080: calloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
    ==10384==    by 0x40061A: copy_problem (typedeftest.c:58)
    ==10384==    by 0x400704: copy_bigproblem (typedeftest.c:81)
    ==10384==    by 0x400861: main (typedeftest.c:112)
    ==10384== 
    ==10384== LEAK SUMMARY:
    ==10384==    definitely lost: 40 bytes in 1 blocks
    ==10384==    indirectly lost: 0 bytes in 0 blocks
    ==10384==      possibly lost: 0 bytes in 0 blocks
    ==10384==    still reachable: 0 bytes in 0 blocks
    ==10384==         suppressed: 0 bytes in 0 blocks
    ==10384== 
    ==10384== For counts of detected and suppressed errors, rerun with: -v
    ==10384== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)
    

    非常感谢任何帮助。

1 个答案:

答案 0 :(得分:1)

我做了一些小改动 想想memcpy而不是循环

#include <stdio.h>                                                             
#include <stdlib.h>                                                            
#include <string.h>                                                            

// types                                                                       

struct Data {                                                                  
    int n;                                                                     
    int *x;                                                                    
};                                                                             
typedef struct Data data_t;                                                    

struct Problem {                                                               
    data_t *data;                                                              
    int m;                                                                     
    int *y;                                                                    
};                                                                             
typedef struct Problem problem_t;                                              

struct BigProblem {                                                            
    problem_t prob;                                                            
    int p;                                                                     
    int *z;                                                                    
};                                                                             
typedef struct BigProblem big_t;                                               

// functions                                                                   

void init_data(data_t *dat, int s)                                             
{                                                                              
    dat->n = s;                                                                
    dat->x = calloc(s, sizeof(int));                                           
}                                                                              

void init_problem(problem_t *prob, data_t *dat)                                
{                                                                              
    prob->data = dat;                                                          
    prob->m = 5;                                                               
    prob->y = calloc(prob->data->n, sizeof(int));                              
}                                                                              

void init_bigproblem(big_t *bigprob, problem_t *prob)                          
{                                                                              
    bigprob->prob = *prob;                                                     
    bigprob->p = 3;                                                            
    bigprob->z = calloc(prob->m, sizeof(int));                                 
}

copy_problem(problem_t *src, problem_t *cpy)                                   
{                                                                              
    int i;                                                                     
    cpy->data = src->data;                                                     
    cpy->m = src->m;                                                           
    cpy->y = calloc(src->data->n, sizeof(int));                                
    for (i=0; i<src->data->n; i++)                                             
        cpy->y[i] = src->y[i];                                                 
}                                                                              

void copy_bigproblem(big_t *src, big_t *cpy)                                   
{                                                                              
    int i;                                                                     

    copy_problem(&src->prob, &cpy->prob);                                      
    cpy->p = src->p;                                                           
    cpy->z = calloc(src->prob.m, sizeof(int));                                 
    for (i=0; i<src->prob.m; i++)                                              
        cpy->z[i] = src->z[i];                                                 
}                                                                              

void free_data(data_t *dat)                                                    
{                                                                              
    free(dat->x);                                                              
}                                                                              

void free_problem(problem_t *prob)                                             
{                                                                              
    free(prob->y);                                                             
}                                                                              

void free_bigproblem(big_t *bigprob)                                           
{                                                                              
    free(bigprob->z);                                                          
    free_problem(&bigprob->prob);                                              
}                                                                              

int main(int argc, char **argv)                                                
{                                                                              
    data_t mydata;                                                             
    problem_t myproblem;                                                       
    big_t mybigprob, big_copy;                                                 

    init_data(&mydata, 10);                                                    
    init_problem(&myproblem, &mydata);                                         
    init_bigproblem(&mybigprob, &myproblem);                                   

    copy_bigproblem(&mybigprob, &big_copy);                                    


    free_bigproblem(&mybigprob);                                               
    free_bigproblem(&big_copy);                                                
    free_data(&mydata);                                                        

    return 0;                                                                  
}