[RESOLVED] ANSI-C and reading use input from stdin
(This is about C, not C++...)
I'm just fiddling with reading some simple user input. The idea is that the user enters a string of less than 20 chars long and then later on enters their age as an integer.
A problem arises if the user enters "asdflajsdkjflakjsdlflajsldjlfajlkdlkjfasdfkjjfaiou" and hits enter. Only the first 19 chars are read (which is good), but the rest is left on the stdin stream. Thus when the age is requested, the remaining text is read straight away.
My Question:
Is there a built-in function that will let me clear out whats remaining in stdin? I have thought of just using a loop to get eat all the remaining queued-up bytes, but that seems a bit messy to me for some reason.
I put 2 comments in th places where I need to clear out the input...
Code:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char firstName[20];
int end = 0;
int age = -1;
printf("Please enter your first name\n: ");
fgets(firstName, sizeof(firstName), stdin); //read the user's name from stdin
/*flush input here?*/
end = strlen(firstName) - 1;
if(firstName[end]=='\n')
firstName[end] = '\0'; //kill the newline if there is one
printf("Hello %s, enter your age: ", firstName);
scanf("%d", &age);
/*flush input again here?*/
if(age < 18)
printf("You are a mere pipsqueak!");
else if(age < 25)
printf("You are a noob!");
else if(age < 30)
printf("You are a budding expert!");
else if(age < 50)
printf("You are an old fart!");
else if(age < 75)
printf("You are a grizzled ancient!");
printf("\n");
return 0;
}
Re: ANSI-C and reading use input from stdin
I think the function you're looking for is (from stdio.h)
Let me know if it works.
Re: ANSI-C and reading use input from stdin
Sunburnt, yeah I did try that earlier (I saw it mentioned in the man pages for "stdio.h") however GCC said it was not defined. Further investigation suggested it was not available under linux, neither is fpurge() apparently.
Re: ANSI-C and reading use input from stdin
fflush(stdin) works on Microsoft compilers, but is heavily frowned upon because, as far as the standard is concerned, you cannot flush input streams.
No, a loop eating up all remaining input is exactly the way to go. Best pack it into a function.
Re: ANSI-C and reading use input from stdin
Do you know what condition I should look for in order to stop 'eating'?
Checking getchar() against: NULL, EOF and '\n' are all apparently incorrect and give varying results.
I'm surprised that something like this isn't mentioned in the man pages.
Hmm, maybe if I use putchar to shove a newline back onto stdin and then eat until i find it? That sounds even dirtyer, yuck.
Re: ANSI-C and reading use input from stdin
Check against both EOF and '\n', that should work. But do this only if the string fgets read does not end in '\n', otherwise there'll be no '\n' and getchar() will block.
Of course, if it's EOF, you might as well terminate.
And no, using putchar() won't work.
Re: ANSI-C and reading use input from stdin
Yes you are right, getchar() is blocking, and does so until I hit enter a second time.
Re: ANSI-C and reading use input from stdin
RESOLVED (kind of)
Ok, I ended up writing a new function that does what I want.
awgets(char*, int) is similar to fgets() except that awgets doesn't keep the newline char, and also it flushes the stin stream after reading one line of input. This is useful for reading a string like "i like cheese" into a char array.
The integer you supply is ideally the length to the char array you are reading into. If you supply 20, then awgets will read no more than 19 characters and it will then add a null terminator in the last element of the destination array. Thus avoiding buffer overruns.
For example if you call:
Code:
char text[20];
...
awgets(text, 20);
and then the user enters:
Hello everyone, I'm Fred!
...then the text array will now contain "Hello everyone, I'm\0".
The remaining " Fred\n" is discarded and removed from stdin.
This stops the user's input for one prompt overflowing and affecting future prompts.
Quote:
Originally Posted by awinput.h
#pragma once
/****** Prototypes ******************************/
int awgets(char *dest, int size);
/****** Definitions ******************************/
int awgets(char *dest, int size)
{
/*
This function allows you to read a string of maximum length: <size-1>.
If the user types more than that number of chars then the rest
(up to a newline character, which is discarded) is removed
from stdin so that future reads are not affected.
Returns the number of characters read from stdin
*/
int i = 0;
char ch = 'a';
char bail = 0;
size--; //leave a char free for the null terminator
while(i < size)
{
ch = fgetc(stdin);
if(ch == EOF || ch == '\n') //handle the end of the stream
{
bail = 1;
break;
}
*dest++ = ch; //store the char that was read
i++; //count the number of chars read so far
}
*dest = '\0'; //set the null terminator
//we've either hit the end of the stream or a newline OR we've
//read enough characters, so empty the remaining data on stdin...
if(!bail)
while( (ch = fgetc(stdin)) != EOF && ch != '\n' );
return i;
}
Re: [RESOLVED] ANSI-C and reading use input from stdin
The function should somehow report that it truncated the input.
Re: [RESOLVED] ANSI-C and reading use input from stdin
Even though the data that was lost is unrecoverable?
Ok, so something like...
Code:
int awgets(char *dest, int size, char *truncated)
{...}
setting that char* to 1 if some data was lost?
Basically like an "out" parameter in C#.
Re: [RESOLVED] ANSI-C and reading use input from stdin
Yes, even then. You never know when you need the info.