Search code examples
cstructurerealloc

Realloc not working in my program, any ideas why?


I am trying to write a program that is going to use the Huffman algorithm to create a dictionary to compress a text file. I am having some problems regarding realloc. My program works just fine, but valgrind reports a lot of errors regarding realloc. I tried writing my own and using the function but nothing works. Any ideas?

If you want to check the output you have to do it like "-o 1 -f read.txt -v"

read.txt could be a any text file that has words that are in ASCII table

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

const int expand_size = 4;
int length = 4;

typedef struct {
    char w[2]; //word
    int v; //value
    int d; //direction
    char b; //binary
} node_t;

int maxi(node_t * huff, int n) {
    int maxi = huff[0].v;
    for (int i = 0; i < n; i++)
        if (huff[i].v > maxi) {
            maxi = huff[i].v;
        }
    return maxi;
}

int mini(node_t * huff, int n) {
    int mini = maxi(huff, n);
    int w = 0;
    for (int i = 0; i < n; i++)
        if (huff[i].v <= mini && huff[i].v >= 0) {
            w = i;
            mini = huff[i].v;
        }
    return w;
}

node_t * realoc(node_t * huff) {
    node_t * temp = realloc(huff, (length + expand_size) * sizeof(node_t));
    return temp;
}

int huffman(node_t * huff, int n) {
    int j = 1;
    int i = 1;

    int index1;
    int index2;
    int value1;
    int value2;

    while (i != n) {
        index1 = mini(huff, n);
        value1 = huff[index1].v;
        huff[index1].v = -1;
        index2 = mini(huff, n);
        value2 = huff[index2].v;
        huff[index2].v = -1;

        huff[index1].d = n;
        huff[index2].d = n;

        huff[index1].b = '1';
        huff[index2].b = '0';

        if (n == length) {
            node_t * temp;
            temp = realoc(huff);
            huff = temp;
            for (int h = length; h < length + expand_size; h++) {
                huff[h].v = 0;
            }
            length += expand_size;
        }

        huff[n].v = value1 + value2;
        huff[n].w[0] = j + '0';
        j++;
        i = i + 2;
        n++;

    }
    return n;
}

int main(int argc, char ** argv) {
    int n;
    ///reading from a file///
    FILE * read;
    char word[2];
    char c;

    ///getopt parimeters///
    int opt;
    char * file = NULL;
    char steps = 0;
    char compression_level = 0;

    ///getopt///
    while ((opt = getopt(argc, argv, "o:f:v")) != -1) {
        switch (opt) {

        case 'f':
            file = optarg;
            break;

        case 'v':
            steps = 1;
            break;

        case 'o':
            compression_level = atof(optarg);
            break;

        case '?':
            printf("Złe parametry wywołania");
            return 1;
            break;
        }
    }

    read = fopen(file, "r");

    node_t * huff = malloc(sizeof(node_t) * (length));

    int counter = 0; ///how many nodes are in the table (nodes from the file not the ones that we create with huffman algorithm)

    for (int i = 0; i < length; i++)
        huff[i].v = 0;

    if (read == NULL) {
        printf("file can't be opened \n");
        return 1;
    }

    if (compression_level == 1) {
        while ((c = fgetc(read)) != EOF) {
            for (int i = 0; i < length; i++) {
                if (huff[i].v == 0) {
                    huff[i].w[0] = c;
                    huff[i].v++;
                    counter++;
                    break;
                }
                if (huff[i].w[0] == c) {
                    huff[i].v++;
                    break;
                }
                if (i == length - 1) {
                    node_t * temp;
                    temp = realoc(huff);
                    huff = temp;
                    for (int j = length; j < length + expand_size; j++) {
                        huff[j].v = 0;
                        //huff[j].w[0] = ' ';
                    }
                    length += expand_size;
                }
            }
        }
    }

    n = huffman(huff, counter);

    ///printing the table///

    int l;
    for (int i = 0; i < counter; i++) {
        l = i;

        if (compression_level == 1)
            printf("%c: ", huff[i].w[0]);

        if (compression_level == 2)
            printf("%c%c: ", huff[i].w[0], huff[i].w[1]);

        while (l != n - 1) {
            printf("%c", huff[l].b);
            l = huff[l].d;
        }
        printf("\n");
    }

    if (steps == 1) {
        for (int i = 0; i < counter; i++) {
            if (huff[i].w[0] == 10)
                printf("'%d' 'LINE FEED' occured %d razy\n", huff[i].w[0], huff[i].v);
            //else printf("'%d' '%s' wystapilo %d razy\n", huff[i].w, huff[i].w, huff[i].v);
        }
        printf("array length %d\n", length);
        printf("how many nodes %d\n", n);
        printf("how many primary nodes %d\n", counter);
        //printf("v = %d, o = %d\n", steps, compression_level);
    }
    free(huff);
    fclose(read);
    return 0;
}

