evie
evie

Reputation: 113

File reading in C with fgets entering into a never ending loop

I'm attempting to do basic file reading in C with fgets. It should read one line, pass it to the tokeniser function which should split it at every ' ' and add it to a linked list. At the moment it is entering into a never ending while loop and I'm not sure why. Any help is appreciated. I am really struggling with this C language

#define INPUTSIZE 11

void tokeniseString(LinkedList *list, char *str)
{
    char *token = strtok(str, " ");

    while (token != NULL)
    {
        insertLast(list, *token);
    }
}

void readInputFile(char *fileName, LinkedList *list)
{
    FILE* inputFile = fopen(fileName, "r");
    char str[INPUTSIZE];

    printf("1");
    if (inputFile == NULL)
    {
        perror("Could not open file");
    }
    else
    {
        while (fgets(str, INPUTSIZE, inputFile) != NULL)
        {
            tokeniseString(list, str);
        }
        
        if (ferror(inputFile))
        {
            perror("Error while reading from file");
        }
    }
}

Upvotes: 1

Views: 59

Answers (1)

chqrlie
chqrlie

Reputation: 145287

You have an endless loop because you do not scan for the next token in the loop body. You should write:

void tokeniseString(LinkedList *list, char *str) {
    char *token = strtok(str, " ");

    while (token != NULL) {
        insertLast(list, *token);
        token = strtok(NULL, " ");
    }
}

Not however that you insert the value of the first byte of the token into the list. You should probably convert the token as a number using strtol() instead:

#include <errno.h>
#include <limits.h>
#include <string.h>
#include <stdlib.h>

void tokeniseString(LinkedList *list, char *str) {
    char *token = strtok(str, " \t\r\n");

    while (token != NULL) {
        char *p;
        long value;
        errno = 0;
        value = strtol(token, &p, 10);
        if (p == token || *p != '\0') {
            fprintf(stderr, "token is not a number: %s\n", token);
        } else
        if (errno != 0 || value > INT_MAX || value < INT_MIN) {
            fprintf(stderr, "number is out of range: %s\n", token);
        } else {
            insertLast(list, (int)value);
        }
        token = strtok(NULL, " \t\r\n");
    }
}

Note that modifying the string argument is considered bad practice, especially using a function with side effects on a static state such as strtok(). Here is another version that does not modify the argument:

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

void tokeniseString(LinkedList *list, const char *str) {
    for (;;) {
        char *p;
        long value;
        int len;

        /* skip whitespace */
        str += strspn(str, " \t\r\n");
        if (*str == '\0')
            break;
        /* get the length of the token */
        len = strcspn(str, " \t\r\n");
        errno = 0;
        value = strtol(token, &p, 10);
        if (p == str) {
            fprintf(stderr, "token is not a number: %.*s\n", len, str);
        } else
        if (p != str + len) {
            fprintf(stderr, "token has extra characters: %.*s\n", len, str);
        } else
        if (errno != 0 || value > INT_MAX || value < INT_MIN) {
            fprintf(stderr, "number is out of range: %.*s\n", len, str);
        } else {
            insertLast(list, (int)value);
        }
        str += len;
    }
}

Also note that you must close the file in readInputFile().

Upvotes: 1

Related Questions