Search code examples
cstructmallocfreerealloc

free() runtime error while working with structure pointer arrays


Hello i have been struggling with my code for a while and finally found that the free() funtion is the cause. I think i am missing something about the details of how free() works.

My output is :

test test test test test 
ID: 200
RELEASE YEAR: 2006


ID: 201
RELEASE YEAR: 2006


ID: 202
RELEASE YEAR: 2006


ID: 203
RELEASE YEAR: 2006


ID: 204
RELEASE YEAR: 2006


AB

Edit : Added the full code

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

#define MAX 1000                                        //Do not edit this macro.

typedef struct{
    int film_id;
    char title[255];
    char description[1023];
    unsigned int release_year;
    char rental_duration;
    float rental_rate;
    unsigned char length;
    float replacement_cost;
    char rating[10];
    char last_update[30];
} RECORD_t, *RECORD;                                    //Do not edit this struct.


RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found);


int main(){
    RECORD rec = (RECORD)malloc(sizeof(RECORD_t)*MAX);  //Do not edit this line.
    FILE *file = fopen("data.txt", "rb");               //Do not edit this line.
    if (file == NULL) {                                 //Do not edit this line.
        printf("Cannot open the file.\n");              //Do not edit this line.
        exit(0);                                        //Do not edit this line.
    }                                                   //Do not edit this line.
    fread(rec, sizeof(RECORD_t)*MAX, 1, file);          //Do not edit this line.
    fclose(file);                                       //Do not edit this line.


    int i,test;
    RECORD *rec_arr;

    rec_arr=find_by_year(2006,rec,200,203,&test);
    for(i=0;i<test;i++){
            printf("ID: %d\n", rec_arr[i]->film_id);
            printf("RELEASE YEAR: %d\n", rec_arr[i]->release_year);
            printf("\n\n");
            fflush(stdout);
    }
    printf("A");
                fflush(stdout);

//  file = fopen("data.txt", "wb");                     //Do not edit this line.
//  fwrite(rec, sizeof(RECORD_t)*MAX, 1, file);         //Do not edit this line.
//  fclose(file);                                       //Do not edit this line.
    free(rec);                                          //Do not edit this line.


    printf("B");
    fflush(stdout);

    free(rec_arr);

printf("C");
    fflush(stdout);

    return 1;                                           //Do not edit this line.
}

RECORD *find_by_year(int release_year, RECORD film_array, int start, int end,int *found) {

    RECORD *rec_arr=malloc(sizeof(RECORD)*1);
    RECORD *narray;//for realloc check
    int size=1,i,j;
    start--;
    if(rec_arr==NULL){//if malloc fails
        printf("MALLOC FAILED find_by_year returning NULL\n");
        fflush(stdout);
        return NULL;
    }

    for(i=start;i<=end;i++){
        if(film_array[i].release_year==release_year){
            rec_arr[size-1]=&film_array[i];
            size++;
            narray=realloc(rec_arr,size);//increment the size by 1


            //ERROR HANDLING
            if(narray==NULL){//if realloc fails
                printf("INNER REALLOC FAILED find_by_year");
                fflush(stdout);
                narray =malloc(sizeof(RECORD) * size);

                if(narray==NULL){ //if malloc fails
                    printf("INNER MALLOC ALSO FAILED find_by_year returning NULL\n");
                    fflush(stdout);
                    return NULL;
                }

                for(j=1;j<size;j++){//copy
                    narray[size-1]=rec_arr[size-1];
                    free(rec_arr);
                }
            }
            printf("test ");
            fflush(stdout);

            rec_arr=narray;
        }
    }
    printf("\n");
    fflush(stdout);

    *found=size-1;


    if(size==1)//if not found anything
        return NULL;

    return rec_arr;
}



From the results of debugging free(rec_arr) fails everytime what could be the problem here. I cropped the code and i am almost sure that the cropped parts are working from the debugging.


Solution

  • This line is incorrect:

    narray=realloc(rec_arr,size);//increment the size by 1
    

    The second argument to realloc should be the number of bytes, not the number of records. You should multiply size by sizeof(RECORD) .


    Here's some general recommendations about the rest of the code:

    • I suggest just aborting in the if(narray=NULL) case. That code will almost never happen anyway , and probably will fail anyway even if it does enter. Recovering from out-of-memory is an advanced topic (especially taking into account that modern operating systems overcommit).
    • You mentioned using Eclipse+CDT -- you should be able to step through the code in the debugger instead of having to use printf debugging statements.
    • It would be good to check for rec being NULL on the first line of main, and also check the return value of find_by_year -- if it returns NULL then you don't want to go on to do the i loop. Your function does not set *found in the case of returning NULL, sometimes, so the caller has to do the null check before using the record count.
    • I don't really agree with the other suggestion to change the realloc strategy. Keeping the code simple to read is not a bad plan , either for beginners or experts. And I doubt it is really inefficient as modern operating systems have a minimum allocation size so the realloc calls will basically be doing nothing unless your search returns more than say 1000 records.