check input program gets stuck in an infinte loop - c

I'm trying to create a program that asks to type something and check if it is an integer. If it is an integer, then print "the integer is ...". Else, print "try again" and waits for another input. However, the program prints an infinite number of "try again" if you type in a character. Here's the source code:
#include <stdio.h>
#include <stdbool.h>
int main()
{
int inp;
bool t = 1;
printf("type an integer\n");
while (t) {
if (scanf("%i", &inp) == 1) {
printf("The integer is %i", inp);
t = 0;
} else {
printf("try again");
scanf("%i", &inp);
}
}
}

OP's code fail to consume the offending non-numeric input. It remains in stdin, for the next input function. As it is unfortunately just another scanf("%i", &inp) which fails the same way - infinite loop.
After attempting to read an int, read the rest of the line.
#include <stdio.h>
#include <stdbool.h>
int main() {
int inp;
int scan_count;
printf("Type an integer\n");
do {
scan_count = scanf("%i", &inp); // 1, 0, or EOF
// consume rest of line
int ch;
while ((ch == fgetchar()) != '\n' && ch != EOF) {
;
}
} while (scan_count == 0);
if (scan_count == 1) {
printf("The integer is %i\n", inp);
} else {
puts("End of file or error");
}
}
An even better approach would read the line of user input with fgets(). Example

