1

Suppose there is a case: input required:

Name of Player
Height of Player
Age of Player

User may input in such a way that he may press enter(\n) after each input.

printf("Please enter Name, Height and Age of Player");

All I want to take this input with the combination of fgets() and sscanf()

1 Answers1

1

You can define a function that does that for you:

bool readline(char *line, size_t size, FILE *stream)
{
    if (!fgets(line, size, stream))
        return false;
    
    size_t npos = strcspn(line, "\n");
    if (line[npos] != '\n') {
        flush_stdin();
        return false;
    }

    line[npos] = '\0';
    return true;
}
  • line: the char buffer that will hold your input.
  • size: the size (capacity) of line.
  • stream: the file stream you want to read from.

In case the number of characters read exceeds the capacity of the buffer, one must flush the input buffer:

int flush_stdin(void)
{
    int c = 0;
    while ((c = getchar()) != EOF && c != '\n');
    return c;
}

As for sscanf(), use it to parse what has been read by fgets().

Here is a demo:

int main(void)
{
    char input[64], name[64];
    printf("Enter your name: ");
    readline(name, sizeof(name), stdin);
    
    printf("Enter your height: ");
    readline(input, sizeof(input), stdin);
    
    float height = .0;
    if (sscanf(input, "%f", &height) != 1) {
        printf("Input error\n");
        return 1;
    }
    
    printf("Enter your age: ");
    readline(input, sizeof(input), stdin);
    
    int age = 0;
    if (sscanf(input, "%d", &age) != 1) {
        printf("Input error\n");
        return 1;
    }
    
    printf("%s is %d years old and %.2f feet tall.\n", name, age, height);
}
Enter your name: Johnny
Enter your height: 5.6
Enter your age: 18
Johnny is 18 years old and 5.60 feet tall.

Notes:

  • Never use fflush(stdin).
  • Skipped checking for readline() return values for simplicity.
Zakk
  • 1,935
  • 1
  • 6
  • 17
  • Minor: IMO `readline()` should not return `false` when the first unread character is a `'\n'`. – chux - Reinstate Monica Jul 13 '22 at 12:26
  • 4
    `char c = 0; while ((c = getchar()) != EOF && c != '\n');` --> Use `int c;` to properly handle the 257 different values from `getchar()`. – chux - Reinstate Monica Jul 13 '22 at 12:29
  • @chux-ReinstateMonica Why it shouldn't? Any reasons for that? – Zakk Jul 13 '22 at 12:33
  • Because an empty line is a valid input. – Robert Harvey Jul 13 '22 at 12:34
  • I'd expect `char name[64]; readline(name, sizeof(name), stdin);` to save any name up to 63 characters in a like-wise manner. As is, `readline()` returns true with a ... 60, 61, 62 long name, false with 63 and false with 64, 65, .... False with 64, 65, .... is OK, yet why false with 63? Seems an undue burden for the calling code to have to provide a +1 buffer, just to make `readline()` easier to code. – chux - Reinstate Monica Jul 13 '22 at 12:39
  • @chux-ReinstateMonica Otherwise, there's no way to tell if there's something left in the buffer. I will leave it like that anyway. – Zakk Jul 13 '22 at 13:27
  • @Zakk Disagree with "there's no way to tell if there's something left in the buffer." Simple call `gethar()` in `if (line[npos] != '\n') {` block before calling `flush_stdin()`. If the result is `'\n'` or `EOF`, then return true. – chux - Reinstate Monica Jul 13 '22 at 13:40
  • OK for `flush_stdin()`. There is still a problem with `readline`: it returns `false` at end of file, but also if the line was truncated. It would be better to return an `int` with the number of bytes in the line, including those that have been truncated, and `-1` or `EOF` at end of file. Setting the destination array to the empty string at end of file is probably a good idea too. – chqrlie Jul 13 '22 at 13:45