Tasnim Zuhod
Tasnim Zuhod

Reputation: 103

c - fclose() causes a crash

I have a problem in this code, it executes successfully until reach fclose(fp) statement, it crashes.

void read_file(const char *filename) {
    FILE *fp;
    int num, i=0;

    fp = fopen("numbers.txt","r");

    if (fp == NULL) {
        printf("Couldn't open numbers.txt for reading.\n");
        exit(0);
    }

    int *random = malloc(sizeof(int));
    if (random == NULL) {
        printf("Error allocating memory!\n");
        return;
    }
    while (fscanf(fp, "%d", &num) > 0) {
        random[i] = num;
        i++;
    }
    printf("\nTEST Before close");

    fclose(fp);

    printf("\nTEST After fclose");
}

The sentence TEST Before close is printed successfully and then the console is stopped printing so TEST After fclose doesn't printed and the cursor start blinking !

Any help? Thanks in advance.

Upvotes: 0

Views: 1987

Answers (1)

Christophe
Christophe

Reputation: 73366

The problm is that

 int *random = malloc(sizeof(int));

only allocates ONE single integer.

If you have more than one integer in your file, your while will increment i index and you will write your variable in an invalid location causing memory corruption. This can trigger a segfault, but it can also result in weird behaviour at any time, as in your case.

   random[i] = num;  /* oops !!! if i>0 memory corruption */ 

Solutions:

If you know the number of integers, you can allocate immediately the right amount memory. I recommend calloc() for this purpose, as it's meant for array allocation, and initializes the allocatied memory to 0:

int *random = calloc(number, sizeof(int));  

If you don't know the number you could extend gradually the size of your array, using realloc():

int number = 100;  /* arbitrary initial size*/ 
int *random = malloc(number*sizeof(int));  
...
while (fscanf(fp, "%d", &num) > 0) {
    if (i==number-1) {
        number  += 100;  /* consider allocating 100 more items */
        random = realloc (random, number*sizeof(int)); 
        if (random==NULL) {
            printf("Not enough momory for reading all the numbers.\n");
            exit(1);
         }
    }
    random[i] = num;
    i++;
}

A last way to proceed is to infer a maximum number of integers based on the file size:

fseek (fp, 0, SEEK_END);  // go to the end 
long size=ftell (fp);     // get the length of file
fseek (fp, 0, SEEK_SET);  // go to start
long number = size/2 + 1;  // each number is at least 1 digit folowed by a space, except the las one
if (n > INT_MAX) {
     printf("File too big !\n");
     exit(1);
}
int *random = calloc((size_t)number, sizeof(int));  
...

This is of course practical, but SEEK_END is unfortunately not supported by all library implementations.

Upvotes: 3

Related Questions