When you entered a char, the variable inp in scanf("%d", &inp) would get null, since the input that doesn't match the format string. And the character you input would remain in the buffer, so that's the reason both your scanf would not stop.
A simplest way to fix this is modify your second scanf("%i", &inp); to scanf("%c", &c); (don't forget to declare a char c in your main function).

check here while(t) its in an infinite loop because you have to set a condition for t something like while(t==1) or while(t>1) or (t<1) something like that. saying while(t) means that t can be anything and it will continue to run.

There is nothing in to break the while loop.
consider getting rid of the boolean, and simply using a while (1) loop with a break. Also you should be using "%d" to indicate an integer in scanf/printf. And there is no need for the scanf call in the else, since your program would loop back and call scanf again anyway.
#include <stdio.h>
int main() {
int inp = 0;
printf("type an integer\n");
while (1) {
if (scanf("%d", &inp) == 1) {
printf("The integer is %d", inp);
break;
}
else {
printf("try again");
}
}
return 0;
}
I hope this helped.

Related

How to fix - unexpected output using getchar() and do-while

I am trying to make a simple code that will read a char from input and execute "Correct" or "Incorrect input" and run the code again until the correct input is entered. First of all it does not work for capital X. The other issue that I want to fix is that after the incorrect input I have to press enter to get the "Enter x" message, instead of getting in immediately after the incorrect input message.
#include <stdio.h>
int main()
{
do
{
printf("Enter x\n");
if (getchar()=='x'|| getchar()=='X')
{
printf("Entered char is X\n");
return 0;
}
else
{
printf("Input incorrect! Please try again!!!\n");
}
}
while (getchar()!='x' || getchar()!='X');
return 0;
}
You need to store the input in a variable, otherwise you keep asking for input several times in a row, for each getchar call.
For weird historic reasons, getchar actually returns an int, since the value EOF that can be returned from it is an int. So the variable must be int.
And finally, each time the user hits enter, a invisible line feed character \n is appended to the input stream. This character does you no good, so you should discard it with an extra read.
#include <stdio.h>
int main (void)
{
int input;
do
{
printf("Enter x\n");
input = getchar();
getchar(); // extra getchar to chew up line feed from stdin
if (input=='x'|| input=='X')
{
printf("Entered char is X\n");
}
else
{
printf("Input incorrect! Please try again!!!\n");
}
} while (input!='x' && input!='X');
return 0;
}
Please note that the opposite of input=='x'|| input=='X' is input!='x' && input!='X' (De Morgan's laws). "If input is not 'x' and input is not 'X' then loop".
When you hit the ENTER key the newline character \n is placed in input buffer. You need to consume that newline character in order to read the next character.
Also you are reading two time, which is unnecessary in this case. So your code should be like this
#include <stdio.h>
int main()
{
char inp;
do
{
printf("Enter x\n");
inp = getchar();
getchar(); // reading the newline character '\n'
if (inp == 'x'|| inp =='X')
{
printf("Entered char is X\n");
return 0;
}
else
{
printf("Input incorrect! Please try again!!!\n");
}
}
while (inp !='x' || inp !='X');
return 0;
}
p.s There is no need to put condition checking in while loop, since you are returning in if condition. while(true) would work fine. Thanks #bruno for pointing that out.
In your code:
if (getchar()=='x'|| getchar()=='X')
getchar() is called twice.
Instead, you should write it this way:
char c = getchar();
if (c=='x'|| c=='X')
for the second part, if your goal is print the message on a new line, then just simply change your printf to:
printf("\nInput incorrect! Please try again!!!\n");

C Program - How to deny any non-numerical input

I've just started learning the language of C, and would love your help in cleaning up / simplifying my code if you know a better way to reach the following.
I want a program to ask for a number, and if that is found then proceed to print and end, however if anything else is put in (e.g. a letter key), then I want the program to loop asking for a number until one is given.
I started off by using a simple scanf input command, but this seemed to go into an infinite loop when I tried to check if a valid number (as we define them) was put in.
So instead I have ended up with this, from playing around / looking online, but I would love to know if there is any more efficient way!
//
// Name & Age Program
// Created by Ben Warren on 1/3/18.
//
#include <stdio.h>
int main (void)
{
//Setting up variables
int num;
char line[10]; /* this is for input */
//Collecting input
printf("Please enter any number? \t");
scanf("%d", &num);
//If Invalid input
while (num==0)
{
printf("\nTry again:\t");
fgets(line, 10, stdin); //turning input into line array
sscanf(line, "%d",&num); //scaning for number inside line and storing it as 'num'
if (num==0) printf("\nThat's not an number!");
}
//If Valid input
{
printf("\n%d is nice number, thank you! \n\n", num);
*}*
return 0;
}
Instead of checking if the value is different to 0, check the return value of
sscanf. It returns the number of conversions it made. In your case it should be 1. Unless the return value is 1, keep asking for a number.
#include <stdio.h>
int main(void)
{
int ret, num;
char line[1024];
do {
printf("Enter a number: ");
fflush(stdout);
if(fgets(line, sizeof line, stdin) == NULL)
{
fprintf(stderr, "Cannot read from stdin anymore\n");
return 1;
}
ret = sscanf(line, "%d", &num);
if(ret != 1)
fprintf(stderr, "That was not a number! Try again.\n");
} while(ret != 1);
printf("The number you entered is: %d\n", num);
return 0;
}
That is not a bad approach for someone new to C. One small improvement would be to actually check the return value of scanf(), since it returns the number of arguments successfully retrieved. Then you could get away from relying on num being 0 to indicate the input was valid. Unless you do want to specifically flag 0 as invalid input.
int ret = scanf("%d", &num);
ret == 1 would mean an integer was succesffully read into num, ret == 0 would mean it was not.
Consider using strtol to parse a string for a long int. This also allows you to detect trailing characters. In this example if the trailing character is not a newline, the input can be rejected. strtol can also detect overflow values. Read the documentation to see how that works.
#include <stdio.h>
#include <stdlib.h>
int main (void)
{
//Setting up variables
long int num = 0;
char line[40] = ""; /* this is for input */
char *parsed = NULL;
printf("Please enter any number? \t");
fflush ( stdout);
while ( fgets(line, 40, stdin))
{
parsed = line;//set parsed to point to start of line
num = strtol ( line, &parsed, 10);
if ( parsed == line) {//if parsed equals start of line there was no integer
printf("Please enter a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
continue;
}
if ( '\n' != *parsed) {//if the last character is not a newline reject the input
printf("Please enter only a number? \t");
printf("\nTry again:\t");
fflush ( stdout);
}
else {
break;
}
}
if ( !parsed || '\n' != *parsed) {
fprintf ( stderr, "problem fgets\n");
return 0;
}
printf("\n%ld is nice number, thank you! \n\n", num);
return 0;
}
0 (zero) is a number...
But I see what you want to do...
You can check for a valid number, using isdigit or a combination of similar functions
I think its also important to follow the advice of other answers to use the return value from scanf using code such as:
int ret = scanf("%d", &num);
and examining ret for success or failure of scanf.

First input skipped, straight to next input

I'm facing a problem with my code of a simple login program. The problem I'm facing is when I use a switch case or if statement for the option of logging in as an Admin or a User, the input for username is skipped and goes directly to password, and no matter what I type it gives me my error message. Instead, I want it to receive my username first then the password. It works fine on its own if there is only code for either Admin OR User, only one but not when there are more than one. Please help. Note: I'm using the same functions for both admin and user just to check if it works. The picture shows the output.I'm a C newbie, so minimal jargon perhaps? Code as follows:
#include<stdio.h>
#include<conio.h>
#include<stdlib.h>
char username[18];
char pass[16];
void arequest()
{
printf("\nPlease Enter username:");
fflush(stdin);
gets(username);
printf("\nPlease Enter Password:");
fflush(stdin);
gets(pass);
}
void averify()
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
_getch();
}
else
{
printf("Invalid Password");
_getch;
}
}
else
{
printf("Invalid Username");
_getch();
}
}
int choice;
int main()
{
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection:");
scanf_s("%d", &choice);
if (choice == 1)
{
arequest();
averify();
}
else if (choice == 2)
{
arequest();
averify();
}
else
{
printf("Invalid Choice");
_getch();
return main;
}
return 1;
}
output
You are flushing the input stream with fflush(). fflush(stdin) is undefined behavior in most cases, and is at best implementation-dependent. To clear the extra characters from the input stream, consider writing a little function like this:
void clear_stream(void)
{
int c;
while ((c = _getch()) != '\n' && c != EOF)
continue;
}
Remove the calls to fflush(). You do not need to clear the stream after gets(username) since gets() discards the newline. Add a call to clear_stream() after this line in main():
scanf_s("%d", &choice);
There may be extra characters, including a newline, left in the input stream after the call to scanf_s(), and these need to be removed before trying to read user input again. In some cases scanf()_s (and scanf()) will skip over initial whitespaces in reading input, but _getch() and getchar() will not. This illustrates one of the dangers of using scanf().
printf("\nPlease Enter your selection:");
scanf("%d", &choice);
clear_stream();
Also, gets() is considered so dangerous that there is never a reason to use it for anything at all. Use fgets() instead. fgets() does keep the newline, where gets() discards it, so I often write my own version of gets() using fgets() that is safe:
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
The library conio.h is nonstandard, as are the functions _getch() and scanf_s(). You should use the stdio.h functions getchar() and scanf(). The value returned by scanf() is the number of successful assignments, and you should check this to be sure that the input is as expected. In your program, if the user enters a letter at the selection prompt, no assignment is made, and the value of choice remains uninitialized. The code continues without handling this problem. choice could be initialized to some reasonable value, such as int choice = -1;. Alternatively, you can check the return value from scanf() to see if an assignment was made, and proceed accordingly.
I noticed that you are returning 1 from main(). You should return 0 unless there is an error. And, I see that you return main in the event of an invalid choice. Maybe you meant to return 1 here? And it appears that you have forgotten to #include <string.h> for the strcmp() function.
Finally, I don't understand why username, pass, and choice are global variables. This is a bad practice. These should be declared in main() and passed to functions as needed. It would be a good idea to #define the global constants MAXNAME and MAXPASS instead of hard-coding the array dimensions.
I didn't intend this to be a full-scale code review when I started, but that is what it turned into. Here is a revised version of your program that implements the suggested changes:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXNAME 18
#define MAXPASS 16
void clear_stream(void)
{
int c;
while ((c = getchar()) != '\n' && c != EOF)
continue;
}
char * s_gets(char *st, int n)
{
char *ret;
int ch;
ret = fgets(st, n, stdin);
if (ret) {
while (*st != '\n' && *st != '\0')
++st;
if (*st)
*st = '\0';
else {
while ((ch = getchar()) != '\n' && ch != EOF)
continue; // discard extra characters
}
}
return ret;
}
void arequest(char username[MAXNAME], char pass[MAXPASS])
{
printf("\nPlease Enter username:");
s_gets(username, MAXNAME);
printf("\nPlease Enter Password:");
s_gets(pass, MAXPASS);
}
void averify(char username[MAXNAME], char pass[MAXPASS])
{
if (strcmp(username, "admin") == 0)
{
if (strcmp(pass, "apass") == 0)
{
printf("Successful Login");
getchar();
}
else
{
printf("Invalid Password");
getchar();
}
}
else
{
printf("Invalid Username");
getchar();
}
}
int main(void)
{
char username[MAXNAME];
char pass[MAXPASS];
int choice;
printf("Welcome to Railway Reservation System");
printf("\n1.Admin \n2.User");
printf("\nPlease Enter your selection: ");
if (scanf("%d", &choice) == 1) {
clear_stream();
if (choice == 1)
{
arequest(username, pass);
averify(username, pass);
}
else if (choice == 2)
{
arequest(username, pass);
averify(username, pass);
}
else
{
printf("Invalid Choice: %d\n", choice);
getchar();
return 1;
}
} else {
clear_stream(); // stream has not yet been cleared
printf("Nonnumeric input");
getchar();
}
return 0;
}
EDIT
The OP mentioned in the comments that scanf() was causing problems in Visual Studio. Apparently Visual Studio tries to force the use of scanf_s(). The issue with this function is not that it is inherently bad, just that it is nonstandard. One solution might be to use the s_gets() function already added to the code to read the user selection into a character buffer, and then to use sscanf() to extract input. This has an advantage in that there is no need to call the clear_stream() function after s_gets(), because s_gets() cleans up after itself, so the clear_stream() function could now be removed altogether from the program. This can be accomplished with only a small change in main():
char choice_buffer[10];
int choice;
...
if (s_gets(choice_buffer, sizeof(choice_buffer)) &&
sscanf(choice_buffer, "%d", &choice) == 1) {
if (choice == 1)
...
} else {
printf("Nonnumeric input");
getchar();
}
s_gets() reads up to the first 9 characters (in this case) of a line of user input into choice_buffer, which is an array that will hold chars (there is more space in choice_buffer than is needed to hold a single digit choice and a '\0'). If there is an error, s_gets() returns a NULL pointer, otherwise a pointer to the first char of choice_buffer is returned. If the return value of s_gets() was non-NULL, then sscanf() assigns the first int stored in the buffer to choice. If no int is found in the string, sscanf() returns a value of 0, failing the conditional test.

