首页 > 解决方案 > 无法从 valgrind 跟踪内存问题

问题描述

我一直在试图找出我做错了什么,但我认为我在导致内存问题的代码中存在不止一个问题。我已经评论了我能够跟踪的部分。我认为我在指针方面存在一些问题,在哪里使用什么,也许还有其他一些小问题。

我的主要代码

     int main(int argc, char ** argv){
        printf("In Main\n");
        if(argc != 7){
            printf("args doesn't match expected value\n");
            return EXIT_FAILURE;
        }
        FILE *fptr = fopen(argv[1], "rb");
        if(fptr == NULL){
            return EXIT_FAILURE;
        }
        long int size_compressed; //size_compressed: Number of bytes in compressed file
        long int size_topology;   //size_topology: Number of bytes topology uses
        long int size_original;   //size_original: Number of bytes in the uncompressed file
    
        fread(&size_compressed, sizeof(long int) , 1, fptr);
        fread(&size_topology, sizeof(long int), 1, fptr);
        fread(&size_original, sizeof(long int), 1, fptr);
        int size = sizeof(char)* sizeof(long int) * size_topology;
    
        printf("Size Compressed: %ld\n", size_compressed);
        printf("Size Topology: %ld\n", size_topology);
        printf("Size Original: %ld\n", size_original);
        
        unsigned char *buffer;
        int *val; 
        buffer = (unsigned char*) malloc(sizeof(unsigned char) * size_topology);
        size_t bytes_read = fread(buffer, sizeof(unsigned char), size_topology, fptr);
        //val = (int*) malloc(sizeof(int) * (size_topology));
        val = (int*) malloc(size);
        fclose(fptr);
    
        if(bytes_read != size_topology){
            printf("Topology size and read bytes don't match!");
        }
    
        for(int i=0; i < size_topology; i++){
          val[i] = buffer[i];
        }
    
        char *toVal; //toVal: char array of 8 to store every bit of a byte
        char *all_topology;  //all_topology: char array of 8 * size_topology to store ALL bits of topology. 
        int j; //j: index for all_topology
        // toVal = (char*) malloc(sizeof(char)* sizeof(int));
        // all_topology = (char*) malloc(size);
        toVal = (char*) malloc(size);
        all_topology = (char*) malloc(size);
    
        //For Loop where conversion of the bytes in val to bits happen, output is stored in all_topology 
        for(int i=0; i < size_topology; i++){
            j = i*8;
            byte_to_bits(val[i], toVal);
            for(int k=0; k< 8;k++){
                all_topology[j] = toVal[k];
                printf("%d", all_topology[j]);
                j++;
            }
            printf("\n");
        }
        //no memory issues up to here

    Snode* stack = NULL;
    int numOfBytes = byte_to_char(all_topology, &stack, size);
    Tnode* tmp = NULL;
    while(1){
        if(isEmpty(stack)){
            break;
        } else{
            tmp = pop(&stack);
        }
    }
    remove_zeroes(stack);
    printf("NumOfBYtes: %d\n", numOfBytes);
    Tnode* node;
    Snode* reverse_stack;
    int flag = 1;
    while(flag){
        node = pop(&stack);
        if(node == NULL){
            break;
        }
        printf("%c\n", node->id);
        push(&reverse_stack, node); 
    }
    // printf("\n");


    // Snode* tmp = reverse_stack;
    // while(reverse_stack != NULL){
    //     char a = peek(&tmp);
    //     printf("%c", a);
    //     tmp = tmp->next;
    // }
    // printf("\n");

    // Topolgy created in the same format as pg6 line1. into stack "reverse_stack"
    // Lots of memory errors and memory lost
    // Still need to build tree



    //free(node);
    free(all_topology);
    free(toVal);
    // free(node);
    free(buffer);
    free(val);
    return EXIT_SUCCESS;
}

Valgrind 输出

