Why does this accept invalid input? - c

I have a triangle program in c
#include <stdio.h>
// A function which decides the type of the triangle and prints it
void checkTriangle(int s1, int s2,int s3)
{
// Check the values whether it is triangle or not.
if ((s1 + s2 > s3 && s1 + s3 > s2 && s2 + s3 > s1) && (s1 > 0 && s2 > 0 && s3 > 0))
{
// Deciding type of triangle according to given input.
if (s1 == s2 && s2 == s3)
printf("EQUILATERAL TRIANGLE");
else if (s1 == s2 || s2 == s3 || s1 == s3)
printf("ISOSCELES TRIANGLE\n");
else
printf("SCALENE TRIANGLE \n");
}
else
printf("\nTriangle could not be formed.");
}
int main(void)
{
// Initializing variables
int a,b,c;
// Getting input from user
printf("Please enter the sides of triangle");
printf("\nPlease enter side 1:");
scanf("%d",&a);
printf("Please enter side 2:");
scanf("%d",&b);
printf("Please enter side 3:");
scanf("%d",&c);
// Calling function in order to print type of the triangle.
checkTriangle(a,b,c);
}
When the input is:
7b
it gives an error, which is what I want, but when I entered the data like this:
7
7
7b
it ignores 'b' and take 7 as an integer — but why? How can I prevent this?
What I want to do is give an error also for
7
7
7b

If you want to be able to detect an error with the user's input, such as a line not being a valid decimal integer, then you could do the following:
Read the input into a buffer using fgets(buffer, size, stdin)
Use strtoul(buffer, &endptr, 10) to parse the buffer as a decimal integer (base 10), where endptr is a char*
endptr will point to the first invalid character in buffer, ie. the character after the last one which was successfully parsed
Now if *endptr == '\0', ie. endptr points to the end of buffer, the whole string was parsed as a valid decimal integer

