C programming loop logic error - c

I have some problem with the loop I trying to do.
My code will prompt user for the value 1, 2 to do something, and 3 to exit.
When I try to add the check for the input if it is not integer the loop will just loop non stop.
I wonder is my if( !input) is wrongly used here?
Can someone guide me?
thanks.
do
{
printf ("Input no\n");
scanf ("%d", &input);
if (input)
{
if ( input == 1)
{
printf ("do wat u wan if is 1\n");
}
if ( input == 2)
{
printf ("do wat u wan if is 2\n");
}
}
else if (!input)
{
printf("error\n");
}
}
while(input !=3 );
if ( input == 3)
{
printf ("exiting\n");
}

You have to clear the input buffer if scanf() doesn't read correctly.
int res = scanf ("%d", &input);
if( res == 0 )
{
int clear = 0 ;
while( ( clear = getchar() ) != EOF && clear != '\n') ;
}
In this case if res is not 1, scanf didn't read an integer and you have some characters left in stdin.
Also set input to 0 before passing it to scanf(), so that your if statement can handle the result correctly.

do
{
printf ("Input no\n");
if(scanf ("%d", &input)==1) //if `scanf` is successfull
{
if ( input == 1)
{
printf ("do wat u wan if is 1\n");
}
else if ( input == 2)
{
printf ("do wat u wan if is 2\n");
}
}else //scanning an integer failed
{
printf("Invalid input(non-numeric value entered). Breaking loop...\n");
scanf("%*s"); //discarding previous input
break; //or use `continue;` for looping once more
}
}
while(input !=3 );
printf ("exited loop\n");
The above code will do what you want and I've also removed uneccessary stuff from it.

The problem here is not your loop, but the format specifier in your call to scanf, if you call scanf with %d it expects an integer, if it doesn't receive one it will not be happy. Try calling scanf with %c instead and convert the read character to the corresponding integer value, this fixes your problem and should be managable to do by you.