Solution

  • In your function int huffman(node_t *huff, int n) you try to realloc() the huff pointer but in C we pass variables by value so you only receive a copy of the pointer. This means caller retains the original pointer and the realloc() memory is lost when you return from the function. You need to pass in a **huff:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h>
    
    const int expand_size = 4;
    int length = 4;
    
    typedef struct {
        char w[2]; //word
        int v; //value
        int d; //direction
        char b; //binary
    } node_t;
    
    int maxi(node_t *huff, int n) {
        int maxi = huff[0].v;
        for(int i=0;i<n;i++)
            if(huff[i].v>maxi)
                maxi=huff[i].v;
        return maxi;
    }
    
    int mini(node_t *huff, int n) {
        int mini = maxi(huff, n);
        int w=0;
        for(int i=0;i<n;i++)
            if(huff[i].v<=mini && huff[i].v >=0){
                w=i;
                mini=huff[i].v;
            }
        return w;
    }
    
    int huffman(node_t **huff, int n){
        int j=1;
        int i=1;
        while (i!=n){
            int index1=mini(*huff, n);
            int value1=(*huff)[index1].v;
            (*huff)[index1].v=-1;
            int index2=mini(*huff, n);
            int value2=(*huff)[index2].v;
            (*huff)[index2].v=-1;
            (*huff)[index1].d = n;
            (*huff)[index2].d = n;
            (*huff)[index1].b = '1';
            (*huff)[index2].b = '0';
            if ( n == length ){
                node_t *temp = realloc(*huff, (length + expand_size) * sizeof *temp);
                if(!temp) {
                    printf("realloc failed\n");
                    exit(1);
                }
                *huff=temp;
                for ( int h = length; h < length + expand_size; h++){
                    (*huff)[h].v = 0;
                }
                length += expand_size;
            }
            (*huff)[n].v=value1 + value2;
            (*huff)[n].w[0]=j+'0';
            j++;
            i=i+2;
            n++;
        }
        return n;
    }
    
    int main( int argc, char** argv) {
        int opt;
        char *file = NULL;
        char steps = 0;
        char compression_level = 0;
        while ((opt = getopt (argc, argv, "o:f:v")) != -1) {
            switch (opt) {
                case 'f':
                    file = optarg;
                    break;
    
                case 'v':
                    steps = 1;
                    break;
    
                case 'o':
                    compression_level = atof ( optarg );
                    break;
    
                case '?':
                    printf("Złe parametry wywołania");
                    return 1;
                    break;
            }
        }
        if(!file) {
            printf("file is required\n");
            return EXIT_FAILURE;
        }
        FILE *read = fopen(file, "r");
        node_t *huff = malloc(length * sizeof *huff);
        int counter = 0;
        for (int i=0; i<length; i++)
            huff[i].v = 0;
    
        if (read == NULL) {
            printf ("file can't be opened \n");
            return 1;
        }
        if(compression_level == 1){
            int c;
            while ((c = fgetc(read)) != EOF ){
                for (int i=0; i<length; i++){
                    if (!huff[i].v){
                        huff[i].w[0] = c;
                        huff[i].v++;
                        counter++;
                        break;
                    }
                    if (huff[i].w[0]== c){
                        huff[i].v++;
                        break;
                    }
                    if (i == length - 1){
                        node_t *temp = realloc(huff, (length + expand_size) * sizeof *temp);
                        if(!temp) {
                            printf("relloc failed\n");
                            exit(EXIT_FAILURE);
                        }
                        huff=temp;
                        for (int j = length; j < length + expand_size; j++)
                            huff[j].v = 0;
                        length += expand_size;
                    }
                }
            }
        }
        int n = huffman(&huff, counter);
        for(int i=0; i<counter; i++){
            int l=i;
            if(compression_level == 1)
                printf("%c: ", huff[i].w[0]);
            if(compression_level == 2)
                printf("%c%c: ", huff[i].w[0], huff[i].w[1]);
            while (l!=n-1){
                printf("%c", huff[l].b);
                l = huff[l].d;
            }
            printf("\n");
        }
        if (steps == 1) {
            for (int i=0; i<counter; i++){
                if( huff[i].w[0] == 10)
                    printf("'%d' 'LINE FEED' occured %d razy\n", huff[i].w[0], huff[i].v);
            }
            printf("array length %d\n", length);
            printf("how many nodes %d\n", n);
            printf("how many primary nodes %d\n", counter);
        }
        free(huff);
        fclose(read);
        return 0;
    }
    

    I also reduced scope of variables, checked return value of realloc(), checked that file is set. Here is the valgrind summary after the change:

    ==2612036== HEAP SUMMARY:
    ==2612036==     in use at exit: 0 bytes in 0 blocks
    ==2612036==   total heap usage: 41 allocs, 41 frees, 53,016 bytes allocated
    ==2612036== 
    ==2612036== All heap blocks were freed -- no leaks are possible