Search code examples
cfgetsstrtok

Reading an arbitrary number of space-separated chars from a line in file


I have a file, which, at one line has an arbitrary number of numbers to be read as integers. In a minimal, reproducible example, I created a file test.dat that contains the following line only:

 1 2 3 4

I then try to use fgets and strtok to achieve this:

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

int main(){

FILE* fileptr;

fileptr = fopen("test.dat","r");
char line[500];
char *token;

int array[20];
int i = 0;

fgets(line,300,fileptr);

token = strtok(line," ");
array[i] = atoi(token);
printf("%d\n", array[i]);
i++;

while(token != NULL){
    token = strtok(line," ");
    array[i] = atoi(token);
    printf("%d\n", array[i]);
    i++;
}

return 0;
}

But this results in printing 21 lines of 1's, followed by 632 lines of 0's. Finally it gives a segmentation fault because the i grows larger than 20, the allocated space for array. What I don't understand is why 600+ lines are printed, and why I can never read beyond the number 1 in the file. What am I missing?

Note: I prefer to keep reading from the file with fgets because this is going to be a simple modification to an existing subroutine that reads an entire file.


Solution

  • A few things:

    • You're not limiting your loop to the capable magnitude of array
    • Your loop is not structured properly. All storage should be done within the loop; the outlier prior need not be there.
    • Your invocation of strtok within the loop is wrong. A continuation of an initial onset of strtok should specify NULL as the first argument. See documentation for strtok for more information and usage examples.

    An example that addresses these problems is here:

    #include <stdio.h>
    #include <string.h>
    #include <stdlib.h>
    
    int main()
    {
        FILE* fileptr = fopen("test.dat","r");
        if (fileptr == NULL)
        {
            perror("Failed to open file: ");
            return EXIT_FAILURE;
        }
    
        char line[500];
        int array[20];
        const size_t max_size = sizeof array / sizeof *array;
        size_t i = 0;
    
        if (fgets(line,300,fileptr))
        {
            char *token = strtok(line," ");
            while (i < max_size && token != NULL)
            {
                array[i] = atoi(token);
                printf("%d\n", array[i]);
                ++i;
                token = strtok(NULL, " ");
            }
    
            // use array and i for whatever you needed
        }
    
        return EXIT_SUCCESS;
    }
    

    Output

    1
    2
    3
    4