24

How to flush the stdin??

Why is it not working in the following code snippet?

#include <string.h>
#include <stdio.h>
#include <malloc.h>
#include <fcntl.h>

int main() {
    int i = 0, j = 0, sat;
    char arg[256];
    char *argq;
    argq = malloc(sizeof(char) * 10);
    
    printf("Input the line\n");
    i = read(0, arg, sizeof(char) * 9);
    arg[i - 1] = '\0';
    fflush(stdin);
    
    i = read(0, argq, sizeof(char) * 5);
    argq[i - 1] = '\0';

    puts(arg);
    puts(argq);
    
    return 0;
}

Now if I give the input as 11 characters, only 9 should be read but the remaining two characters in the stdin are not flushed and read again in the argq. Why?

Input: 123 456 789

Output:

123 456
89

Why am I getting this 89 as the output?

chqrlie
  • 131,814
  • 10
  • 121
  • 189
Subodh Asthana
  • 293
  • 1
  • 2
  • 9

8 Answers8

45

I believe fflush is only used with output streams.

You might try fpurge or __fpurge on Linux. Note that fpurge is nonstandard and not portable. It may not be available to you.

From a Linux fpurge man page: Usually it is a mistake to want to discard input buffers.

The most portable solution for flushing stdin would probably be something along the lines of the following:

int c;
while ((c = getchar()) != '\n' && c != EOF);
jschmier
  • 15,458
  • 6
  • 54
  • 72
  • 1
    Nice - didn't know about fpurge() – mob Feb 02 '10 at 20:40
  • 5
    Or, easier: `scanf("%*[^\n]%*c");` You can of course merge this onto the end of your existing `scanf` format string to discard the remainder of a line after processing part of it with `scanf`, too.. – R.. GitHub STOP HELPING ICE Nov 28 '12 at 16:09
  • @R.. perhaps you could explain the provided regex in more detail, even though it's been 5 years. Or provide a link to material that can clarify it. – Ungeheuer Apr 05 '17 at 07:03
  • @Ungeheuer: It's not regex. It's the `scanf` `%[` conversion specifier that should be documented with scanf. – R.. GitHub STOP HELPING ICE Apr 06 '17 at 02:50
  • 1
    @R..GitHubSTOPHELPINGICE: `scanf("%*[^\n]%*c");` will not discard the newline if there is no pending character to match the `[^\n]` character class, ie: if there is just a newline pending in `stdin`. – chqrlie Jun 22 '22 at 14:13
11
int c;
while((c = getchar()) != '\n' && c != EOF);

Is how I'd clear the input buffer.

  • 2
    There might be a potential downside if doing so. Say afterward you want to use `fgets` read from `stdin`, which is empty, then you have to firstly type the `enter` key before the actual typing. – J.G Mar 26 '19 at 16:33
3

How to flush the stdin??

Flushing input streams is invoking Undefined Behavior. Don't try it.

You can only flush output streams.

dirkgently
  • 108,024
  • 16
  • 131
  • 187
2

You are overriding the last element of the input in arg with '\0'. That line should be arg[i]='\0'; instead (after error and boundary checking you are missing.)

Other's already commented of the flushing part.

Nikolai Fetissov
  • 82,306
  • 11
  • 110
  • 171
2

If you use GLIBC you can just mess with the stdin ptr manually

void flush_stdin(){
    unsigned long* tmpstdin = (unsigned long*)stdin;
    unsigned long* oldbuf = (unsigned long*)*(tmpstdin+4);
    free((void*)oldbuf);
    *tmpstdin=(unsigned long)0xfbad2088;
    tmpstdin+=1;
    memset(tmpstdin,'\x00',64);
}
Zopazz
  • 56
  • 5
  • @chrqlie You're right. You should ofc check whether or not stdin has been initialized before freeing the old buf. Making a check to see if oldbuf is 0x0, should fix any errors you might get, in case you're trying to free an uninitialized heap ptr – Zopazz Jun 23 '22 at 10:49
0

You can't clean stdin in Linux without bumping into scenarios that the command will start waiting for input in some cases. The way to solve it is to replace all std::cin with readLineToStdString():

void readLine(char* input , int nMaxLenIncludingTerminatingNull )
{
    fgets(input, nMaxLenIncludingTerminatingNull , stdin);

    int nLen = strlen(input);

    if ( input[nLen-1] == '\n' )
        input[nLen-1] = '\0';
}

std::string readLineToStdString(int nMaxLenIncludingTerminatingNull)
{
    if ( nMaxLenIncludingTerminatingNull <= 0 )
        return "";

    char* input = new char[nMaxLenIncludingTerminatingNull];
    readLine(input , nMaxLenIncludingTerminatingNull );

    string sResult = input;

    delete[] input;
    input = NULL;

    return sResult;
}

This will also allow you to enter spaces in std::cin string.

Sunny127
  • 265
  • 3
  • 8
-2

In Windows you can use rewind(stdin) fuction.

  • why don't you post tested code snippet along with your code. Because rewind is not intended to do what OP want achieve. – Haseeb Mir Nov 26 '18 at 21:53