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;
}
Related
Working on a C knapsack program that will have a UI like interface, I have come to a point where I need for the user to be able to enter in characters for commands and while all of the ones which require only a simple one character input are quite simple I need to be able to allow the user to enter in a char and an int at the same time in the cases of adding or removing a number from the knapsack. While I know this can be done with two separate inputs from the user I'm wondering how can this be done in the same line without requiring the user to enter in two separate inputs. For example if the user types a 7 then it will add 7 to the knapsack.
CODE
#include <stdio.h>
#include "knapsack.c"
#include <stdlib.h>
#include <string.h>
int main()
{
listitemptr k2 = NULL;
char input[100];
int *returnval;
while(*input != 'q'){
printf("> ");
fgets(input, 100, stdin);
if(*input == 'p'){
KnapsackPrint(&k2);
}
else if(*input == 'a'){
printf("test\n");
sscanf(input, "%d", returnval);
printf("%d\n", *returnval);
}
else if(*input == 'r'){
}
else if(*input == 'l'){
}
else if(*input == 's'){
}
}
}
There are many solutions for your user input proble. I would suggest you read one line at a time with fgets() and parse it with sscanf():
#include <ctype.h>
#include <stdlib.h>
#include <string.h>
#include "knapsack.c"
int main() {
char input[100];
listitemptr k2 = NULL;
int i, returnval = 0;
char command;
for (;;) {
printf("> ");
if (!fgets(input, sizeof input, stdin))
break;
i = strspn(input, " \t\n"); /* skip blanks */
command = input[i++];
if (command == '#' || command == '\0') {
/* ignore comment lines and blank lines */
continue;
}
if (command == 'q' && input[i] == '\n')
break;
}
if (command == 'p') {
KnapsackPrint(&k2);
continue;
}
if (command == 'a') {
int item;
if (sscanf(input + i, "%i", &item) != 1) {
printf("invalid input\n");
continue;
}
KnapsackAdd(&k2, item);
continue;
}
// add more commands
printf("unknown command: %c\n", command);
}
return returnval;
}
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 )
I have to enter random names and weights and finish the loop when I hit enter instead of the name. However the way I used to detect the enter does not serve to take the name so getting two variables. The question is how to put the enter of the test and name using the same variable
#include <stdio.h>
#include <string.h>
#include <ctype.h>
int main() {
int c, weight[1000], i = 0;
char name[1000];
puts ("Enter the person's name or only enter to end the program");
if ((c = getchar() == '\n')) {
} else {
while (c != '\n') {
printf("Enter the name");
scanf("%s", &nome[i]);
i++;
printf("Enter the \n");
scanf("%i", &weight[i]);
}
}
return 0;
}
Here is a simple example
#include <stdio.h>
#include <string.h>
int main(void)
{
char name[1000] = {0}; // initialise
puts ("Enter the person's name or only enter to end the program");
if (fgets(name, sizeof(name), stdin) != NULL) {
name [ strcspn(name, "\r\n") ] = 0; // remove trailing newline etc
if (strlen(name)) {
printf("The name entered was: %s\n", name);
}
else {
printf("You did not enter a name\n");
}
}
return 0;
}
First off, names is an array of characters and you're treating it like an array of strings. Secondly, loops that need to exit based on input are most clearly expressed with break:
char *names[1000];
int count = 0;
while (1) {
char *r, buf[1000];
int len;
char *r = fgets(buf, 1000, stdin);
if (NULL == r) break; // EOF
if ((len = strlen(buf)) < 2) break; // NL only
r = malloc(len + 1);
if (NULL == r) break;
strcpy(r, buf);
names[count] = r;
count += 1;
...
}
...
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
}
//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
}