When setting a character value to specified user input using the getchar() method, the user could potentially decide to not input anything, but still hit the enter key. Is there a way to check to see if the character value is "\n"?
// for example:
printf("input y/n\n");
char inp;
// the user hits enter before entering any value
inp = getchar();
getchar();
while (inp != 'y' && inp != 'n') {
inp = getchar();
getchar();
}
if (inp == 'y') {
printf("+\n");
} else {
printf("-\n");
}
example input/output
case 1
'enter'
yy results in: +
case 2
'enter'
y
y
yy results in: +
case 3
'enter'
y
'enter'
y results in: +
Would anyone be willing to explain these cases? As someone who is new to c, but relatively experienced in java, I'm curious to understand the uses and logic of getchar().
Please remove the second getchar()
// the user hits enter before entering any value
inp = getchar();
//getchar(); // this getchar() is not needed
also in
while (inp != 'y' && inp != 'n') {
inp = getchar();
// getchar(); // this getchar() is not needed
}
Related
I'm having a problem with multiple characters while using a while loop. I'm writing a code that would direct the user to a new function based on the input of either "y" or "n". When I scanf for one character it works fine; however, when the user types in multiple characters the while loop repeats.
#include <stdio.h>
int main()
{
char x;
printf("type in letter n or y\n");
scanf("%c", &x);
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
scanf(" %c", &x);
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
For example, if I type in hoyp, it would say "Invalid, ..." 2 times and then the "y works" would be written on the third line. How can the code be changed so that the invalid would only be said once, and the user must input again to allow the program to continue?
This is how scanf behaves. It keeps reading in all the characters you've entered. You can accept a string as input first using fgets and extract and check only its first character. fgets allows you to specify the exact number of characters to be read. I have first declared a char array of size 4096. This will work when the input is up to 4095 characters. You can adjust the size as per your needs.
#include <stdio.h>
int main()
{
char x, buffer[4096];
printf("type in letter n or y\n");
fgets(buffer, 4096, stdin);
x = buffer[0];
while (x!= 'Y' && x!='N' && x!= 'n' && x!='y')
{
printf("Invalid, please type Y/N to continue: \n");
fgets(buffer, 4096, stdin);
x = buffer[0];
}
if (x== 'Y' || x == 'y')
{
printf("y works");
}
if (x =='N' || x =='n')
{
printf("n works");
}
}
Here is my approach to the problem:
I have used fgets() instead of scanf(). See why
here.
I have used the suggestion by users jamesdlin and M.M in this question to solve the repeated printing issue when the input is more than one character or if the input is empty. I encourage you to read the whole thread to know more about this issue.
(Optional) Used some extra headers for better code readability in the loop conditions. I think the fgets() could be used in the condition of the while() but I got used to the pattern I have written below.
Edit: added a condition to reject inputs with length > 1. Previously, inputs that starts with 'y' or 'n' will be accepted (and are interpreted as 'y' or 'n' respectively) regardless of their length.
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
void clearInput();
int main()
{
// allocate space for 'Y' or 'N' + '\n' + the terminator '\0'
// only single inputs will be accepted
char _inputbuff[3];
char choice;
bool isValidInput = false;
while(!isValidInput) {
printf("Please enter your input[y/n]: ");
// use fgets() instead of scanf
// this only stores the first 2 characters of the input
fgets(_inputbuff, sizeof(_inputbuff), stdin);
// don't accept empty input to prevent hanging input
if(_inputbuff[0] == '\n') {
printf("Empty input\n");
// go back to the top of the loop
continue;
}
// input is non-empty
// if the allocated space for the newline does not
// contain '\n', reject the input
if(_inputbuff[1] != '\n') {
printf("Input is more than one char.\n");
clearInput();
continue;
}
choice = _inputbuff[0];
// printf("The input is %c\n", choice);
// convert the input to uppercase for a 'cleaner' code
// during input validation
choice = toupper(choice);
// the input is not 'Y' or 'N'
if(choice != 'Y' && choice != 'N') {
printf("Please choose from Y or N only.\n");
// go back to the top of the loop
continue;
}
// the input is 'Y' or 'N', terminate the loop
isValidInput = true;
}
// conditions for 'Y' or 'N'
if(choice == 'Y') {
printf("The input is Yes.\n");
return 0;
}
if(choice == 'N') {
printf("The input is No.\n");
return 0;
}
}
void clearInput() {
int _clear;
// clear input stream to prevent repeated printing of invalid inputs
while ((_clear = getchar()) != '\n' && _clear != EOF ) { }
}
(This is my first time answering a question and it has been a while since I have used C so feel free to give suggestions/corrections regarding my answer. Thanks!)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
int valid=0, running=1;
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%d", &c);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
scanf(" %c", retry);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(choice==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
Here the user should enter either 1 or 2. If the user enters any other number or character then I want to ask the user to input again. The program works fine if the user enters any other number like 5/6/7 etc. But if the user enters a character the program goes into an infinite loop. I can break the loop with a scanf status check but then the program stops. Instead, I want to prompt the user to input again if he enters anything except 1 or 2.
scanf returns the number of successful input assignments, or EOF on end of file or error. You should get in the habit of checking this return value. In this case of scanf( "%d", &c ), you should expect a return value of 1 on a successful input.
The %d conversion specifier tells scanf to skip over any leading whitespace, then read characters up to the first character that isn't a decimal digit, leaving that character in the input stream.
Example - suppose you enter "12.3" as an input. scanf( "%d", &c ) will read, convert, and assign the "12" portion of the input to c and return 1. The ".3" portion of the input is left in the input stream.
If you call scanf( "%d", &c ) again, the first thing it sees is that '.' character, so it immediately stops reading (you have a matching failure).
Since no input was actually read, nothing gets assigned to c and scanf returns 0. This will keep happening until you remove that '.' character with some other input operation like getchar() or scanf( "%*c" ), etc.
You should always check the result of scanf to make sure you read as many items as you expect:
int r = 0;
do
{
r = scanf( "%d", &c );
if ( r == EOF )
{
// end of file or error signaled on the input stream; in this case we
// just exit the program
exit( 0 );
}
else if ( r == 0 )
{
// matching failure - there's a bad character in the input stream
// remove it with getchar and try again
getchar();
}
} while( r != 1 );
// at this point we either have good input or have already exited the program
Apparently, using scanf with %d, but input characters causes buffer issues. See code below for one way to avoid the problem:
#include <stdio.h>
#include <stdlib.h>
void generate(){
printf("generate\n");
}
void retrieve(){
printf("retrieve\n");
}
int main(){
int valid=0, running=1, idx=0, c=-100;
char retry;
char s[25];
printf("\n1. Generate\n2. Retrieve");
while(!valid){
printf("\n\nEnter choice> ");
scanf("%s", s);
c = atoi(s);
if(c==1){
valid=1;
generate();
while(running){
printf("\n\nPress Y to generate again. Press N to retrieve> ");
while(scanf(" %c", &retry)==0);
if(retry == 'Y' || retry == 'y'){
idx++;
generate();
}else if(retry == 'N' || retry == 'n')
running = 0;
else
printf("Invalid input. Try again.");
}
retrieve();
}else if(c==2){
valid = 1;
retrieve();
}else
printf("Invalid input. Try again");
}
return(0);
}
One possible execution is shown below:
1. Generate
2. Retrieve
Enter choice> Bad
Invalid input. Try again
Enter choice> Worse
Invalid input. Try again
Enter choice> 1
generate
Press Y to generate again. Press N to retrieve> Y
generate
Press Y to generate again. Press N to retrieve> n
retrieve
I want to read one keyboard input - and depending whether it is valid or not proceed with the operation or do something else. If it's invalid the input should be repeated.
At this point I'm aware already scanf is not the tool of my desire, but that here would be the default-code (if scanf would work as intended):
char val;
int incorrect = 0;
printf("Do you wish to proceed?: <Yy/Nn>");
do
{
incorrect = 0;
scanf(" %c", &val); //Changed to " %c" alread from "%c"
//getchar(); //Tried already, doesn't solve the problem
if (!(val == 'y' || val == 'Y' || val == 'n' || val == 'N'))
{
printf("Invalide Input!\n");
incorrect = 1;
}
} while (incorrect);
The problem is if instead of a one-character input there is a longer input the error-message will be repeated by the number of the characters.
Also, if instead of for instance 'n' the input is "nasdlfjas" it is still considered as a valid input.
Changing the scanf to val = getchar(); if (kind != EOF) (with or without the EOF-part) as suggested here doesn't change the behavior. But the Error-message is added right after the question.
The "GetStuff()" from this solution suffers from the same problem. The error-output is multiple and one single correct character in the whole input determines the result.
This variant however is doing better, but evaluates the result on the first character of the entire string.
Other variants which include a while((c = getchar()) != EOF); which is the preferred variant to use getchar have similar issues of going through the loop-body before the input of the character (and therefore printing the error).
I decided to read a string instead of a character and then just evaluate the result by dealing with the string itself. Something like:
do{
int c, line_length = 0;
int i = 0;
while ((c = getchar()) != EOF && c != '\n' && line_length < MAX_LINE - 1)
{
sentence[i++] = c;
line_length++;
}
// String Stuff
if (!(val == 'y' || val == 'Y' || val == 'n' || val == 'N'))
{
printf("Invalide Input!\n");
incorrect = 1;
}
} while (incorrect);
But again there will "Invalide Input!" be printed before entering anything.
What exactly would be the proper way to evaluate just the input of a single character?
On a character input in the first scanf(), the second one doesn't run. getchar() isn't working either for Try Again input. It skips to take input for Would you like to play again? (Y/N)? It seems that your_choice is supposed to take the character and check it afterward but the character is actually being taken by ch. What is causing it to work like this and how to resolve the issue. I've tried re-initializing the variables but doesn't work.
#include <stdio.h>
void choice(int);
int main() {
char ch;
int random, your_choice;
do {
srand(time(NULL));
system("cls");
printf("** 0 is for Rock **\n");
printf("** 1 is for Scissors **\n");
printf("** 2 is for Lizard **\n");
printf("** 3 is for Paper **\n");
printf("** 4 is for Spock **\n");
printf("\nEnter your choice here:");
scanf("%d", &your_choice);
random = rand() % 5; //random number between 0 & 4
if ((your_choice >= 0) && (your_choice <= 4)) {
//choice printer omitted for this post
if ((random == ((your_choice + 1) % 5)) || (random == ((your_choice + 2) % 5)))
printf("\n\n... and you win!!!\n");
else if ((random == ((your_choice + 3) % 5)) || (random == ((your_choice + 4) % 5)))
printf("\n\n... and you lose!!!\n");
else if (random == your_choice)
printf("\n\nUnfortunately, it's a tie!\n");
} else
printf("\nWell, this is wrong! Try again with a number from 0 to 4!!\n");
printf("\nWould you like to play again? (Y/N)?: ");
scanf(" %c", &ch);
} while (ch == 'y' || ch == 'Y');
return 0;
}
If the user enters characters that cannot be converted to a number, scanf("%d", &your_choice); returns 0 and your_choice is left unmodified, so it is uninitialized. The behavior is undefined.
You should test for this and skip the offending input this way:
if (scanf("%d", &your_choice) != 1) {
int c;
/* read and ignore the rest of the line */
while ((c = getchar()) != EOF && c != '\n')
continue;
if (c == EOF) {
/* premature end of file */
return 1;
}
your_choice = -1;
}
Explanation:
scanf() returns the number of successful conversions. If the user types a number, it is converted and stored into your_choice and scanf() returns 1, if the user enters something that is not a number, such as AA, scanf() leaves the offending input in the standard input buffer and returns 0, finally if the end of file is reached (the user types ^Z enter in windows or ^D in unix), scanf() returns EOF.
if the input was not converted to a number, we enter the body of the if statement: input is consumed one byte at a time with getchar(), until either the end of file or a linefeed is read.
if getchar() returned EOF, we have read the entire input stream, no need to prompt the user for more input, you might want to output an error message before returning an error code.
otherwise, set your_choice to -1, an invalid value so the read of the code complains and prompts for further input.
Reading and discarding the offending input is necessary: if you do not do that, the next input statement scanf(" %c", &ch); would read the first character of the offending input instead of waiting for user input in response to the Would you like to play again? (Y/N)?: prompt. This is the explanation for the behavior you observe.
I wanted to check whether input given is integer input or not. I did not wanted to store input in a string. After seeing several questions on stackoverflow and by hit and trial, I have created following code
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
if(a == '\n')
scanf("%c",&a);
else
{
while(a != '\n')
scanf("%c",&a);
}
}
It works but according to my understanding, the following should have also worked
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
while(a != '\n')
scanf("%c",&a);
}
Can someone please tell me why above did not worked ?? Also if someone has better solution please give it also.
Note :I am considering 12qwe also as an invalid input. I just want integers.
The problem with
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
while(a != '\n')
scanf("%c",&a);
}
is that if a happens to contain '\n' before the scan, and the scan fails, the inner while loop doesn't run at all. So
if the scan failed trying to parse an int from the input stream because the input was e.g. "ab c\n", the offending input remains in the input stream, the next scanf in the outer while loop control fails parsing an int again, a remains '\n', repeat.
if an input error occurred before reading a character from the stream into a, the scanf in the outer loop control fails because of a corrupted stream, repeat.
In the other version,
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
if(a == '\n')
scanf("%c",&a);
else
{
while(a != '\n')
scanf("%c",&a);
}
}
you make at least some progress as long as there is input to be read from the stream, since whatever a contains, you read at least one character from the input stream before attempting the next parsing of an int. It will also result in an infinite loop if the input stream is corrupted/closed/ends prematurely, e.g. if you redirect stdin from an empty file. You can have that loop also output multiple "Please enter an integer only : " messages by giving input like `"a\nb\nc\nd\n".
So you should check whether scanf encountered the end of the stream or some other read error before converting anything from the input, and abort in that case:
int reads;
while(((reads = scanf("%d%c", &num, &a)) != 2 && reads != EOF) || a != '\n')
{
printf("Please enter an integer only : ");
// read at least one character until the next newline
do {
reads = scanf("%c", &a);
}while(reads != EOF && a != '\n');
}
This is a wrong way to do. You can rather read the input using fgets() and then parse your string for integer ASCII range.
fgets(s, 1024, stdin)
for (i=0; s[i] ! = '\0';i++) {
if( s[i] <'0' && s[i] >'9')
// not an integer<br>
You can also use standard functions like isalnum, isalpha etc.
it works……
while(scanf("%d%c",&num,&a) != 2 || a != '\n')
{
printf("Please enter an integer only : ");
do{
scanf("%c",&a);
}while(a != '\n');
}