If you really want each number on a separate line of input, and for the whole of the line to be valid number or space, then you probably need to forget scanf() and family and use fgets() and strtol() instead.
#include <stdlib.h>
#include <errno.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
static int read_side(void)
{
char buffer[4096];
if (fgets(buffer, sizeof(buffer), stdin) == 0) // EOF
return -1;
char *end;
errno = 0;
long result = strtol(buffer, &end, 10);
if (result < 0 || errno != 0) // Neither errors nor negative numbers are allowed
return -1;
if (end == buffer) // Nothing was convertible
return -1;
while (isspace(*end))
end++;
if (*end != '\0') // Non-spaces after the last digit
return -1;
if (result > INT_MAX) // Result too big for `int`
return -1;
return result;
}
(If you needed to accept any valid int value but distinguish errors, then you'd pass in a pointer to the function and return -1 on error or 0 on success, and assign the safe result to the pointer.)
Yes, it really is that fiddly to do the job properly. And yes, analyzing the result of strtol() is as tricky as that; you do have to be very careful. (And there's an outside chance I've forgotten to check for a detectable error condition.) And no, I don't think you can do the equivalent job with scanf() et al; in particular, the behaviour on overflow with scanf() is undefined.

you shouldn't use scanf or do scanf("%[^\n]s", word); Or use someting like get()
also put d or x at the end of my example not s for string :P

Read the input into a string buffer. Parse the string to extract numeric values be of any kind one by one.

%d accepts only integer. try with %x in scanf() for hex-decimal input.
Better you can get input as string then check using isnumeric() else use scanf("%[^\n]s", word) like #mou suggested.

Related

How to check if scanf("%s", &var) is a number, and thus turn it into an integer

I have this code and I need help converting the comments to c code
// if the input of scanf() is "q"
{
break;
}
else
{
// convert to int
}
Firstly, how do I check if an input is a certain character. Secondly, how do I turn a string into an integer. Example: "123" -> 123
Things I've tried, that didn't work: (it is possible that I implemented these solutions incorrectly)
how does scanf() check if the input is an integer or character?
Convert char to int in C and C++
I am not using any standard libraries except for stdio.h to print some logging information on the window
you have to know also that any string is terminated by null character which is '\0' to indicate the termination of the string , also you have to check is the user entered characters not numbers and so on (that's not implemented in this code).
I also handled if negative numbers are entered.
but you have to handle if the user entered decimals numbers , to sum up . there are so many cases to handle.
and here the edited code :
#include <stdio.h>
int main(){
char inputString[100];
printf("enter the input:\n");
scanf("%s", &inputString);
if(inputString[0] == 'q' && inputString[1] == '\0' )
{
printf("quiting\n");
//break;
}
else {
int i = 0;
int isNegative = 0;
int number = 0;
// check if the number is negative
if (inputString[0] == '-') {
isNegative = 1;
i = 1;
}
// convert to int
for ( ;inputString[i] != '\0' ; i++) {
number *= 10;
number += (inputString[i] - '0');
}
if(isNegative == 1)
number *= -1;
printf("you entered %d\n", number);
}
return 0;
}
The fundamental question here is, Do you want to use scanf?
scanf is everyone's favorite library function for easily reading in values. scanf has an input specifier, %d, for reading in integers.
And it has a different input specifier, %s, for reading in arbitrary strings.
But scanf does not have any single input specifier that means, "Read in an integer as an integer if the user types a valid integer, but if the user types something like "q", have a way so I can get my hands on that string instead."
Unless you want to move mountains and implement your own general-purpose input library from scratch, I think you have basically three options:
Use scanf with %d to read integers as integers, but check scanf's return value, and if scanf fails to read an integer, use that failure to terminate input.
Use scanf with %s to read the user's input as a string, so you can then explicitly test if it's a "q" or not. If not, convert it to an integer by hand. (More on this below.)
Don't use scanf at all. Use fgets to read the user's input as a whole line of text. Then see if it's a "q" or not. If not, convert it to an integer by hand.
Number 1 looks something like this:
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%d", &i) != 1) {
/* end of input detected */
break;
}
do something with i value just read;
}
The only problem with this solution is that it won't just stop if the user types "q", as your original problem statement stipulated. It will also stop if the user types "x", or "hello", or control-D, or anything else that's not a valid integer. But that's also a good thing, in that your loop won't get confused if the user types something unexpected, that's neither "q" nor a valid integer.
My point is that explicitly checking scanf's return value like this is an excellent idea, in any program that uses scanf. You should always check to see that scanf succeeded, and do something different if it fails.
Number 2 would look something like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(scanf("%19s", tmpstr) != 1) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
This will work well enough, although since it uses atoi it will have certain problems if the user types something other than "q" or a valid integer. (More on this below.)
Number 3 might look like this:
char tmpstr[20];
while(some loop condition) {
printf("enter next integer, or 'q' to quit:\n");
if(fgets(tmpstr, 20, stdin) == NULL) {
printf("input error\n");
exit(1);
}
if(strcmp(tmpstr, "q\n") == 0) {
/* end of input detected */
break;
}
i = atoi(tmpstr); /* convert string to integer */
do something with i value just read;
}
One thing to note here is that fgets includes the newline that the user typed in the string it returns, so if the user types "q" followed by the Enter key, you'll get a string back of "q\n", not just "q". You can take care of that either by explicitly looking for the string "q\n", which is kind of lame (although it's what I've done here), or by stripping the newline back off.
Finally, for both #2 and #3, there's the question of, what's the right way to convert the user's string to an integer, and what if it wasn't a valid integer? The easiest way to make the conversion is to call atoi, as my examples so far have shown, but it has the problem that its behavior on invalid input is undefined. In practice, it will usually (a) ignore trailing nonnumeric input and (b) if there's no numeric input at all, return 0. (That is, it will read "123x" as 123, and "xyz" as 0.) But this behavior is not guaranteed, so these days, most experts recommend not using atoi.
The recommended alternative is strtol, which looks like this:
char *endp;
i = strtol(tmpstr, &endp, 10); /* convert string to integer */
Unlike atoi, strtol has guaranteed behavior on invalid input. Among other things, after it returns, it leaves your auxiliary pointer endp pointing at the first character in the string it didn't use, which is one way you can determine whether the input was fully valid or not. Unfortunately, properly dealing with all of the ways the input might be invalid (including trailing garbage, leading garbage, and numbers too big to convert) is a surprisingly complicated challenge, which I am not going to belabor this answer with.
Here are some guidelines:
scanf("%s", &var) is incorrect: you should pass the maximum number of characters to store into the array var and pass the array without the & as it will automatically convert to a pointer to its first element when passed as an argument:
char var[100];
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
to compare the string read to "q", you can use strcmp() declared in <string.h>:
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
to convert the string to the number it represents, use strtol() declared in <stdlib.h>:
char *p;
long value = strtol(var, &p, 0);
testing for a proper conversion is tricky: strtol() updated p to point to the character after the number and set errno in case of range error:
errno = 0;
char *p;
long value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
Here is a complete program:
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
char var[100];
char *p;
long value;
printf("Enter a number: ");
if (scanf("%99s", var) != 1) {
printf("premature end of file\n");
return 1;
}
if (strcmp(var, "q") == 0) {
printf("quitting\n");
return 0;
}
errno = 0;
value = strtol(var, &p, 0);
if (p == var) {
printf("not a number: %s\n", p);
return 1;
}
if (*p != '\0') {
printf("extra characters: %s\n", p);
return 1;
}
if (errno) {
printf("conversion error: %s\n", strerror(errno));
return 1;
}
printf("the number entered is: %ld\n", value);
return 0;
}
You can try this: (Assuming only positive integers needs to convert)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
// Write C code here
char var[100];
int numb_flag=1, i=0,number=0;
scanf("%s",var);
while(var[i]!='\0') { // Checking if the input is number
if(var[i]>=48 && var[i]<=57)
i++;
else {
numb_flag = 0;
break;
}
}
if(numb_flag==1) {
number = atoi(var);
printf("\nNumber: %d",number);
} else {
printf("\nNot A Number");
}
return 0;
}
//Mind that in order to be more precise you could also use atof().
//The function works the same way as atoi() but is able to convert float
// (returned value is 'double') the string s
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXILEN 100 /*change the value based on your needs*/
int main(){
int n, lim = MAXILEN;
char s[MAXILEN], *p = s, c;
/*taking the string from the input -- I do not use scanf*/
while(--lim > 0 && (c = getchar()) != EOF && c != '\n')
*p++ = c;
//here you can also do the check (if you want the '\n' char):
//if(c == '\n')
// *s++ = c;
*p = '\0';
if(s[0] == 'q' && s[1] == '\0')
exit(EXIT_SUCCESS); /*change the argument based on your needs*/
else
n = atoi(s);
printf("[DEBUG]: %d\n", n);
}

