#include "stdafx.h"
#include <stdlib.h>
void main()
{
char buffer[20];
int num;
printf("Please enter a number\n");
fgets(buffer, 20, stdin);
num = atoi(buffer);
if(num == '\0')
{
printf("Error Message!");
}
else
{
printf("\n\nThe number entered is %d", num);
}
getchar();
}
The above code accepts a number in the form of a string and converts it to integer using atoi. If the user inputs a decimal number, only the bit before the decimal is accepted. Moreover, if the user enters a letter, it returns 0.
Now, I have two queries:
i) I want the program to detect if the user entered a number with decimal point and output an error message. I don't want it to take the part before the decimal point. I want it to recognize that the input is invalid.
ii) If atoi returns 0 in case there are letters, how can I validate it since the user can enter the number 0 as well?
Thanks.
atoi is not suitable for error checking. Use strtol or strtoul instead.
#include <errno.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
long int result;
char *pend;
errno = 0;
result = strtol (buffer, &pend, 10);
if (result == LONG_MIN && errno != 0)
{
/* Underflow. */
}
if (result == LONG_MAX && errno != 0)
{
/* Overflow. */
}
if (*pend != '\0')
{
/* Integer followed by some stuff (floating-point number for instance). */
}
There is the isdigit function that can help you check each character:
#include <ctype.h>
/* ... */
for (i=0; buffer[i]; i++) {
if (!isdigit(buffer[i])) {
printf("Bad\n");
break;
}
}
Related
Our task for school lesson is to input a number of integers. We don't know how many there will be.
I would like to know if there is a possibility to format scanf function that either stores integer or terminate itself by pressing enter.
Can I somehow put together scanf("%d") which only stores integers and scanf("%[^\n]) which terminates scanf function?
What I have known yet is that I cannot use scanf("%d%[^\n]) because scanf is waiting for that one integer, which I don't want to input because I already stored all integers I had to.
I don't really like a possibility to store string of all those integers into an array and then convert it to elements of another array with the exact numbers.
The scanf function is difficult to use correctly.
Instead, read a line at a time with fgets. If the entered string is just a newline, you exit the loop. If not, use strtol to parse the value. You'll know if just an integer was entered if the end pointer points to the newline at the end of the input.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main()
{
char line[100], *p;
long val;
while (fgets(line, sizeof(line), stdin)) {
// if enter was pressed by itself, quit loop
if (!strcmp(line, "\n")) {
break;
}
errno = 0;
val = strtol(line, &p, 10);
if (errno) {
perror("error reading value");
} else if ((p != line) && (*p == '\n')) {
// a valid integer was read
printf("read value %ld\n", val);
} else {
// a non-integer was read or extra characters were entered
printf("not a valid integer: %s", line);
}
}
return 0;
}
Scan a character. Skip space and tab. Exit on newline.
Unget most recent character and try to scan an integer. If unable to scan an integer, scan and discard non-digit except space tab and newline.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main ( void) {
char i = '\0';
int value = 0;
int result = 0;
printf ( "type number separated by space then enter\n");
while ( 1 == scanf("%c",&i)) {//scan a character
if ( ' ' == i || '\t' == i) {
continue;
}
if ( i == '\n') {
break;//newline so leave loop
}
ungetc ( i, stdin);//replace the character in input stream
if ( 1 == ( result = scanf ( "%d", &value))) {
printf ( " number entered as %d\n", value);
}
else {
scanf ( "%*[^0-9 \t\n]");//clean non digits except space tab newline
//or you could just break;
}
}
return 0;
}
#include <stdio.h>
int main(int argc, char** argv) {
int num = 0;
printf("Input: ");
scanf("%d", &num); <<<
printf("%d\n", num);
return 0;
}
scanf("%d", &num);
Clang-Tidy: 'scanf' used to convert a string to an integer value, but function will not report conversion errors; consider using 'strtol' instead
I wrote a very simple code with CLion and it recommends me 'strtol' instead of 'scanf'.
But I'm using only integer variable and there is no strings. I can't figure out why the inspection message pops up.
How do I modify this code?
How do I modify this code?
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
enum { INPUT_SIZE = 30 };
int main () {
char *ptr;
long ret;
char str[INPUT_SIZE];
fgets(str, INPUT_SIZE, stdin);
ret = strtol(str, &ptr, 10);
if( ret == LONG_MAX || ret == LONG_MIN ) {
perror("!! Problem is -> ");
}
else if (ret) {
printf("The number is %ld\n", ret);
}
else {
printf("No number found input is -> %s\n", ptr);
}
return(0);
}
If successful, strtol() returns the converted long int value.
If unsuccessful, strtol() returns 0 if no conversion could be
performed. If the correct value is outside the range of representable
values, strtol() returns LONG_MAX or LONG_MIN, according to the sign
of the value. If the value of base is not supported, strtol()
returns 0.
If unsuccessful strtol() sets errno to one of the following values:
Error Codes:
EINVAL The value of base is not supported.
ERANGE The conversion caused an overflow.
Source : IBM
Can you check overflow using scanf() for example?
Input: 1234 stackoverflow
Output: The number is 1234
Input: 123nowhitespace
Output: The number is 123
Input: number is 123
Output: No number found input is -> number is 123
Input: between123between
Output: No number found input is -> between23between
Input: 9999999999999999999
Output: !! Problem is -> : Result too large
Maybe off-topic but, Jonathan Leffler says in his comments(in another topics) that handle warnings just as errors.
I have a variable int number and I need code that only allows introducing 1, 2, 3, 4 or 5 to the variable.
I have scanf and I just do an if...else to check out if the number is between 1 and 5, but the point is that I don't know what to do if I introduce a character, e.g. 'q'. I mean, I want the program to say "That's a character, not a number."
use sscanf on a buffer (or in the example below, argv the program argument) to attempt to find a digit, then a character.
The return code from sscanf is :
...the number of input items successfully matched
and assigned, which can be fewer than provided for, or even zero in the
event of an early matching failure.
Here is an example program
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
#include <string.h>
int main(int argc, char ** argv){
int val=-1;
char other;
int code;
if (argc !=2 ) {
printf("please give an arg to program\n");
exit(0);
}
code=sscanf(argv[1],"%d",&val);
if (code == 1) {
printf( "number %d", val);
}
else {
code=sscanf(argv[1],"%c",&other);
if (code == 1) {
printf("character is %c", other);
}
else {
printf("error occured");
}
}
}
Only accept input of 1 to 5, inclusive:
#include <stdio.h>
int main() {
int rc, answer = 0;
printf("A number between 1 and 5: ");
rc = scanf("%i", &answer);
if(rc == EOF || rc == 0 || answer > 5 || answer <= 0) {
fprintf(stderr, "Only numbers between 1 and 5, please.\n");
return -99;
} else {
printf("You entered: %d\n", answer);
return 0;
}
}
Return Value
These functions return the number of input items successfully matched and assigned, which can be fewer than provided for, or even zero in the event of an early matching failure.
The value EOF is returned if the end of input is reached before either the first successful conversion or a matching failure occurs. EOF is also returned if a read error occurs, in which case the error indicator for the stream (see ferror(3)) is set, and errno is set indicate the error.
Basically, scanf will continue to scan until a match is made or it fails. An example program would be this:
#include <stdio.h>
int main() {
int number, result;
result = scanf("%i", &number);
if(result == EOF) {
// an error occured.
fprintf(stderr, "That's not a number");
} else {
// logic! yay!
// the result is in `number`.
}
}
Use man scanf for more information.
Try with this code:
#include <stdio.h>
int clearStdin()
{
while (getchar() != '\n');
return 1;
}
int main()
{
int integer = 0;
char character;
printf("Enter an integer not a character:\n");
do
{
printf("? ");
} while (((scanf("%d%c", &integer, &character) != 2) || (character != '\n')) && clearStdin());
printf("You entered the following integer: %d\n", integer);
return 0;
}
scanf will return the number of successful conversions and assignments, so you can check that to make sure you read at least 1 digit character:
int value;
...
if ( scanf( "%d", &value ) == 1 )
{
// read at least 1 digit
}
else
{
// first character was not whitespace or a digit
}
What's this "read at least 1 digit" nonsense? The %d conversion specifier tells scanf to skip any leading whitespace, then read and convert decimal digits until it finds a non-digit character. This means if you type a string like "12w4", scanf will convert and assign 12 to value, return 1, and leave "w4" in the input stream to foul up the next read.
That's probably not the behavior you want. You could scan for a following non-digit character, like so:
#include <ctype.h>
...
int value;
char follow;
...
if ( scanf( "%d%c", &value, &follow ) == 2 )
{
if ( !isspace( follow ))
{
fprintf( stderr, "detected non-digit character in input\n" );
}
}
else
{
// first character was not whitespace or a digit
}
You've caught that case, but your input may now be in a bad state; how do you know if the next character was part of a bad input or not? IOW, how do you know the input was 12w4 and not 12w 4?
Personally, I take a different approach. I read the input as a string, then use strtol to perform the conversion:
/**
* Assuming a 64-bit integer value, average 3.2 bits per decimal digit, we
* need to store up to 22 digits plus an optional sign character plus the 0
* terminator
*/
define INPUT_SIZE 24
...
char input[INPUT_SIZE] = {0};
long value = 0;
...
if ( fgets( input, sizeof input, stdin ))
{
char *newline = strchr( input, '\n' );
if ( !newline )
{
fprintf( stderr, "Input is too long for a 64-bit integer...rejecting\n" );
/**
* Cycle through the input stream until we see the newline character
*/
while ( fgets( input, sizeof input, stdin ) && !strchr( input, '\n' ))
;
}
else
{
char *chk; // will point to the first character that's *not*
// part of a decimal integer
long temp = strtol( input, &chk, 10 );
if ( !isspace( *chk ) && *chk != 0 )
{
fprintf( stderr, "%s is not a valid integer input\n", input );
}
else
{
value = temp;
}
}
}
This allows me to catch cases where the input value is obviously too long to store in the target data type, something from which scanf does not protect you. It also allows me to catch cases where a non-digit character is fat-fingered in the middle of the input and reject the whole input outright, something else from which scanf doesn't protect you.
Simple read 1 char and test it.
int ch;
while ((ch = fgetc(stdin)) != EOF) {
if ((ch < '1') || (ch > '5')) {
fputs(stdout, "That's a not number 1 to 5.\n");
}
else {
ch -= '0';
printf("Good: %d entered\n", ch);
}
}
I'm working on a challenge problem from my textbook where I'm supposed to generate a random number between 1-10, let the user guess, and validate their response with isdigit(). I (mostly) got the program to work with the code below.
The main issue I ran into is that using isdigit() required the input to be stored as a char, which I then had to convert before the comparison so the actual number was compared and not the ASCII code for the number.
So my question is, since this conversion only works for numbers 0 - 9, how can I change the code to allow for the user to successfully guess 10 when that's the number that is generated? Or what if I wanted the game to have a range of 1-100 - how would I then accomplish this? Can I not verify the input with isdigit() if I'm using a possible range greater than 0-9? What is a better way to verify user input?
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <time.h>
int main(void) {
char buffer[10];
char cGuess;
char iNum;
srand(time(NULL));
iNum = (rand() % 10) + 1;
printf("%d\n", iNum);
printf("Please enter your guess: ");
fgets(buffer, sizeof(buffer), stdin);
sscanf(buffer, "%c", &cGuess);
if (isdigit(cGuess))
{
cGuess = cGuess - '0';
if (cGuess == iNum)
printf("You guessed correctly!");
else
{
if (cGuess > 0 && cGuess < 11)
printf("You guessed wrong.");
else
printf("You did not enter a valid number.");
}
}
else
printf("You did not enter a correct number.");
return(0);
}
You can use the return value of scanf to determine whether the read was successful. So, there are two paths in your program, successful reading and failed reading:
int guess;
if (scanf("%d", &guess) == 1)
{
/* guess is read */
}
else
{
/* guess is not read */
}
In the first case, you do whatever your program logic says. In the else case, you have to figure out "what was the problem", and "what to do about it":
int guess;
if (scanf("%d", &guess) == 1)
{
/* guess is read */
}
else
{
if (feof(stdin) || ferror(stdin))
{
fprintf(stderr, "Unexpected end of input or I/O error\n");
return EXIT_FAILURE;
}
/* if not file error, then the input wasn't a number */
/* let's skip the current line. */
while (!feof(stdin) && fgetc(stdin) != '\n');
}
input value 123 -- this value is integer, and valid
input value 1b23a -- this value is invalid
How do I detect which values are valid and not?
Here is my code:
#include <stdio.h>
#include <conio.h>
void main()
{
char str1[5],str2[5];
int num,num1,i;
num=0;
clrscr();
printf("Enter the Number ");
scanf("%s",str1);
for(i=0;str1[i]!='\0';i++)
{
if(str1[i]>=48&&str1[i]<=56)
num=num1*10+(str[i]-48);
else
{
printf("The value is invalid ");
}
}
printf("This Number is %d",num);
getch();
}
Please see this answer regarding use of strtol(). It is a safe way to convert arbitrary input that should be a string representation of an integer, while also saving 'garbage' bytes for additional analysis.
Using it, your code would look something like this:
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#ifdef LINUX_VERSION
#include <curses.h>
#else
#include <conio.h>
#endif
#define BUFF_SIZE 1024
int main(void)
{
char str1[BUFF_SIZE], *garbage = NULL;
long num = 0;
printf("Enter the Number ");
scanf("%s",str1);
errno = 0;
num = strtol(str1, &garbage, 0);
if (errno) {
printf("The number is invalid\n");
return 1;
}
printf("You entered the number %ld\n", num);
if (garbage != NULL) {
printf("Additional garbage that was ignored is '%s'\n", garbage);
}
getch();
return 0;
}
This doesn't fix everything that is questionable about what you posted, but it should help you get off to a better start.
Output is:
tpost#tpost-desktop:~$ ./t
Enter the Number 1234abdc
You entered the number 1234
Additional garbage that was ignored is 'abdc'
Compiled via:
gcc -Wall -DLINUX_VERSION -o t t.c -lcurses
I'm not sure what platform you are using, so additional fixes to the code may be needed.
#include<stdio.h>
#include<conio.h>
void main()
{
char str1[5],str2[5];
int num,num1,i;
num=0;
clrscr();
printf("Enter the Number ");
scanf("%s",str1);
for(i=0;str1[i]!='\0';i++)
if(str1[i]>=48&&str1[i]<=56)
num=num1*10+(str[i]-48);
else
{
printf("The value is invalid ");
}
}
printf("This Number is %d",num);
getch();
}
One way is to use sscanf and check that there are no characters following the number. This is done most easily by adding a %c on the end and testing the return code, like this:
const char *yourString = ...;
int theValue, dummy;
if (sscanf(yourString, "%d%c", &theValue, &dummy) == 1) {
// Was a pure number, parsed into 'theValue'
} else {
// Either no number or had junk after it
}