Home > Back-end >  getline and fgets failed to get input on first attempt
getline and fgets failed to get input on first attempt

Time:08-29

void someFunction(){
    char *buffer;
    size_t bufsize = 32;
    int bytes_read;

    for (;;) {
        buffer = (char *) malloc(bufsize * sizeof(char));
        if (buffer == NULL) {
            perror("Unable to allocate buffer");
            exit(1);
        }

        FILE *ptr;
        ptr = fopen("sample.txt", "a");
        printf("Enter Stuff to write down:\n");
        //getline(&buffer,&bufsize,stdin);
        //fgets(buffer, 30, stdin);
        //scanf("%[^\n]%*c", buffer);
        //scanf("%s", buffer);

        if (buffer[0] == '0') {
            break;
        }

        WriteWithFprintf(ptr, buffer);
        free(buffer);
        fclose(ptr);
    }
}

The problem is: if I use

    getline(&buffer,&bufsize,stdin);

or

    fgets(buffer, 30, stdin);

then it escapes the first like so:

    Enter Stuff to write down:
    Enter Stuff to write down:
    0

If I use:

    scanf("%[^\n]%*c", buffer);

then I get an infinite loop.

It does work with:

   scanf("%s", buffer);

but I want input with space so this is not an option for me.

CodePudding user response:

All of the behaviors described for different variations on your code are consistent with the next character available to be read from stdin being a newline, presumably from a preceding line of input.

In that case,

  • the getline() and fgets() alternatives will read the newline (and any preceding characters) as a line, and then loop to read the line you actually want on the second pass.
  • the first scanf() variation will read nothing on account of a matching failure for the %[^\n] field (leading whitespace is not skipped for %[ directives). Not having matched anything to that, there will be no attempt to match anything to the %*c.
  • the second scanf() alternative will work as you describe, because scanf will automatically consume leading whitespace when processing a %s directive, including any newline.

There is a variety of things you could do, depending on exactly how want to handle input. Here is one:

    int c = fgetc(stdin);
    if (c == EOF) {
        // handle eof ...
    } else if (c != '\n') {
        ungetc(c, stdin);
    }
    // your choice for reading the wanted data ...

That will consume up to one leading newline from stdin to get it out of your way.

CodePudding user response:

getline and fgets failed to get input on first attempt

Neither failed. Both simply read a '\n' and immediately returned. This '\n' was left-over from a previous input function like scanf("%s", ...), that did not consume the entire line. getline() is not part of the standard C library.

scanf("%[^\n]%*c", buffer); fails to read anything when the first available character is '\n'.

scanf("%s", buffer); consumes all optional leading white space like '\n'. This may appear to work for OP.

scanf("%[^\n]%*c", buffer); and scanf("%s", buffer); are both poor code as they do not have a width limit, risking buffer overflow.


I recommend for a learner to not use scanf() at all and perform all input with fgets(), including the part of code not posted.

  •  Tags:  
  • c
  • Related