==10990== 
==10990== HEAP SUMMARY:
==10990==     in use at exit: 552 bytes in 23 blocks
==10990==   total heap usage: 53 allocs, 30 frees, 1,778 bytes allocated
==10990== 
==10990== Searching for pointers to 23 not-freed blocks
==10990== Checked 70,128 bytes
==10990== 
==10990== 168 bytes in 7 blocks are definitely lost in loss record 1 of 3
==10990==    at 0x4C2C089: calloc (vg_replace_malloc.c:762)
==10990==    by 0x400D53: createNode (tree.c:9)
==10990==    by 0x400868: byte_to_char (pa2.c:46)
==10990==    by 0x400C4A: main (pa2.c:152)
==10990== 
==10990== 192 bytes in 8 blocks are definitely lost in loss record 2 of 3
==10990==    at 0x4C2C089: calloc (vg_replace_malloc.c:762)
==10990==    by 0x400D53: createNode (tree.c:9)
==10990==    by 0x40089B: byte_to_char (pa2.c:52)
==10990==    by 0x400C4A: main (pa2.c:152)
==10990== 
==10990== 192 bytes in 8 blocks are definitely lost in loss record 3 of 3
==10990==    at 0x4C2C089: calloc (vg_replace_malloc.c:762)
==10990==    by 0x400D53: createNode (tree.c:9)
==10990==    by 0x400941: byte_to_char (pa2.c:69)
==10990==    by 0x400C4A: main (pa2.c:152)
==10990== 
==10990== LEAK SUMMARY:
==10990==    definitely lost: 552 bytes in 23 blocks
==10990==    indirectly lost: 0 bytes in 0 blocks
==10990==      possibly lost: 0 bytes in 0 blocks
==10990==    still reachable: 0 bytes in 0 blocks
==10990==         suppressed: 0 bytes in 0 blocks
==10990== 
==10990== ERROR SUMMARY: 3 errors from 3 contexts (suppressed: 0 from 0)

基于valgrind的输出,我还添加了下面错误中提到的功能。

byte_to_char

int byte_to_char(char *topology, Snode** stack, int size){
    int numOfBytes = 0;
    char ascii_concat[8]; 
    unsigned char ascii_val = 0;  
    int countChar =0;
    Tnode* node;
    //char char_top[80];
    for(int i=0; i < size; i++){
        if(topology[i] == 0){
            //char_top[i] = 48; //ASCII Value of 0
            node = createNode(48, 0);
            push(stack, node);
            numOfBytes++;
        } else{
            ascii_val = 0xff;
            //char_top[i] = 49; //ASCII Value of 1
            node = createNode(49, 1);
            push(stack, node);
            numOfBytes++;
            i++; //skip the leaf node indicator
            countChar++;  
            for(int j=0; j<8; j++){
                ascii_concat[j] = topology[i++];
            }
            i--;
            for(int j=0; j<8; j++){
                if(ascii_concat[j] == 0){
                    ascii_val = (1 << (j)) ^ ascii_val;
                }
            }
            //printf("%c\n", ascii_val);
            //Create leaf node
            //char_top[i] = ascii_val;
            node = createNode(ascii_val, 2);
            push(stack, node);
            numOfBytes = numOfBytes+8;
            //count characters in header
        }
        countChar++;
    }

    // printf("chars\n");
    // for(int i=0;i < 24; i++){
    //    printf("%c", char_top[i]);
    // }
    free(node);
    return numOfBytes;
    
}

创建节点

Tnode *createNode(int key, int bal)
{
    Tnode *n = (Tnode *)calloc(1, sizeof(Tnode));
    //Tnode *n = (Tnode*) malloc(sizeof(Tnode));
    n->key = key;
    n->balance = bal;
    n->left = NULL;  //?
    n->right = NULL; //?
    return n;
}

标签: cmemoryvalgrind

解决方案


在 for 循环中的函数 byte_to_char 中,您在调用 createNode 函数时分配了 3 次内存。但是这个内存永远不会被释放,所以 valgrind 会发出内存泄漏的信号。您必须在循环中释放节点变量,否则每次更改指针的值时都会丢失地址并且您将无法释放内存。

因为你不能在循环中释放,也许你应该发送你的节点的副本,然后释放你的节点变量

Tnode *my_duplicate_node(const Tnode *src)
{
    Tnode *dest = calloc(sizeof(Tnode), 1);

    memcpy(dest, src, sizeof(Tnode));
    return dest;
}

for(int i=0; i < size; i++){
    if(topology[i] == 0){
        node = createNode(48, 0);
        push(stack, my_duplicate_node(node));
        free(node);
    } else{
        [...]
        node = createNode(49, 1);
        push(stack, my_duplicate_node(node));
        free(node);
    }
}

它不存在为结构复制内存块的任何函数,因此您可以尝试类似 my_duplicate_node 函数


推荐阅读