scanf validation sits and waits for another input. Why?

I was working on this sample exercise, and everything works as I would like it to, but there is one behavior I don't understand.
When providing input: if I make consecutive invalid entries everything seems to work great. But if I enter a number different from 1,2,3 in the case of the first question, or 1,2 in the case of the second question, the program just sits there until a new input is given. If another invalid entry is made, it goes back to the error "invalid entry" message, and if an appropriate number is entered, everything moves along fine.
I do not understand why it stops to wait for a second input...anyone?
Thanks guys.
#include <stdio.h>
static int getInt(const char *prompt)
{
int value;
printf("%s",prompt);
while (scanf("%d", &value) !=1)
{
printf("Your entry is invalid.\nGive it another try: %s", prompt);
getchar();
scanf("%d", &value);
}
return value;
}
int main() {
int wood_type, table_size, table_price;
printf("Please enter " );
wood_type = getInt("1 for Pine, 2 for Oak, and 3 for Mahogany: ");
printf("Please enter ");
table_size = getInt("1 for large, 2 for small: ");
printf("\n");
switch (wood_type) {
case 1:
table_price = (table_size == 1)? 135:100;
printf("The cost of for your new table is: $%i", table_price);
break;
case 2:
table_price = (table_size == 1)? 260:225;
printf("The cost of for your new table is: $%i", table_price);
break;
case 3:
table_price = (table_size == 1)? 345:310;
printf("The cost of for your new table is: $%i", table_price);
break;
default:
table_price = 0;
printf("The cost of for your new table is: $%i", table_price);
break;
}
}
You most likely need to flush your input buffer (especially with multiple scanf calls in a function). After scanf, a newline '\n' remains in the input buffer. fflush does NOT do this, so you need to do it manually. A simple do...while loop works. Give it a try:
edit:
static int getInt(const char *prompt)
{
int value;
int c;
while (printf (prompt) && scanf("%d", &value) != 1)
{
do { c = getchar(); } while ( c != '\n' && c != EOF ); // flush input
printf ("Invalid Entry, Try Again...");
}
return value;
}
The blank line you get if you enter nothing is the normal behavior of scanf. It is waiting for input (some input). If you want your routine to immediately prompt again in the case the [Enter] key is pressed, then you need to use another routine to read stdin like (getline or fgets). getline is preferred as it returns the number of characters read (which you can test). You can then use atoi (in <stdlib.h>) to convert the string value to an integer. This will give you the flexibility you need.
example:
int newgetInt (char *prompt)
{
char *line = NULL; /* pointer to use with getline () */
ssize_t read = 0; /* number of characters read */
size_t n = 0; /* numer of chars to read, 0 no limit */
static int num = 0; /* number result */
while (printf ("\n %s ", prompt) && (read = getline (&line, &n, stdin)) != -1)
{
if ((num = atoi (line)))
break;
else
printf ("Invalid Input, Try Again...\n");
}
return num;
}
If some invalid input is entered, it stays in the input buffer.
The invalid input must be extracted before the scanf function is completed.
A better method is to get the whole line of input then work on that line.
First, put that input line into a temporary array using fgets(),
then use sscanf() (safer than scanf because it guards against overflow).
#include <stdio.h>
int main(int argc, const char * argv[]) {
char tempbuff[50];
int result, d , value;
do
{
printf("Give me a number: ");
fgets( tempbuff, sizeof(tempbuff), stdin ); //gets string, puts it into tempbuff via stdin
result = sscanf(tempbuff, "%d", &value); //result of taking buffer scanning it into value
if (result < 1){ //scanf can return 0, # of matched conversions,
//(1 in this case), or EOF.
printf("You didn't type a number!\n");
}
}while (result < 1);
//some code
return 0;
}
Knowledge from: http://www.giannistsakiris.com/2008/02/07/scanf-and-why-you-should-avoid-using-it/

