How to clear stdin before getting new input? - c

I have read about 5-10 different advices how to clear stdin, but none of them suits my needs. The thing is that fflush(stdin) worked perfectly at my computer, but unfortunately it doesn't seem to work everywhere, so I need something with the same functionality. Every other way I tried clears stdin when it is not empty but requires user input when stdin IS empty, which means it requires input in a moment I dont want to get any (+ it discards it anyway).
The question is: Can I somehow make sure, that stdin IS empty before I require user input? (and if not, THEN and only then clear it somehow?)
something like:
if (stdin is NOT empty)
while (getchar() != '\n')
continue;
EDIT: the thing is that I load characters from stdin one by one and at some point, a part of the input from previous iteration might or might not get discarded. either way, I need to have clear stdin before I ask the user for another input to be processed. Clearing the buffer itself is not such a big deal, the problem is what happens when the input is empty when the program gets to the point of clearing stdin, because in that moment the program needs another input which is going to be eaten by the clearing function. Thats what I want to get rid of. (when I could use fflush(stdin); I just knew, that for the next line of my program the stdin WILL be empty no matter what, no questions asked...)

How to clear stdin before getting new input?
.. so I need something with the same functionality.
With portable C this is not possible.
Instead suggest a different (and more usual C) paradigm:
Insure previous input functions consumes all the previous input.
fgets() (or *nix getline()) is the typical approach and solves most situations.
Or roll your own. The following reads an entire line, but does not save extra input.
int mygetline(char *buf, size_t size) {
assert(size > 0 && size <= INT_MAX);
size_t i = 0;
int ch;
while ((ch = fgetc(stdin)) != EOF) { // Read until EOF ...
if (i + 1 < size) {
buf[i++] = ch;
}
if (ch == '\n') { // ... or end of line
break;
}
}
buf[i] = '\0';
if (i == 0) {
return EOF;
}
return i;
}

From a similar question, Use poll() with fds.fd set to 0 (stdin), fds.events set to POLLIN, nfds set to 1, and timeout set to zero. After calling poll(), fds.revents will be set to zero if the buffer is empty, and to POLLIN otherwise.
struct pollfd fds = {0, POLLIN, 0};
poll(&fds, 1, 0);
if(fds.revents == POLLIN}
printf("stdin buffer is not empty");
This solution will work on posix-compliant systems, but not Windows. Use select() for portability.

TL;DR fflush(stdin) invokes undefined behavior as per the standard, you should never use it.
Coming to your code (logic), instead of looking for a newline, you can look for EOF. It does not have a prerequisite that stdin should have some input before running this loop.
Something like
while (getchar() != EOF); //; is not a mistake
should meet your needs.

Use only fgets() to read stdin.
Use a large enough buffer and/or test for full lines.
Using fgets() you never have to worry about extra characters in stdin.
// read characters until 'X'
while (((ch = getchar()) != EOF) && (ch != 'X')) putchar(ch);
// discard X and the rest of the line
fflush(stdin); // UB except for Windows
// read full line
char tmp[1000], *p;
if (!fgets(tmp, sizeof tmp, stdin)) /* deal with error */;
if (!*tmp) /* embedded NUL detected: input is not a text file */;
if (tmp[strlen(tmp) - 1] != '\n') /* partial line */;
p = tmp;
while (*p && *p != 'X') putchar(*p++);
// ignore the X and all the subsequent characters

