I have written the below small code with several conditions on number entered by the user
#include<stdio.h>
int main()
{
int userInput;
while(1)
{
printf("Press '1':To Print\n");
scanf("%d",&userInput);
if(userInput==1)
{
printf("ABCD\n");
}
else
{
printf("WARNING:Pressed invalid key");
}
}
}
When I press any number then it works fine, but when I press up arrow/any character key and press enter the loop runs infinite times.
Why is this happening and is there any way to prevent it?
You're not checking whether scanf failed. May something like this help?
#include <stdio.h>
#include <ctype.h>
#include <stdbool.h>
void printHelp(bool afterInvalid) {
if(afterInvalid)
fprintf(stderr, "\nInvalid input, try again!\n");
printf("Press 1 to print\nPress 3 to break\nInput: ");
}
int main() {
while(1) {
int userInput;
printHelp(false);
if(scanf("%d", &userInput) == 0) {
char ch;
bool reachedNewline = false;
do {
if(reachedNewline) {
printHelp(true);
reachedNewline = false;
}
ch = getchar();
if(ch == '\n')
reachedNewline = true;
} while(!isdigit(ch));
ungetc(ch, stdin);
continue;
}
if(userInput == 1)
printf("ABCD\n");
else if(userInput == 3) {
printf("Breaking!\n");
break;
} else
printHelp(true);
}
return 0;
}
this makes it an infinite loop that keep asking to print..
#include<stdio.h>
int main()
{
int userInput;
while(1!=EOF)
{
printf("Press '1':To Print\n");
scanf("%d",&userInput);
if(userInput==1)
{
printf("ABCD\n");
}
else
{
printf("WARNING:Pressed invalid key");
}
}
}
Check the return value from scanf("%d"... and consume the non-numeric input as needed.
#include<stdio.h>
int main(void) { // Add void
int ch = 0;
while (ch != EOF) {
int userInput;
printf("Press '1':To Print\n");
// Expect 0, 1 or EOF to be returned
int fields_scanned = scanf("%d",&userInput);
if (fields_scanned == 1) {
printf("ABCD %d\n", userInput);
}
else if (fields_scanned == 0) {
printf("WARNING:Pressed invalid key\n");
}
// Consume remaining characters in the line
while ((ch = fgetc(stdin)) != '\n' && ch != EOF) {
;
}
}
return 0; // Not required, yet good practice.
}
All in all, recommend using fgets()/other code instead of scanf()
#define INT_MAX_SIZE (sizeof (int) * CHAR_BITS /3 + 3)
fputs(Prompt, stdout);
char buf[INT_MAX_SIZE*2 +1]; // I like 2x expected size, no need to be stingy here.
if (fgets(buf, sizeof buf, stdin) == NULL) break; // No more input or error
// Use sscanf() or strtol(), etc
if (sscanf(buf, "%d", &userInput) == 1) {
; // Success
} else {
; // Failure
}
Related
I have some functions like push, pop, delete etc. for a singly linked list and implemented the following function to get user input:
void user_input(){
char input[10];
while(fgets(input, 9, stdin)){
if(strncmp(input, "add", 3) == 0){
int x;
printf("Number to add: ");
scanf("%d", &x);
push(x);
printf("%d added.\n", x);
}
else if(strncmp(input, "del", 3) == 0){
int x;
printf("Number to delete: ");
scanf("%d", &x);
delete(x);
printf("%d deleted.\n", x);
}
else if(strncmp(input, "q", 1) == 0){
printf("Program terminated.\n");
break;
}
// and some other if else statements...
}
So I can input a string like "add", then strncmp will compare it and I get another prompt asking me to enter the number I want to add and stores in x using scanf. Something like this:
add
Number to add: 5
5 added.
However I am looking for a way to be able to enter something like this:
add 5
del 2
etc.
Basically a string and int value in one line separated by space, instead of writing "add" first, pressing enter and writing the number. I tried using sscanf but had no luck yet.
It is much easier to step past input errors if you use fgets and then sscanf. You simply read another input string instead of messing around unblocking the input when invalid data was entered.
#include <stdio.h>
#include <string.h>
void push(int x) {
}
void delete(int x) {
}
void triple(int x, int y, int z) {
}
int main(void)
{
char input[100];
char oper[20];
int x, y, z; // romantic expansion for more than one argument
int res;
int err;
while(1) {
err = 0;
if(fgets(input, sizeof input, stdin) != NULL) {
res = sscanf(input, "%19s%d%d%d", oper, &x, &y, &z);
if(res == 2 && strcmp(oper, "add") == 0){
push(x);
printf("%d added.\n", x);
}
else if(res == 2 && strcmp(oper, "del") == 0) {
delete(x);
printf("%d deleted.\n", x);
}
else if(res == 4 && strcmp(oper, "trip") == 0) { // fantasy
triple(x, y, z);
printf("%d %d %d tripled.\n", x, y, z);
}
else if(res == 1 && strcmp(oper, "q") == 0){
printf("Program terminated.\n");
break;
}
// some other if else statements...
else {
err = 1;
}
}
else {
err = 1;
}
if(err) {
printf("Bad operation.\n");
}
}
return 0;
}
You could use scanf() like
char str[10];
int c;
if( scanf("%9s %d", str, &c)!=2 )
{
perror("Something went wrong.");
}
The width for %s is one less than the size of str. The extra character is for the \0.
scanf() returns the number of successful assignments that it made which in this case should be 2.
Now if you enter an input like
del 2
str will have "del" and c will have 2.
A good strategy for what are trying to do would be:
Read the input line by line.
Process each line.
Continue until there is no input or the user chose to quit.
Here's the core outline.
// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100
void processLine(char line[]);
int main()
{
char line[LINE_SIZE];
while ( fgets(line, LINE_SIZE, stdin) != NULL )
{
processLine(line);
}
}
void processLine(char line[])
{
}
In processLine, your first job is to pull the command. Do the needful based on the command.
void processLine(char line[])
{
char command[20];
int num = 0;
// Read the command and gather the number of characters read
// This allows you to read more data from (line + num)
int n = sscanf(line, "%19s%n", command, &num);
if ( n != 2 )
{
// Problem
exit(0);
}
// The command is to quit, exit.
if ( isQuitCommand(command) )
{
exit(0);
}
char* commandData = line + num;
if ( isAddCommand(command) )
{
processAdd(commandData);
}
else if ( isDeleteCommand(command) )
{
processDelete(commandData);
}
else { ... }
}
Here's a version of the program with stubs used for couple of functions.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
// Make LINE_SIZE big enough for your needs
#define LINE_SIZE 100
void processLine(char line[]);
int isQuitCommand(char command[]);
int isAddCommand(char command[]);
int isDeleteCommand(char command[]);
void processAdd(char commandData[]);
void processDelete(char commandData[]);
int main()
{
char line[LINE_SIZE];
while ( fgets(line, LINE_SIZE, stdin) != NULL )
{
processLine(line);
}
}
void processLine(char line[])
{
char command[20];
int num = 0;
// Read the command and gather the number of characters read
// This allows you to read more data from (line + num)
int n = sscanf(line, "%19s%n", command, &num);
if ( n != 2 )
{
// Problem
exit(0);
}
// The command is to quit, exit.
if ( isQuitCommand(command) )
{
exit(0);
}
char* commandData = line + num;
if ( isAddCommand(command) )
{
processAdd(commandData);
}
else if ( isDeleteCommand(command) )
{
processDelete(commandData);
}
else
{
// ...
}
}
int isQuitCommand(char command[])
{
return (command[0] == 'q');
}
int isAddCommand(char command[])
{
return (strcmp(command, "add") == 0);
}
int isDeleteCommand(char command[])
{
return (strcmp(command, "del") == 0);
}
void processAdd(char commandData[])
{
// Add code to process commandData
}
void processDelete(char commandData[])
{
// Add code to process commandData
}
I need to check whether the input is number. My code looks something like this:
int input;
while ( scanf(" %s %d", string, &input) != EOF) {
if ( isNotANumber(input) ) {
printf("Not a number"); }
doSomethingElse(input, string);
}
EDIT: I need to be accepting input and calling the function doSomethingElse(input) until the user enters EOF.
isNotANumber is a mock function, I don't have that function, I'm asking how could I write it.
EDIT 2: Variable string needs to be a string, variable input needs to be an integer.
EDIT 3: I tried separating my code into this:
while (scanf(" %s", string) != EOF) {
if (scanf("%d",&input) != 1) {
printf("not a number");
}
doSomething();
}
But it stil doesn't work for input like "4a".
For example, you can change it as follows.
#include <stdio.h>
#define doSomethingElse(input) do{ printf("your input is %d\n", input); }while(0)
int main(void){
int input;
int status;
while ((status = scanf("%d", &input)) != EOF) {
if ( status == 0 ) {
printf("Not a number\n");
while(getchar() != '\n'); //clear input
}
else {
doSomethingElse(input);
}
}
}
However, this can not check input like 123.456. (accept 123)
So, It is recommended to input with fgets and check with strtol.
As already pointed out, like scanf(" %s %d", string, &input) can not check the input after the number.
So, For convenience, check backward input.
char string[32], ch;
int input;
int status;
while ((status = scanf("%31s %d%c", string, &input, &ch )) != EOF) {
if ( status == 3 && ch == '\n') {
doSomethingElse(input);
}
else {
printf("Not a number\n");
while(getchar() != '\n'); //clear input
}
}
Example using fgets and strtol
(mystrtoi has reorganized the answer of chux. thanks)
#include <stdio.h>
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#define doSomethingElse(input) do{ printf("your input is %d\n", input); }while(0)
int mystrtoi(const char *str, int *err) {
char *endptr;
*err = errno = 0;
long l = strtol(str, &endptr, 0);
if (errno == ERANGE || *endptr != '\0' || str == endptr) {
*err = 1;
}
// Only needed if sizeof(int) < sizeof(long)
if (l < INT_MIN || l > INT_MAX) {
*err = 1;
}
return (int) l;
}
int main(void){
char line[128];
char string1[32], string2[128];
int num, err;
while (fgets(line, sizeof line, stdin)){
// if(2 != sscanf(line, "%31s %31s", string1, string2)){// or use strtok to split
if(2 != sscanf(line, "%31s %127[^\n]", string1, string2)){
printf("invalid input\n");
continue;
}
num = mystrtoi(string2, &err);
if(err) {
printf("Not a number\n");
}
else {
doSomethingElse(num);
}
}
}
while ( scanf("%d", input) != EOF)
Your scanf code has two problems:
scanf returns the number of successfully read item, not EOF. Here you want to check if scanf has successfully read one integer input
scanf expects the address of the variable
You should re-write that line as:
while ( scanf("%d", &input) == 1 )
How to create a seperate function for the Continue or Stop so can always refer to there. below not a proper C but just an idea what to achieve
main()
do{
request for input...
if found invalid, Continue or stop?
...
After one complete run
ask again for Continue or stop?
...
}while(Continue)
I have tried this, but the value from the feed,Continue can't pass to the main function. is there something wrong with my logic or there is more simpler ways to do this.
struct Ans {
int Continue;
int Stop;
char choice;
};
struct Ans feed ;
void YesNo(){
int p=1;
int q=2;
char choice;
feed.Continue=0;
feed.Stop=0;
while (feed.Continue==0)
{
printf("\nDo you wish to try again (Type Y to continue Q to quit:");
scanf(" %c", &choice);
choice = toupper(choice);
if(choice == 'Y')
{
feed. Continue = p;
return;
}
else if(choice=='Q') {
feed.Stop = q;
return;
}
else
{
printf("\nError: Invalid choice\n");
do
{
feed.choice = getchar();
} while (feed.choice != '\n' && feed.choice != EOF);
}
}
}
void main{
Loop:do{
printf("Please enter(k):\n");
scanf("%d",&k);
struct Ans feed;
char str[N];
if (fgets(str, sizeof str, stdin))
{
flag = 0;
long value;
char *check;
value = strtol(str, &check, 0);
if (!isspace(*check) && *check != 0) flag = 1;
{
printf("\nInvalid Input\n");
}
while ( flag == 1)
{
YesNo();
flag = 0;
{
if (feed.Continue) {
goto Loop;
}
else if (feed.Stop) exit(0);
}
}
}
if ((k<0)||(k>N-1)) {
printf("Input value out of range");
}
YesNo();
{
if (feed.Continue) {
goto Loop;
}
else if (feed.Stop) exit(0);
}
//run something
do{
printf("\nDo you wish to try again (Type Y to continue Q to quit:");
scanf(" %c", &choice);
choice = toupper(choice);
}while((choice != 'Y') && (choice != 'Q'));
}while(choice == 'Y');
return ;
}
}
You can make ContinueOrStop function outside the main function and then call in main when you need like
void ContinueORStop()
{
do{
request for input...
if found invalid, Continue or stop?
...
After one complete run
ask again for Continue or stop?
...
}while(Continue)
}
main()
{
ContinueOrStop();
}
//why the code starts printing retry infinitely if i wrongly
enter a string in place of int i in terminal
#include<stdio.h>
#include<stdlib.h>
int main(int argc, char const *argv[])
{
int i,j=0;
while(1)
{
scanf("%d",&i);
if(i==10)
{
printf("you got the max! YOU WON\n");
break;
}
else
{
printf("%s\n","retry" );
}
}
return 0;
}
Try consuming (flushing) on bad input:
else {
while ((j = fgetc(stdin)) != '\n' && j != EOF);
printf("%s\n", "retry");
}
An alternative using fgets (is preferable because it consumes the whole line) and strtol:
#include <stdio.h> /* fgets, printf */
#include <stdlib.h> /* strtol */
#include <string.h> /* strchr */
int main(void) /* No args */
{
char buf[128], *p;
int i;
while (fgets(buf, sizeof(buf), stdin)) {
if ((p = strchr(buf, '\n')) != NULL) {
*p = '\0'; /* remove newline */
}
i = (int)strtol(buf, &p, 10); /* Base 10 */
if (*p != '\0' || i != 10) {
printf("retry\n");
} else {
printf("you got the max! YOU WON\n");
break;
}
}
return 0;
}
Read fails because of you inputted wrong type and i will have garbage value.
Add initialization to i:
int i=0, j=0;
scanf returns number of succesful reads. Add return value check to scanf:
int r = scanf("%d",&i); // Will return 1 if 1 argument was successully read
if(r == 1 && i == 10)
{
//do something
}
Edit:
As others have pointed out, it seems that scanf doesn't consume incoming bytes if input is wrong. Thus you might want to replace it wit fgets and sscanf:
int r;
char temp[32];
fgets(temp, 32, stdin); // Read input to temporary buffer
r = sscanf(temp, "%d", &i); // Try to convert value on buffer
if(r == 1 && i == 10)
{
//do something
}
I'm using this piece of code to read users input and check if it is a number or not.But sincerly it just works for numbers and letters. I want it to work with every char. For example "!?%". I have already tried to change the "isalnum" by "isascii" but that does not work.
#include <stdio.h>
#include <ctype.h>
int main ()
{
int a;
int b = 1;
char c ;
do
{
printf("Please type in a number: ");
if (scanf("%d", &a) == 0)
{
printf("Your input is not correct\n");
do
{
c = getchar();
}
while (isalnum(c));
ungetc(c, stdin);
}
else
{
printf("Thank you! ");
b--;
}
}
while(b != 0);
getchar();
getchar();
return 0;
}
Unless you have specific requirements, you should use fgets and sscanf
while (1) {
char buf[1000];
printf("Please input a number: ");
fflush(stdout);
if (!fgets(buf, sizeof buf, stdin)) assert(0 && "error in fgets. shouldn't have hapenned ..."):
/* if enter pending, remove all pending input characters */
if (buf[strlen(buf) - 1] != '\n') {
char tmpbuf[1000];
do {
if (!fgets(tmpbuf, sizeof tmpbuf, stdin)) assert(0 && "error in fgets. shouldn't have hapenned ...");
} while (buf[strlen(tmpbuf) - 1] != '\n');
}
if (sscanf(buf, "%d", &a) == 1) break; /* for sufficiently limited definition of "numbers" */
printf("That was not a number. Try again\n");
}
A correct way in strictly C89 with clearing input buffer, checking overflow looks like:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int readLong(long *l)
{
char *e,in[20];
fgets( in,20,stdin );
if(!strchr(in,'\n')) while( getchar()!='\n' );
else *strchr(in,'\n')=0;
errno=0;
*l=strtol(in,&e,10);
return *in&&!*e&&!errno;
}
int main()
{
long l;
if( readLong(&l) )
printf("long-input was OK, long = %ld",l);
else
puts("error on long-input");
return 0;
}