Change the first part of your code to:
...
int input;
do
{
char line[256];
printf("Input no\n");
fgets(line, sizeof(line), stdin);
sscanf(line, "%d", &input);
if (input)
...
Never ever use scanf! This is almost unusable. It may lack consistent behavior across compilers.
The problem is: if scanf() encounters an item which is not usable according to the format %d, the item will stay in the input buffer forever. You can avoid this by using %s and converting afterwards. Better: on line-input use line-reading (gets()/fgets())
If you want to detect digits/non-digits in the incoming string, you could use the isdigit() function from <ctype.h>. Your code would end up in the following form:
int input;
do {
char line[256];
printf("Input no\n");
fgets(line, sizeof(line), stdin);
if (isdigit(line[0])) { /* check if first char is a number */
sscanf(line, "%d", &input); /* scan this number from string */
if (input == 1) {
printf("do wat u wan if is 1\n");
}
if (input == 2) {
printf("do wat u wan if is 2\n");
}
}
else {
input = 0; /* reset input to any value != 3 */
printf("error\n");
}
} while (input != 3);
Don't forget to #include <ctype.h>.

Related

Accept numeric values only in C

I am trying to read a numeric only value that will then execute a specific function, depending on its value using the switch statement.
I know I could just use while(option < 0 || option >3 || option != 99), but is there a workaround?
Personal work:
do
{
printf("Please choose an option :\n0. Create Database\n1.Add New Student \n2. Show All Students \n3.Delete Student\n99.Exit\n");
scanf("%d", &option);
} while (!isdigit(option));
Which does not work for some reason.
Your major problem there is that, if scanf fails to read any digits for some reason (such as if you enter x), it will return zero (the number of items successfully scanned), not populate option, and (this is the killer) leave the input pointer in the same place as before you started.
That unfortunately means, when you go back to get another number, it will just attempt reread the problematic data and probably end up in an infinite loop without allowing more input.
The scanf family is meant for formatted data and there's precious little that's more unformatted than user input :-)
Your best bet would be to use a rock-solid input function to get in a line, then just check that line to see if it's valid. Such a function can be found here. Incorporating that into your needs would give you something like:
#include <stdio.h>
#include <string.h>
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
if (buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
#include <ctype.h> // only needed for isdigit, not for above code.
int main(void) {
int option;
do {
// Only allowed up to two characters (plus '\0').
char buff[3];
int result = getLine(
"Menu\n"
" 0. Create Database\n"
" 1. Add New Student\n"
" 2. Show All Students\n"
" 3. Delete Student\n"
" 99. Exit\n"
"Please choose option: ",
buff, sizeof(buff));
// No point continuing on EOF, input stream is closed.
if (result == NO_INPUT) {
puts("\n*** End of input");
return 1;
}
// All faults just restart operation: too long, too short,
// non-digits.
if (result == TOO_LONG) continue;
if (! isdigit(buff[0])) continue;
if (buff[1] != '\0' && ! isdigit(buff[1])) continue;
// Now get the integer representation and continue unless valid.
sscanf(buff, "%d", &option);
} while (option != 99 && (option < 0 || option > 3));
printf("You chose %d\n", option);
return 0;
}
And, yes, I know I said you should check the return value from scanf but it's not necessary in the case of my posted code since you've already established at that point that the string you're scanning is a valid one- or two-digit number.
Like Carl said:
isdigit is just for check single character, and should NOT be used here to the int value obtained from scanf .
To archive your requirement, we can use scanf to obtain a string, then use strtol convert to int, check the endptr to confirm if there is any invalid character.
Code may like this:
int option;
char str[8];
char *endp;
do{
printf("Please choose an option :\n0. Create Database\n1.Add New Student \n2. Show All Students \n3.Delete Student\n99.Exit\n");
scanf("%7s", str);
option = strtol(str,&endp,10);
} while (*endp);
This is the most complete and safest solution I can come up with using scanf:
int option;
int status;
char tailchar;
status = 2;
tailchar = '\n';
do {
if(tailchar != '\n' || status != 2){
for (int c=getchar(); c!='\n' && c!=EOF; c=getchar());
}
printf("Please choose an option:\n"
" 0. Create Database\n"
" 1. Add New Student \n"
" 2. Show All Students \n"
" 3. Delete Student\n"
"99. Exit\n");
status = scanf(" %d%c", &option, &tailchar);
} while (status != 2 || option < 0 || (option >3 && option != 99));
if(tailchar != '\n'){
for (int c=getchar(); c!='\n' && c!=EOF; c=getchar());
}
It only accepts valid options, and cleans any bad input by the user before asking to choose again.

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.

check input program gets stuck in an infinte loop

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.

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/

How to end while loop by pressing the 'Enter' key, not any alphabet key?

I want to end while loop by pressing the 'Enter' key, not any alphabet key. I could not figure out how I can do that.
I have done it such that, if the input is not the digit it will exit, but I want the input to be 'Enter' key.
void main (void)
{
float f;
float total=0.0;
printf("Enter numbers to be add: ");
while (scanf("%f",&f)==1)
{
total=total+f;
printf("Enter another # to be add: ");
scanf("%1.0f",&f);
}
printf("Addition Total = %1.0f",total);
}
Try fgets... should work.
http://www.codecogs.com/reference/computing/c/stdio.h/fgets.php
using your frame work you should read in a string and then check if it is blank. If the string is blank you can end execution. If the string is not blank you should scanf the string.
Use sscanf (http://www.cplusplus.com/reference/clibrary/cstdio/sscanf/) to read the string after you have verified that it is not blank.
You can use fgets and sscanf instead:
char buffer[100];
while (fgets(buffer, sizeof(buffer), stdin))
{
/* On DOS/Windows an empty line might be 2 characters ("\r\n") */
if (strlen(buffer) == 1)
break; /* Only newline in buffer */
if (sscanf(buffer, "%f", &f) == 1)
{
total += f;
printf("Enter another number: ");
}
}
Try to use getch
c = null
while(c != 0x0D)
{
c = getch();
}
More info

Resources