0

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.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
Tasnim Zuhod
  • 103
  • 2
  • 2
  • 10
  • this `fscanf(fp, "%d", &num)>0` is ok, but the correct way is `fscanf(fp, "%d", &num) == 1`. – Iharob Al Asimi Feb 27 '15 at 00:20
  • 4
    Change `printf("\nTEST After fclose");` to `printf("\nTEST After fclose\n");`. I think you'll find that it actually is printed and the crash occurs elsewhere. – r3mainer Feb 27 '15 at 00:21
  • 1
    I see very often that people learn to put a new line at the begining of a text line, that doesn't make sense to me, besides of course that the `'\n'` flushes the output buffer. – Iharob Al Asimi Feb 27 '15 at 00:22
  • 4
    The problem is that you're allocating space for exactly one `int`, and then loading a whole bunch of `int`s from the file. The `malloc` needs to allocate enough memory to hold all of the `int`s. – user3386109 Feb 27 '15 at 00:24
  • how is that? how to allocate enough memory? – Tasnim Zuhod Feb 27 '15 at 00:27
  • How many numbers are in the file? – user3386109 Feb 27 '15 at 00:28
  • 1
    One way is to start by allocating enough memory for 100 numbers. After reading 100 numbers, use `realloc` to double the size of the memory (so it can hold 200 numbers). Keep doubling with `realloc` until you have all of the numbers. – user3386109 Feb 27 '15 at 00:31
  • Another way is to put something at the beginning of the file that tells how many numbers are in the file. And another way is to open the file, count how many numbers are in the file, allocate the memory, `rewind` the file and then read all the numbers. – user3386109 Feb 27 '15 at 00:34
  • the parameter 'filename' is not used – user3629249 Feb 28 '15 at 04:07
  • Possible duplicate of [fclose() causing segmentation fault](http://stackoverflow.com/questions/1443164/fclose-causing-segmentation-fault) – Jim Fell Nov 13 '15 at 22:22

1 Answers1

3

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.

Christophe
  • 68,716
  • 7
  • 72
  • 138