C Integer Safe Input

How can I get a safe input of integer (especially, positive number) using scanf or gets? I've tried several solutions and each solution had some problems.
1. Using getchar() to remove string inputs
int safeInput() {
int input;
scanf("%d", &input);
while(getchar() != '\n');
return input;
}
This method effectively handles string inputs, however, if strings such as 3a are inputted, the value of input becomes 3, which is not a true exception handle.
2. Retrieving input as a string then converting to integer value.
int safeInput() {
char[200] input, safe_input;
gets(input);
// I know about the security issue about gets - but it's not the point.
int i = 0;
while (1) {
if (input[i] >= 48 && input[i] <= 57) safe_input[i] = input[i];
else break;
i++;
}
return atoi(safe_input);
}
This method has problem that it cannot handle if string that has longer length than allocated to input was inputted.
3. What if defining a string using pointer?
I concerned about defining input by pointer, like char *input;. However, once I executed gets(input)(or scanf("%s", input)), it raised runtime-error.
So what is a proper way to retrieve an integer value from console window using scanf or gets?
The answer depends on what exactly you mean by safe. If you want to catch any possible input error, your only option is to use a function of the strtol() family, which even allows for a range check. In my beginners' guide away from scanf(), I'm describing its use.
Here's the code adapted to what you're attempting here, with comments:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
// return success as boolean (0, 1), on success write result through *number:
int safeInput(int *number)
{
long a;
char buf[1024]; // use 1KiB just to be sure
if (!fgets(buf, 1024, stdin))
{
// reading input failed:
return 0;
}
// have some input, convert it to integer:
char *endptr;
errno = 0; // reset error number
a = strtol(buf, &endptr, 10);
if (errno == ERANGE)
{
// out of range for a long
return 0;
}
if (endptr == buf)
{
// no character was read
return 0;
}
if (*endptr && *endptr != '\n')
{
// *endptr is neither end of string nor newline,
// so we didn't convert the *whole* input
return 0;
}
if (a > INT_MAX || a < INT_MIN)
{
// result will not fit in an int
return 0;
}
// write result through the pointer passed
*number = (int) a;
return 1;
}
First if you want a safe input, do not use gets. Saying that you know about the issues is not a true excuse when you could use fgets. Next, the trick is to try to read a non blank character after the int: if you find no one, then there is nothing after the int on the line.
int safeInput(int *input) { // the return value is the indicator of failed read
int c;
char dummy[2]; // never forget the terminating null!
if (scanf("%d%1s", input, dummy) == 1) return 1;
// in case of error, skip anything up to end of line or end of file
while (((c = fgetc(stdin)) != '\n') && (c != EOF));
return 0;
}
The nice point here, is that when scanf returns 1, the %1s has eaten anything up to the end of line, including the terminating 'n'. But this has a major drawback: the scanf will only end on end of stream or after reading one additional (non blank) character. For that reason, Felix Palmen's answer is easier and safer to use.

