Search code examples
cfgets

fgets that would skip when called the second time


I think the problem of my code is with my fgets but I do not know how to fix it. So, when I call the function for the first time, everything works, but if for the second time, the function skips everything after the printf.

So the output would be:

Output:
Please enter x and y coordinates separated by a comma for the piece you wish to enter: 3,4
x: 3, y:4
Please enter x and y coordinates separated by a comma for the piece you wish to enter: x:
, y:

This is the code:

void functioncall()
{
    char coord[4];
    printf("Please enter x and y coordinates separated by a comma for the piece you wish to place: ");
    fgets(coord, 4, stdin);

    char *xcoord = strtok(coord, ",");
    char *ycoord = strtok(NULL, " ");
    if (!ycoord)
    {
        ycoord = "";
    }

    printf("x: %s, y: %s\n", xcoord, ycoord);
}

I cannot give an input when it is called for the second time.


Solution

  • The reason for the behaviour you see is the size of the coord array. When you specify the size as 4, it means you can get 1 digit, 1 comma, 1 digit, and 1 null byte stored — which doesn't leave room for the newline, so the second call to the function reads the newline (only), which doesn't parse well.

    You should allow for much more space — users are endlessly inventive in what they type (leading blanks, trailing blanks, intermediate blanks, signs, leading zeros, etc.). I tend to use 4096 for single lines of input — partly for the shock value, and also because if someone's willing to write a 4-page essay on a single line, they deserve what they get.

    This code works for me:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static void functioncall(void)
    {
        char coord[4096];
        printf("Please enter x and y coordinates separated by a comma for the piece you wish to place: ");
        if (fgets(coord, sizeof(coord), stdin) == 0)
        {
            fprintf(stderr, "Got EOF in %s\n", __func__);
            exit(EXIT_FAILURE);
        }
        const char delims[] = ", \n\t";
    
        char *xcoord = strtok(coord, delims);
        char *ycoord = strtok(NULL, delims);
        if (!ycoord)
        {
            ycoord = "";
        }
    
        printf("x: [%s] y: [%s]\n", xcoord, ycoord);
    }
    
    int main(void)
    {
        functioncall();
        functioncall();
        return 0;
    }
    

    Example run (program name cd19, source file cd19.c):

    $ ./cd19
    Please enter x and y coordinates separated by a comma for the piece you wish to place: 234 , 495
    x: [234] y: [495]
    Please enter x and y coordinates separated by a comma for the piece you wish to place: 1,2
    x: [1] y: [2]
    $
    

    The choice of delimiter characters ensures that the 234 , 495 example works OK (the tab is optional, but not necessarily a bad idea). It does, however, mean that the user is not obliged to enter a comma.