Letter guessing game weird output

So here is my code:
#define _CRT_SECURE_NO_DEPRECATE
#include <stdio.h>
#define MAX_GUESSES 4
int PlayGame(char guess);
int WinOrLose(char userguess, char solution);
int main()
{
FILE* infile;
char correctlet;
int games,
igame,
result;
infile = fopen("inputLet.txt", "r");
printf ("Welcome to the letter guessing game!\n");
printf ("Your job is to guess a random letter.\n");
printf("You can guess each letter a maximum of 4 times,\n");
printf ("and you will get a hint after every guess.\n");
printf ("LET'S DO THIS!\n\n>");
printf ("\nHow many games would you like to play (1-3)?\n>");
scanf ("%d",&games);
for(igame=0;igame<games;igame++)
{
fscanf(infile," %c",&correctlet);
printf("This is game %d\n", igame+1);
result = PlayGame (correctlet);
if (result == 0)
{
printf ("\nCongratulations, you guessed the right letter!\n");
}
else
{
printf ("\nUnfortunately, you did not guess the right letter. Better luck next time!\n");
}
}
return 0;
}
int PlayGame(char solution)
{
int guessnumber,
result;
char userguess;
guessnumber = 0;
while(guessnumber < MAX_GUESSES)
{
printf("Please enter your guess\n>");
scanf("%c", &userguess);
if (sizeof userguess == 0)
{
continue;
}
else if (sizeof userguess >=1)
{
printf ("Your guess was %c\n",userguess);
result = WinOrLose (userguess, solution);
if (result == 0)
{
return 0;
break;
}
else if (result == 1)
{
if (solution < userguess)
{
printf("The correct letter comes before %c alphabetically\n", userguess);
}
else if (solution > userguess)
{
printf("The correct letter comes after %c alphabetically\n", userguess);
}
guessnumber ++;
}
}
}
}
int WinOrLose (char userguess, char solution)
{
if(solution==userguess)
{
return 0;
}
else if (solution != userguess)
{
return 1;
}
}
The output asks for the number of games, and then it outputs please enter your guess your guess was (blank) The correct letter comes after (blank) Please enter your guess and THEN it allows for user input. So why is it going through one iteration of PlayGame without asking for user input? I have tried everything I can think of and can't fix the problem. I am compiling on VC++ 2010, if that helps.
Thanks in advance!
The simple answer is to flush your buffers.
The stdin buffer, the buffer that takes instructions from the keyboard (or a pipe) and submits it to the program occasionally gets some characters "stuck" in it. Junk characters that never quite get submitted, extra returns, etc. that will cause scanf() to think it reached the proper end, but actually hasn't.
fflush(stdin);
The function fflush "flushes" a buffer. The effect of this is to consume data from a buffer until the data received is the character '\0' (NULL). This means that it's reached the last of the data that is currently in the buffer.
Calling this before calling scanf() means that when scanf() is called, you reasonably know that the program will block on scanf() until you've submitted, and not just consume some junk from the buffer.

Resources