C Program - How to deny any non-numerical input - c

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.

Related

Why this code is not re-prompting correctly?

I am totally new to C.
I want to re-prompt when the input value is not a number and when it's a number it should be less than 1. when I give any sort of string it works correctly. But when I give any number it goes to the next line without printing "Number: ".Then in the next line, it prints "Number: "again if the input value is less than 1.
int x;
printf("Number: ");
while (scanf("%d", &x) != 1 || x < 1 )
{
printf("Number: ");
scanf("%*s");
}
and the result it gives me is this
result
It would be wise to use fgets to read the line, then use sscanf to parse the input. That way, you can get the line, then check if sscanf succeeds!
Simple example:
int target_number; // The number you will have at the end of this.
while (1) { // Loop for rechecking number
char line[16]; // See notes on how to read the whole line.
fgets(line, sizeof(line), stdin);
// We use 1 here because sscanf returns the number of format specifiers that are matched. Since you only need one number, we use 1.
if (sscanf(line, "%d", &target_number) != 1) {
fprintf(stderr, "Invalid Input! Please enter in a valid number.");
continue;
}
}
// Do whatever you will with target_number
Notes
You can see how to read the whole line here.
This code is not safe!
It does not protect against buffer overflow attacks and the like. Please see this on the right way to do this. If this is just for learning, you don't need to worry.
/*This is how it will work the way you want.
If I understand your goal correctly, of course?
If your goal was different,
please specify and I will try to solve it.*/
#include<stdio.h>
int main(void)
{
int x;
printf("Number: ");
while (scanf("%d.%*d", &x)!=1 || x<0)
{
if(x<0)
{
printf("Number: ");
continue;
}
else
printf("Number: ");
scanf("%*s");
}
printf("Hello world!");
return 0;
}

fgets doesn't stop reading user input