The select module offers a function called select that achieves exactly what you're looking for. select.select takes three arguments:
select.select(rlist, wlist, xlist)
Each argument should be a list of file descriptors (such as [sys.sdtin]) and it then waits until a specific IO operation is available. The IO operations are read, write or some other exception on the given file descriptors. It returns a tuple of corresponding lists populated with the file descriptors that are ready.
So, if there is input waiting in sys.stdin then the function would behave like so:
>>> import select
>>> import sys
>>>
>>> select.select([sys.stdin], [], [])
([sys.stdin], [], [])
>>>
By itself, this doesn't solve your problem because by default the function will wait until an IO operation is available. Importantly, however, select.select has an optional timeout argument denoting how long it will wait before giving up. We simply have to set the timeout to zero and we can check for input without blocking the program flow.
Let's see an example where there is no input waiting in sys.stdin:
>>> import select
>>> import sys
>>>
>>> timeout = 0
>>> select.select([sys.stdin], [], [], timeout)
([], [], [])
>>>
Knowing that we only want the first element of that tuple (the input streams) we're ready to make a useful if statement:
if sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
print('Input is waiting to be read.')
That means clearing the input stream just needs some iteration:
while sys.stdin in select.select([sys.stdin], [], [], 0)[0]:
sys.stdin.readline()
And we can of course use this on any input stream, so lets put it in a function:
def clear_input(stream, timeout=0):
'''Takes an input stream and discards each line in the buffer.
The given timeout denotes how long in seconds to wait for
further input when none is available.
'''
while stream in select.select([stream], [], [], timeout)[0]:
stream.readline()
So let's demonstrate our function to achieve what you ask for in your question:
import select
import sys
import time
def clear_input(stream, timeout=0):
while stream in select.select([stream], [], [], timeout)[0]:
stream.readline()
if __name__ == '__main__':
print('Type some lines now. They will be ignored.')
time.sleep(5)
print('Clearing input.')
clear_input(sys.stdin)
user_input = raw_input('Please give some fresh input: ')
print(user_input)
The clear_input function can be used as a non-blocking way to clear input streams and should work in Python2 and Python3.

Related

fgets() always waiting for input, can't find how to fix it

