I am not able to flush stdin. How can I flush stdin in C?
Asked Answered
T

8

23

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?

Tigges answered 2/2, 2010 at 20:33 Comment(4)
Because fflush() is only defined for output streams.Trabue
You can always create your own function for discarding input characters. If you name it ignore, then you could be closer to the C++ streams. ;-)Nace
See also How to clear input buffer in C?Paule
Does this answer your question? How to completely clear stdin and the \n before scanf()Wildman
F
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);
Fructose answered 2/2, 2010 at 20:37 Comment(5)
Nice - didn't know about fpurge()Greaves
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..Miltie
@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.Jackstraws
@Ungeheuer: It's not regex. It's the scanf %[ conversion specifier that should be documented with scanf.Miltie
@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.Tobit
S
11
int c;
while((c = getchar()) != '\n' && c != EOF);

Is how I'd clear the input buffer.

Simonides answered 27/1, 2012 at 1:2 Comment(1)
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.Tipstaff
M
3

How to flush the stdin??

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

You can only flush output streams.

Millinery answered 2/2, 2010 at 20:36 Comment(0)
A
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.

Axum answered 2/2, 2010 at 20:39 Comment(0)
S
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);
}
Soilasoilage answered 22/6, 2022 at 13:7 Comment(1)
@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 ptrSoilasoilage
B
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.

Buckskin answered 24/12, 2017 at 12:49 Comment(0)
C
-2

In Windows you can use rewind(stdin) fuction.

Consequently answered 3/6, 2016 at 14:6 Comment(1)
why don't you post tested code snippet along with your code. Because rewind is not intended to do what OP want achieve.Culex

© 2022 - 2024 — McMap. All rights reserved.