I found some challenge on reddit to make a program which will sum up all DnD dice rolls. Number of throws is unlimited therefore I created this while loop.
I used fgets to input the string, (I can't input only integers because the input is for example 1d3, where 1 is number of dice thrown, and 3 is number of sides of the dice thrown.)
When the user is prompted to input dice, fgets never stops reading user input.
For example:
To end inputting dice type 0
1d3
1d4
1d5
0
0
^C
Main function:
int main(void)
{
char input[MAXSIZE];
int sum = 0;
printf("To end inputting dice type 0\n");
while(*(input) != 0);
{
fgets(input, sizeof(input), stdin);
printf("Debug: input = ");
puts(input);
printf("\n");
sum += dice(input);
printf("Debug: sum = %d\n", sum);
}
printf("Sum of dice rolls is %d.", sum);
return 0;
}
Firstly, the literal value of the character input 0 is not 0. In ASCII, it is 48 (decimal).
Try
while(*(input) != '0') // (1) - use the character literal form
// (2) remove the ;
That said, the standard output is usually line buffered. You need to force a flush if you want to see the outputs in the terminal. You can do that by either
add a newline
printf("Debug: input = \n");
use fflush(stdout).
Try this:-
while(fgets(input, sizeof input, stdin) != NULL)
or
while(fgets(input, sizeof input, stdin))
The issue was really simple and such a beginner mistake I feel shameful for even asking the question.
The semicolon after the while loop.
Thanks all for helping me out.
char input[MAXSIZE] = { 0 }; // initialise input!
// otherwise you get to here and access an uninitialised variable:
while(*(input) != 0); // <--- and a semicolon right there!!! Remove that!
In fact I think the loop you want is while (fgets(input, sizeof input, stdin) && strcmp(input, "0\n"))... note that I've hoisted the fgets into the loops control expression.
You should probably do a check after calling fgets to ensure a newline is read, for example
while (fgets(input, sizeof input, stdin) && strcmp(input, "0\n")) {
size_t n = strcspn(input, "\n");
if (input[n] == '\n') input[n] = '\0';
else assert(input[n] == '\0'), // #include <assert.h>
fscanf(stdin, "%*[^\n]"),
fgetc(stdin);
There's no undefined behaviour associated with reading unsigned integers when using fscanf, so if you only plan on using positive values you can use that instead of fgets if you wish, i.e.
unsigned dice_count, dice_sides;
while (fscanf(stdin, "%ud%u", &dice_count, &dice_sides) == 2) {
printf("You chose to roll %u times with dice that contain %u sides\n", dice_count, dice_sides);
}

how do I make sure that the user is entering a integer in c?

I want the program to ask the user for a number, and if the user does not enter a number the program will say "input not a integer."
Thx for the help guys!
I propose this (it doesn't handle integer overflow):
#include <stdio.h>
int main(void)
{
char buffer[20] = {0}; // 20 is arbitrary;
int n; char c;
while (fgets(buffer, sizeof buffer, stdin) != NULL)
{
if (sscanf(buffer, "%d %c", &n, &c) == 1)
break;
else
printf("Input not integer. Retry: ");
}
printf("Integer chosen: %d\n", n);
return 0;
}
EDIT: Agreed with chux suggestions below!
One possible way: use scanf() function to read the input. It returns the number of items it successfully read.
Another way: read the input as string with scanf() of fgets() and then try to parse it as integer.

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 check if the user input an integer using scanf

I created a program to make a diamond out of *'s. I am looking for a way to check if the type of input is an integer in the C language. If the input is not an integer I would like it to print a message.
This is what I have thus far:
if(scanf("%i", &n) != 1)
printf("must enter integer");
However it does not display the message if it's not an integer. Any help/guidance with this issue would be greatly appreciated!
you can scan your input in a string then check its characters one by one, this example displays result :
0 if it's not digit
1 if it is digit
you can play with it to make your desired output
char n[10];
int i=0;
scanf("%s", n);
while(n[i] != '\0')
{
printf("%d", isdigit(n[i]));
i++;
}
Example:
#include <stdio.h>
#include <string.h>
main()
{
char n[10];
int i=0, flag=1;
scanf("%s", n);
while(n[i] != '\0'){
flag = isdigit(n[i]);
if (!flag) break;
i++;
}
if(flag)
{
i=atoi(n);
printf("%d", i);
}
else
{
printf("it's not integer");
}
}
Use fgets() followed by strtol() or sscanf(..."%d"...).
Robust code needs to handle IO and parsing issues. IMO, these are best done separately.
char buf[50];
fgets(buf, sizeof buf, stdin);
int n;
int end = 0; // use to note end of scanning and catch trailing junk
if (sscanf(buf, "%d %n", &n, &end) != 1 || buf[end] != '\0') {
printf("must enter integer");
}
else {
good_input(n);
}
Note:
strtol() is a better approach, but a few more steps are needed. Example
Additional error checks include testing the result of fgets() and insuring the range of n is reasonable for the code.
Note:
Avoid mixing fgets() and scanf() in the same code.
{ I said scanf() here and not sscanf(). }
Recommend not to use scanf() at all.
strtol
The returned endPtr will point past the last character used in the conversion.
Though this does require using something like fgets to retrieve the input string.
Personal preference is that scanf is for machine generated input not human generated.
Try adding
fflush(stdout);
after the printf. Alternatively, have the printf output a string ending in \n.
Assuming this has been done, the code you've posted actually would display the message if and only if an integer was not entered. You don't need to replace this line with fgets or anything.
If it really seems to be not working as you expect, the problem must be elsewhere. For example, perhaps there are characters left in the buffer from input prior to this line. Please post a complete program that shows the problem, along with the input you gave.
Try:
#include <stdio.h>
#define MAX_LEN 64
int main(void)
{ bool act = true;
char input_string[MAX_LEN]; /* character array to store the string */
int i;
printf("Enter a string:\n");
fgets(input_string,sizeof(input_string),stdin); /* read the string */
/* print the string by printing each element of the array */
for(i=0; input_string[i] != 10; i++) // \0 = 10 = new line feed
{ //the number in each digits can be only 0-9.[ASCII 48-57]
if (input_string[i] >= 48 and input_string[i] <= 57)
continue;
else //must include newline feed
{ act = false; //0
break;
}
}
if (act == false)
printf("\nTHIS IS NOT INTEGER!");
else
printf("\nTHIS IS INTEGER");
return 0;
}
[===>] First we received input using fgets.Then it's will start pulling each digits out from input(starting from digits 0) to check whether it's number 0-9 or not[ASCII 48-57],if it successful looping and non is characters -- boolean variable 'act' still remain true.Thus returning it's integer.

Resources