Validating integer of length 11 and starts with 0

I'm trying to make a function to validate mobile entry, the mobile number MUST starts with 0 and is 11 numbers (01281220427 for example.)
I want to make sure that the program gets the right entry.
This is my attempt:
#include <stdio.h>
#include <strings.h>
void integerValidation(char x[15]);
int main(int argc, char **argv)
{
char mobile[15];
integerValidation(mobile);
printf("%s\n\n\n", mobile);
return 0;
}
void integerValidation(char x[15]){
char input[15];
long int num = -1;
char *cp, ch;
int n;
printf("Please enter a valid mobile number:");
while(num<0){
cp = fgets(input, sizeof(input), stdin);
if (cp == input) {
n = sscanf(input, "%ld %c", &num, &ch);
if (n!=1) {printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
else if (num<0)
printf("ERROR! Please enter a valid mobile number:");
else if ((strlen(input)-1)>11 || (strlen(input)-1)<11 || strncmp(&input[0], "0", 1) != 0){
printf("ERROR! Please enter a valid mobile number:");
num = -1;
}
}
}
long int i;
i = strlen(input);
//Because when I try to print it out it prints a line after number.
strcpy(&input[i-1], "");
strcpy(x, input);
}
Now, if I don't use
strcpy(&input[i-1], "");
the array prints a new line after the number, what would be a good fix other than mine? and how can I make this function optimized and shorter?
Thanks in advance!
Edit:
My question is: 1. Why does the input array prints a new line in the end?
2. How can I make this code shorter?
End of edit.
If you insist on using sscanf(), you should change the format this way:
int integerValidation(char x[15]) {
char input[15], c;
printf("Please enter a valid mobile number:");
while (fgets(input, sizeof(input), stdin)) {
if (sscanf(input, "%11[0123456789]%c", x, &c) == 2
&& x[0] == '0' && strlen(x) == 11 && c == '\n') {
// number stored in `x` is correct
return 1;
}
printf("ERROR! Please enter a valid mobile number:");
}
x[0] = '\0'; // no number was input, end of file reached
return 0;
}
%12[0123456789] parses at most 11 characters that must be digits.
%c reads the following character, which should be the trailing '\n'.
I verify that both formats have been matched, and the number starts with 0 (x[0] == '0') and it has exactly 11 digits.
You're seeing the newline, since fgets() reads until an EOF or a newline is received. The newline is stored in the buffer, and after that the string is terminated with '\0'.
An alternative would be to directly overwrite the newline with another null-byte: input[i-1] = '\0' (which basically does the same thing as your solution, but saves a function call).
The same goes for the check with strncmp with length 1, you can directly check input[0] == '0'. Note that you have to compare against '0' (char) here, not "0" (string).
A few other things I'm seeing:
You can also spare the %c in the format string for sscanf (you're never evaluating it anyway, since you're checking for 1 as return value), which also eliminates the need for char ch.
Also, you're passing char x[15] as argument to your function. This is a bit misleading, because what actually gets passed is a pointer to a char array (try using sizeof(x), your compiler will most likely issue a warning about the size of char * being returned by sizeof()).
What you could do is to ditch the char array input, which you're using as temporary buffer, and use the buffer which was handed over as argument. For this to be save, you should use a second funcion parameter to specify the size of the buffer which was handed to the function, which would result in a function header like as follows:
void integerValidation(char *input, size_t len);
With this, you'd have to use len instead of sizeof(input). The following question provides more detail why: C: differences between char pointer and array
Since you're not using a temporary buffer anymore, you can remove the final call to strcpy().
There are also a lot of checks for the number length/format. You can save a few:
If you use %lu instead of %ld no signed numbers are being converted, which saves you the check for num < 0.
You're checking whether the length of the read number is <11 or >11 - why not just check for !=11?
You're calling strlen() three times on the input-buffer (or still twice with the reworked check for lengh 11) - it makes sense to call it once, save the length in a variable and use that variable from then on, since you're not altering the string between the calls.
There is already an accepted answer, but for what it's worth, here is another.
I made several changes to your code, firstly avoiding "magic numbers" by defining the phone number length and an arbitrarily greater string length. Then there is no point passing an array x[15] to a function since it pays no regard to its length, might as well use the simpler *x pointer. Next, I return all reasons for failure back to the caller, that's simpler. And instead of trying to treat the phone number as a numeric entry (note: letters, spaces, hyphens, commas and # can sometimes be a part of phone number too) I stick to a character string. Another reason is that the required leading zero will vanish if you convert the entry to an int of some size. I remove the trailing newline that fgets() reads with the input line, and the result is this.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXLEN 11
#define STRLEN (MAXLEN+10)
int integerValidation(char *x);
int main(int argc, char **argv)
{
char mobile[STRLEN];
while (!integerValidation(mobile)) // keep trying
printf("Invalid phone number\n");
printf("%s\n\n\n", mobile); // result
return 0;
}
int integerValidation(char *x)
{
int i, len;
printf("Please enter a valid mobile number:");
if(fgets(x, STRLEN, stdin) == NULL) // check bad entry
return 0;
x [ strcspn(x, "\r\n") ] = 0; // remove trailing newline etc
if((len = strlen(x)) != MAXLEN) // check length
return 0;
if(x[0] != '0') // check leading 0
return 0;
for(i=1; i<len; i++) // check all other chars are numbers
if(!isdigit(x[i]))
return 0;
return 1; // success
}

Digit Validation - Endless Loop

I have this code to validate user input. Condition: value entered should be a zero or positive number only. Negative values and alphabetic characters are not accepted.
Here is my code for this, that just keeps on looping:
#include <stdio.h>
int main ()
{
int a, b, c, d;
printf ("enter value for a:");
do {
b = 0;
scanf ("%d", &a);
if (!isdigit(a)) {
printf("Number must be numeric!:\n");
b++;
}
else if (a < 0) {
printf ("number must be postive\n");
b++;
} else {
printf("\neverything is goood\n");
}
} while (b != 0);
}
isdigit() is expecting an ASCII encoded character, however scanf with the %d argument is converting an ASCII encoded number (a string) into an actual number.
ie. If you input '1', with the ASCII code of 0x31, scanf("%d",... will convert this to the value 1. The ASCII code of 1 is not numeric.
To fix this, either:
Make a type char and use the scanf format specifier %c, then isdigit() will do what you want it to.
Use strtol to read in more than one character and perform your own error checking with the char **endptr argument.
Also, you should turn up your compiler warnings and include the header file that contains the isdigit() function, ctype.h.
Once a user makes a mistake, b is always > 0. You need to add a line that sets b = 0 after correct information is entered (i.e. after your printf("\neverything is good\n"); statement. Just be certain to add { & } to the else statement preceding it, so that the printf & new b = 0; statement will be included in that branch)
Here are few issues with your code that I can spot:
You use scanf with %d format specifier that already parses an input as integer value. Thus, there is no need to check if it is numeric with isdigit. In fact, isdigit is checking a decimal digit character, so your usage is incorrect.
You never check for scanf return. You should. In case there was an error (i.e. value was non-numeric), the input is not removed from the stream. In other words, you will get stuck trying to parse the same bad value over and over.
You have unused variables and forgot to include certain header files. But these are minor things in your case (but could be major in certain situations!).
That being said, here is some code that might work out for you:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
static void skip_input(FILE *stream)
{
int c;
do {
c = fgetc (stream);
} while (c != EOF && c != '\n');
}
int main()
{
int a;
int r;
printf("Please enter a value: ");
for (;;) {
r = scanf("%d", &a);
if (r == EOF)
return EXIT_FAILURE;
if (r != 1) {
printf("Number must be numeric!\n");
skip_input(stdin);
} else if (a < 0) {
printf("Number must be postive\n");
skip_input(stdin);
} else {
printf("Everything is goood\n");
break;
}
}
return EXIT_SUCCESS;
}
Hope it helps.
You are using b as your error flag.
In the "everything is good block", try setting b=0;
Additionally, if you do that, you can get rid of the b++; lines, and simply initialize b=1;
You should only be doing b++ if you need to report how many times the user messed up, which I am presuming you don't need?
There are a couple of problems here.
The first is that the return value of scanf() isn't being checked. If input is available then scanf returns the number of variables that were assigned, which can be 0 or 1 in this case (because you're only attempting to assign one variable). If the user enters a non-numeric character then the loop will execute repeatedly without ever waiting for more user input because there's input available but it'll never match your "%d" conversion. If you want to use scanf() then you'll have to check the return value. If the return value is zero then a non-numeric value was entered, which means that you'll have to clear that value out of the input buffer by reading until the end of the line. If the return value is equal to EOF then either an I/O error occurred or you reached the end of the stream. If the return value is 1 then you know that the value was numeric, which brings me to the next problem.
The routine, isdigit(), takes an integer argument, but it expects that integer value to represent a character. Since you're using scanf() to convert the input to an integer, the value stored in a no longer represents a character; it represents an actual number. Because of this, the call to isdigit() will only return a true value if the user enters a number that corresponds to a digit character. In my locale, that means that the validation will only succeed if the user enters a number between 48 and 57, inclusive. If you're using scanf() then the isdigit() check is not necessary because scanf() will return a value of 1 only if the user entered a numeric value.
To be honest, however, I wouldn't use scanf() to read in user input if I could avoid it precisely because of the need to flush the input buffer if the user enters something wrong. I'm not entirely sure what your requirements are, but I'll assume that you're supposed to read a positive integer from the command line and that the number of digits doesn't matter.
In this case, you'll probably want to use fgets() to read the user input then use strtol() to convert the value to a signed long integer and perform the validation at the same time:
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
int main () {
long result;
long len;
int is_valid = 0;
char buf[128];
char *arg;
char *end;
while (!is_valid) {
/* Prompt the user for the integer. */
printf("Enter a non-negative integer: ");
if (fgets(buf, sizeof(buf), stdin) == NULL) {
printf("Giving up so soon?\n");
break;
}
/* Verify that the input doesn't exceed our buffer length. */
len = strlen(buf);
if (buf[len] != '\n') {
printf("Input buffer length exceeded - aborting.\n");
exit(1);
}
/* Skip any leading whitespace. */
for (arg = buf; isspace(*arg); arg++);
/* Attempt to convert the argument. */
errno = 0;
result = strtol(arg, &end, 10);
if (errno == EINVAL) {
printf("Please enter a numeric value.\n");
continue;
}
if (errno == ERANGE) {
printf("Numeric value out of range.\n");
continue;
}
/* Check for non-whitespace characters after the end of the integer. */
for (; isspace(*end); end++);
if (*end != '\0') {
printf("Please enter a numeric value.\n");
continue;
}
/* Verify that the number is non-negative. */
if (result < 0) {
printf("Please enter a positive value.\n");
continue;
}
/* The number is valid. */
printf("Excellent!\n");
is_valid = 1;
}
return 0;
}
This isn't perfect; aborting if the input buffer length is exceeded isn't exactly user-friendly. It should take care of the validation problem, however.

How to do error control for rejecting characters, spacing and extra decimal point?

the program requires user to key in an initial value which allows for range between 0 to 1000 including decimal placing
how to create error control to reject characters, spacing, or additional decimal point placed such as 1.2.3? n loop itself to prompt user for new input
printf("Please enter initial velocity(in m/s) of ball when thrown vertically upwards: \n");
scanf("%lf%c",&v0,&rubbish);
printf("%f\n",v0);
printf("%c\n",rubbish);
/*error control for incorrect range of value entered*/
while (v0<0 || v0> 1000|| rubbish !='\n')
{
/*Ask user for correct value of velocity*/
v0='\n', rubbish="\n";
printf("\nIncorrect value keyed\n");
printf("Please enter again the initial velocity(in m/s) of ball when thrown vertically upwards: \n");
scanf("%lf",&v0);
scanf("%c",&rubbish);
printf("%f\n",v0);
printf("%c\n",rubbish);
}
how to implement strtod() when i have to get keyed values?
I understand it as: you'd like to get a double from a user (I understand "keyed" in your comment as "typed on keyboard"). With additional constraint that input line should not contain any other characters or extra decimals.
You could do it in two steps:
read line
parse double
read line from stdin
#include <stdio.h> // fgets
#include <string.h> // strlen
// ...
char buf[BUFSIZ];
char *s = NULL;
if ((s = fgets(buf, BUFSIZ, stdin)) == NULL || strlen(s) == (BUFSIZ-1)) {
// can't read from stream or line is too long
return -1; // return <0 from your function to indicate error to the caller
}
At this point s contains user input.
parse double using strtod()
strtod() can detect many error conditions: overflow, underflow, empty strings, or leading non-whitespace characters can't be interpreted as a floating-point number. The interface might be confusing (and some corner cases changed between c89 and c99). You can peek and choose what conditions you'd like to detect and ignore others.
Here's an example that requires that the string contained only a number and optional leading, trailing whitespace and nothing else:
#include <ctype.h> // isspace
#include <errno.h>
#include <math.h> // HUGE_VAL
#include <stdlib.h> // strtod
// ...
int ret = 0;
char *endptr = NULL;
double d = 0.0;
int save = errno; // save original value
errno = 0; // clear
if (out && // double *out (function parameter)
!(((d = strtod(s, &endptr)) == 0.0 || d == HUGE_VAL || d == -HUGE_VAL) &&
(str == endptr || errno == EINVAL || errno == ERANGE))) {
// `d` contains a number
// check what left in the string
while(isspace(*endptr))
++endptr; // skip whitespace
if (*endptr == '\0')
*out = d; // success
else
ret = -1; // error: non-whitespace encountered after the number
}
else
ret = -1; // error: can't read a number
errno = save; // restore
return ret;

Resources