0

I`m making a file reader that reads integers numbers line by line from a file. The problem is that is not working. I think I am using fscanf in a wrong way. Can someone help me?

I had already look for answers in others questions but I can`t find anything that explain why I my code is not working.

int read_from_txt(){
    FILE *file;
    file = fopen("random_numbers.txt", "r");
    //Counting line numbers to allocate exact memory
    int i;
    unsigned int lines = 0;
    unsigned int *num;
    char ch;
    while(!feof(file)){
        ch = fgetc(file);
        if (ch == '\n'){
            lines++;
        }
    }
    //array size will be lines+1
    num = malloc(sizeof(int)*(lines+1));
    //storing random_numbers in num vector
    for(i=0;i<=lines;i++){
        fscanf(file, "%d", &num[i]);
        printf("%d", num[i]);
    }
    fclose(file);
}

The txt file is like:

12 
15
32
68
46
...

But the output of this code keeps giving "0000000000000000000..."

Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
  • 3
    after the `fgetc` loop the file pointer is at the end of the file. You need to `rewind` the file before reading it again. – kaylum Mar 29 '17 at 19:51
  • @Lashane `file` was opening in text mode. Text files corresponding to the compiler's C library understanding of a text file will translate the `\n`, `\r\n` or `\r` to a `'\n'`. `if (ch == '\n')` is sufficient. If other text files need to be processed, many other issues occur beyond this post's scope. – chux - Reinstate Monica Mar 29 '17 at 20:04
  • 1
    Tip: any time code does not behave as expected and code is doing I/O, add code to check the return value of I/O functions like `fscanf(file, "%d", &num[i]);` which would have shown a problem - this saves you time. – chux - Reinstate Monica Mar 29 '17 at 20:07
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/139420/discussion-between-chux-and-lashane). – chux - Reinstate Monica Mar 29 '17 at 20:40
  • `while(!feof(file))` [is always wrong](http://stackoverflow.com/questions/5431941/why-is-while-feof-file-always-wrong). `fgetc`returns an `int` not a `char`. – n. 'pronouns' m. Mar 30 '17 at 04:10

2 Answers2

2

You forgot to "rewind" the file:

fseek(file, 0, SEEK_SET);

Your process of reading goes through the file twice - once to count lines, and once more to read the data. You need to go back to the beginning of the file before the second pass.

Note that you can do this in a single pass by using realloc as you go: read numbers in a loop into a temporary int, and for each successful read expand the num array by one by calling realloc. This will expand the buffer as needed, and you would not need to rewind.

Be careful to check the results of realloc before re-assigning to num to avoid memory leaks.

Sergey Kalinichenko
  • 675,664
  • 71
  • 998
  • 1,399
1

You could try to use the getline function from standard IO and add the parsed numbers into the array using only one loop. See the code below. Please check https://linux.die.net/man/3/getline

Also, you can use the atoi or strtoul functions to convert the read line to an integer. Feel free to check https://linux.die.net/man/3/atoi or https://linux.die.net/man/3/strtoul

The code below evaluate a file with a list of numbers and add those numbers to a C integer pointer

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

int main(int argc, char ** argv) {
    FILE * file;

    file = fopen("./file.txt", "r");

    size_t read;
    char * line = NULL;
    size_t line_len = 0;

    size_t buffer_size = 10;
    int * buffer = (int *)malloc(sizeof(int) * buffer_size);

    int seek = 0;
    while((read = getline(&line, &line_len, file)) != -1) {
        buffer[seek++] = atoi(line);

        if (seek % 10 == 0) {
            buffer_size += 10;
            buffer = (int *)realloc(buffer, sizeof(int) * buffer_size);
        }
    }

    for (int i = 0; i < seek; i++) {
        printf("%d\n", buffer[i]);
    }

    free(buffer);
    fclose(file);
}

If you aren't sure which conversion function should you use. You can check the difference between atoi and sscanf at What is the difference between sscanf or atoi to convert a string to an integer?

Community
  • 1
  • 1
Mateo Olaya
  • 155
  • 8
  • 1
    A couple of notes, there is absolutely **no** error checking provided by `atoi`, any subsequent code that relies on `buffer[X]` containing an `unsigned` value within the range `0 - INT_MAX` has no way to validate that `buffer[X]` contains a valid value. (better to use `strtoul` with error checking). Next, assigning the return of `realloc` to the pointer itself (rather than to a `tmp` pointer) risks creating a memory leak by losing a reference to the original block of memory. (better `void *tmp = realloc(buffer, sizeof *buffer * buffer_size); if (tmp) buffer = tmp;`. (no need to cast either) – David C. Rankin Mar 30 '17 at 04:13
  • @DavidC.Rankin is right, you might check the integrity of conversion using `sscanf` or `strtoul`. Also, you should check pointers integrity for avoiding possible leak or memory issues. Thanks David C. – Mateo Olaya Mar 30 '17 at 04:52