I have an issue here were I can't find a way to stop fgets() to read from stdin after I paste my input in it. I want it to read what I pasted and stop after (it can be different length). Now it is waiting for another input.
void readMatrix(char (*charM)[40]) {
char charT[42] = {0};
int count = 0;
while (fgets(charT, 42, stdin) != NULL) {
for (int i = 0; i < 40; i++){
if (charT[i] == 0 || charT[0] == '\n' ) {
printf("Erreur: Caractère `EOF` inattendu, attendu `H`, `X`
ou `.`.");
exit(0);
}
if(charT[i] != '.' && charT[i] != 'H' && charT[i] != 'X') {
printf("Erreur: Caractère `%c` inattendu, attendu `H`, `X`
ou `.`.", charT[i]);
exit(0);
}
charM[count][i] = charT[i];
}
count++;
if (count == 20) break;
}
}
Thanks!
while (fgets(charT, 42, stdin) != NULL)
Even though you do not type in anything and you hit enter, it will feed a null-terminated string in C. You either need to change this condition, or alternatively you need to feed the standard input an End-of-Transmission character. For Linux it is Ctrl + D, for Windows it is Ctrl + Z.
When you copy and paste, there is nothing copied that ends the input.
Since there is nothing copied in that ends the input, fgets() not return NULL.
After doing the copy and paste, there may be a last line of input waiting to be read. In that case, it is necessary to hit the enter key, so fgets() will return that last line of input. If you're lucky, that step is not necessary (because a carriage return has been copied as the last character) but there is still nothing telling fgets() that input has ended.
The fact that everything has been copied does not tell fgets() that input has ended. The significance is that, if you wish, you will be able to repeatedly copy text into your program, as many times as you like.
To actually signal the end of input to your program, you need to manually do something to indicate that. For most flavours of unix, that is done using CTRL-D. For windows, it is CTRL-Z. Depending on how your program is run (e.g. in a terminal window or not) it may be necessary to manually do that twice (e.g. hit CTRL-Z twice under windows).
Note that it is a good idea to hit the enter key at least once before signally end of input. If there is an incomplete line waiting to be read (i.e. no newline yet) some keyboard or terminal drivers will discard the last line if they encounter end of input. For example, under windows, always hit then CTRL-Z (and, possibly, you will still need to enter CTRL-Z a second time).
Note: some programs do sensibly handle copy and paste. But those programs use a system-dependent function INSTEAD of fgets() so they can recognise the end of copy/pasted text. You can't emulate that behaviour using fgets(), hence the need for the user to do something.

How to return to previous scanf and keep the flow

I'm programming this code (personal software) for a spa which is still in a beta version but I encounter a issue well is more like an idea than an issues let me explain you:
Source code:
fflush(stdin);
gets(NC1.Customer_Nameandlastname);
fflush(stdin);
printf("provide the customer's age\n\t");
fflush(stdin);
scanf("%d",&NC1.Customer_Age);
fflush(stdin);
this is just part of the source code but what I want to do when the program is running is this:
If the the person that is typing the information makes a mistake or wants to retype the same information but the next command line is already waiting for the input data the question is how would I do to go back to the previous line and then after I finish continue to the next line?
So it is like how would I return to the previous scanf() if I already type that information and then the system is waiting for the next line.
Please help me because I dont really know what yo do I am seeking how to do it but I still not able to find it.
You cannot portably flush input from stdin with fflush(stdin);. It invokes undefined behavior.
You can read the rest of an offending line from stdin with this function:
void flush_line(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
}
Furthermore, do not use gets(). This unsafe function (you cannot provide the size of the destination array, so any properly crafted input may cause undefined behavior, a flaw that can be used by an attacker to compromise your program). The function was finally removed from the C Standard in 2011. Use fgets() and remove the trailing linefeed if any this way:
if (fgets(line, sizeof line, stdin)) {
line[strcspn(line, "\n")] = '\0';
...
}
You cannot restart a failed scanf(). The return value gives you some information as to where it failed, but not enough to restart the parse reliably. A better way to parse standard input is to read line by line and use sscanf() to parse the lines. Example:
/* read the customer's age. Keep prompting in case of invalid input */
for (;;) {
char line[80];
printf("provide the customer's age\n\t");
/* force flush of stdout for systems that do not do it
automatically upon reading from stdin */
fflush(stdout);
if (!fgets(line, sizeof line, stdin)) {
/* end of file reached */
return -1;
}
if (sscanf(line, "%d", &NC1.Customer_Age) == 1) {
/* input parsed correctly, break out to the next question */
break;
}
/* parse failed, output an appropriate message and restart */
printf("bad input, please type a number\n");
}
This is really a basic problem, what you want is a loop like this
while (fgets(buffer, SIZE_OF_BUFFER, stdin) != NULL) {
if (is_input_valid(buffer) == 1)
break;
/* Or else, go again */
}
After asking the user for all the details, ask something like
Do you want to store this record in the database?
Instruct the user that if he makes a mistake, he should enter garbage for the following fields, and answer "no, I want to discard this record".
Maybe the user will understand by himself that this is what he should do, because asking for such confirmation is a pretty standard practice.

C - how to handle user input in a while loop

I'm new to C and I have a simple program that takes some user input inside a while loop, and quits if the user presses 'q':
while(1)
{
printf("Please enter a choice: \n1)quit\n2)Something");
*choice = getc(stdin);
// Actions.
if (*choice == 'q') break;
if (*choice == '2') printf("Hi\n");
}
When I run this and hit 'q', the program does quit correctly. However if I press '2' the program first prints out "Hi" (as it should) but then goes on to print the prompt "Please choose an option" twice. If I enter N characters and press enter, the prompt gets printed N times.
This same behaviour happens when I use fgets() with a limit of 2.
How do I get this loop working properly? It should only take the first character of input and then do something once according to what was entered.
EDIT
So using fgets() with a larger buffer works, and stops the repeated prompt issue:
fgets(choice, 80, stdin);
This kind of helped: How to clear input buffer in C?
When you getc the input, it's important to note that the user has put in more than one character: at the very least, the stdin contains 2 chars:
2\n
when getc gets the "2" the user has put in, the trailing \n character is still in the buffer, so you'll have to clear it. The simplest way here to do so would be to add this:
if (*choice == '2')
puts("Hi");
while (*choice != '\n' && *choice != EOF)//EOF just in case
*choice = getc(stdin);
That should fix it
For completeness:
Note that getc returns an int, not a char. Make sure to compile with -Wall -pedantic flags, and always check the return type of the functions you use.
It is tempting to clear the input buffer using fflush(stdin);, and on some systems, this will work. However: This behavior is undefined: the standard clearly states that fflush is meant to be used on update/output buffers, not input buffers:
C11 7.21.5.2 The fflush function, fflush works only with output/update stream, not input stream
However, some implementations (for example Microsoft) do support fflush(stdin); as an extension. Relying on it, though, goes against the philosophy behind C. C was meant to be portable, and by sticking to the standard, you are assured your code is portable. Relying on a specific extension takes away this advantage.
What seems to be a very simple problem is actually pretty complicated. The root of the problem is that terminals operate in two different modes: raw and cooked. Cooked mode, which is the default, means that the terminal does not read characters, it reads lines. So, your program never receives any input at all unless a whole line is entered (or an end of file character is received). The way the terminal recognizes an end of line is by receiving a newline character (0x0A) which can be caused by pressing the Enter key. To make it even more confusing, on a Windows machine pressing Enter causes TWO characters to be generated, (0x0D and 0x0A).
So, your basic problem is that you want a single-character interface, but your terminal is operating in a line-oriented (cooked) mode.
The correct solution is to switch the terminal to raw mode so your program can receive characters as the user types them. Also, I would recommend the use of getchar() rather than getc() in this usage. The difference is that getc() takes a file descriptor as an argument, so it can read from any stream. The getchar() function only reads from standard input, which is what you want. Therefore, it is a more specific choice. After your program is done it should switch the terminal back to the way it was, so it needs to save the current terminal state before modifying it.
Also, you should handle the case that the EOF (0x04) is received by the terminal which the user can do by pressing CTRL-D.
Here is the complete program that does these things:
#include <stdio.h>
#include <termios.h>
main(){
tty_mode(0); /* save current terminal mode */
set_terminal_raw(); /* set -icanon, -echo */
interact(); /* interact with user */
tty_mode(1); /* restore terminal to the way it was */
return 0; /* 0 means the program exited normally */
}
void interact(){
while(1){
printf( "\nPlease enter a choice: \n1)quit\n2)Something\n" );
switch( getchar() ){
case 'q': return;
case '2': {
printf( "Hi\n" );
break;
}
case EOF: return;
}
}
}
/* put file descriptor 0 into chr-by-chr mode and noecho mode */
set_terminal_raw(){
struct termios ttystate;
tcgetattr( 0, &ttystate); /* read current setting */
ttystate.c_lflag &= ~ICANON; /* no buffering */
ttystate.c_lflag &= ~ECHO; /* no echo either */
ttystate.c_cc[VMIN] = 1; /* get 1 char at a time */
tcsetattr( 0 , TCSANOW, &ttystate); /* install settings */
}
/* 0 => save current mode 1 => restore mode */
tty_mode( int operation ){
static struct termios original_mode;
if ( operation == 0 )
tcgetattr( 0, &original_mode );
else
return tcsetattr( 0, TCSANOW, &original_mode );
}
As you can see, what seems to be a pretty simple problem is quite tricky to do properly.
A book I can highly recommend to navigate these matters is "Understanding Unix/Linux Programming" by Bruce Molay. Chapter 6 explains all the things above in detail.
The reason why this is happening is because stdin is buffered.
When you get to the line of code *choice = getc(stdin); no matter how many characters you type, getc(stdin) will only retrieve the first character. So if you type "foo" it will retrieve 'f' and set *choice to 'f'. The characters "oo" are still in the input buffer. Moreover, the carriage return character that resulted from you striking the return key is also in the input buffer. Therefore since the buffer isn't empty, the next time the loop executes, rather than waiting for you to enter something, getc(stdin); will immediately return the next character in the buffer. The function getc(stdin) will continue to immediately return the next character in the buffer until the buffer is empty. Therefore, in general it will prompt you N number of times when you enter a string of length N.
You can get around this by flushing the buffer with fflush(stdin); immediately after the line *choice = getc(stdin);
EDIT: Apparently someone else is saying not to use fflush(stdin); Go with what he says.

Clearing Input Buffer in C

I have a large program, a text twist game with graphics in c. somewhere in my code i use kbhit() i did this code to clear my input buffer:
while ((c = getchar()) != '\n' && c != EOF);
This code works and wait for me to hit enter key to exit from the loop. The problem is, the loop waits me to hit enter, any other key will output in the screen (unreadable). My question, is there any other way to clear the input buffer without pressing anything, like using fflush to clear output buffer?
Assuming you're on some kind of Unix variant....
There are two things you need to clear here:
The FILE * input buffer managed by the C library.
The OS input buffer that your program has not yet read.
The first can be cleared with fflush, just like output streams, except that the data is simply discarded rather than written out.
The second requires some low-level OS I/O calls. In general you should not mix these with the FILE * I/O functions, but they should be safe between fflush and any other read/get operation.
First, you'll need to use select to see if a read operation would block. This effectively checks to see if the OS buffer is clear. If the read would not block, then you do a one-character read, and repeat the select. The key point is that you have to check if there is data to read before you read and discard it, or else it will block until there is data to read.
The code might look something like this (untested):
fflush(stdin);
int stdinin_fd = fileno(stdin);
while (1) {
fdset readset;
FD_ZERO(&readset);
FD_SET(stdin_fd, &readset);
struct timeval timeout = {0, 0};
int result = select(stdin_fd+1, &readset, NULL, NULL, timeout);
if (result == 1) {
char c;
read(stdin_fd, &c, 1);
} else if (result == 0
|| (result == -1 && errno != EINTR)) {
break;
} // else loop
}
It might be possible use a larger read-size when clearing the OS buffers, which would be more efficient, but I'm not sure about the portability of that, and anyway I'm assuming there won't be much data to clear.

Useful context of scanf(...) != EOF

Soo... I saw a guy claim this code was working on another question.
while(scanf("%X", &hex) != EOF) {
//perform a task with the hex value.
}
So, in what context does the EOF flag get thrown? I though it would just keep asking for a number indefinitely. I added another line of code to test it, and it does exactly what I expected it too.....
This isn't a file, this seems to be stdin. So.... WHEN is this code useful?
Ie, in what context is the EOF return thrown?
If you look at the documentation for scanf, you will read that the value EOF is returned if a read failure occurred before the first value was assigned. (ie end of file)
http://en.cppreference.com/w/cpp/io/c/fscanf
You could equally test:
while(scanf("%X", &hex) == 1)
This is my preference. I expect one input, so I will be explicit.
Realistically speaking, this input is good on linux because ^d will end the stream, thus throwing the 'error.'
On windows, this behavior is different... whatever it is is not ctrl+d. At least I know now though, since I use both.
Thanks!
EOF is returned on I/O error and end-of-file. With stdin, an I/O error is a rare event and with keyboard input the end-of-file indication usual takes a special key sequence.
A practical use occurs with redirected input.
Assume a program exists that reads hexadecimal text and prints out decimal text:
// hex2dec.c
#include <stdio.h>
int main(void) {
unsigned hex;
int cnt;
while((cnt = scanf("%X", &hex)) == 1) {
printf("%u\n", hex);
}
// At this point, `cnt` should be 0 or EOF
if (cnt != EOF) {
puts("Invalid hexadecimal sequence found.");
return 1;
}
return 0;
}
// hex.txt contents:
abc
123
Conversion occurs with the command
hex2dec < hex.txt
2748
291
By detecting EOF on the stdin, the program knows when to return.

Resources