How to allow only digits to be entered in an array? - c

So I am trying to write a program that receives a 10 digit phone number from the user.
It must only be 10 characters long.
It can only consist of digits. Entering a alphabet character or special character will give an error message.
I have tried using the isdigits() function but that doesn't seem to work.
Here is my code so far.
Is there any other way to do this without using isdigits()?
#include <stdio.h>
#include <string.h>
#include <ctype.h>
void clearKeyboard(void);
int main (void)
{
char phoneNum[11];
int needInput = 1;
int i;
int flagBad = 0;
while (needInput == 1) {
scanf_s("%10s", phoneNum);
clearKeyboard();
// (String Length Function: validate entry of 10 characters)
if (strlen(phoneNum) == 10) {
needInput = 0;
for (i = 0; i < 10; i++) {
if (isdigits(phoneNum[i] == 0)) {
flagBad = 1;
}
}
if (flagBad == 1) {
needInput = 1;
printf("Enter a 10-digit phone number: ");
}
}
else needInput == 0;
}
printf("Successful");
return 0;
}
void clearKeyboard(void)
{
while (getchar() != '\n'); // empty execution code block on purpose
}

scanf_s("%10s", phoneNum); fails as it is missing an argument. Review your scanf_s() documentation.
I do not recommend scanf_s(). Instead avoid mixing user I/O with input validation. Get the input, then validate it.
char buf[80]; // Be generous.
if (fgets(buf, sizeof buf, stdin)) {
buf[strcspn(buf, "\n")] = '\0'; // Lop off potential \n
// OK we have the input, now validate.
char phoneNum[11];
int n = 0;
// Use sscanf, isdigit, or ...
if (sscanf(buf, "%10[0-9]", phoneNum, &n) == 1 && n == 10 && buf[n]==0) {
puts("Success");
} else {
printf("Bad input <%s>\n", buf);
}
"%10[0-9]%n", phoneNum, &n --> Scan 1 to 10 digits into phoneNum[] and append a '\0'. Save scanning offset into n

I think the function you need is isdigit(), not isdigits().

You should use scanf("%10s", phoneNum); and also include #include <stdlib.h> which contains isdigit() method.

As AbdelAziz stated, you should use is isdigit(), not isdigits().
Also, your if statement is wrong:
if (isdigits(phoneNum[i] == 0))
should be:
if (isdigit(phoneNum[i]) == 0)

Related

How to use scanf() to capture only Strings

Hi i am new to C and i am trying to use the Character array type below to captures input from users. How do i prevent or escape numerical characters. I just want only strings to be captured.
char str_input[105];
In have tried
scanf("%[^\n]s",str_input);
scanf("%[^\n]",str_input);
scanf("%[^0-9]",str_input);
scanf("%[A-Zaz-z]",str_input);
str_input = fgetc(stdin);
None of the above worked for me.
Input
2
hacker
Expected Output
Hce akr
int main() {
char *str_input;
size_t bufsize = 108;
size_t characters;
str_input = (char *)malloc(bufsize * sizeof(char));
if (str_input == NULL)
{
perror("Unable to allocate buffer");
exit(1);
}
characters = getline(&str_input,&bufsize,stdin);
printf("%zu characters were read.\n",characters);
int i;
int len = 0;
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2==0? printf("%c",str_input[i]): 'b';
}
printf(" ");
for (i = 0, len = strlen(str_input); i<=len; i++) {
i%2!=0? printf("%c",str_input[i]): 'b';
}
return 0;
}
Error
solution.c: In function ‘main’:
solution.c:21:5: warning: implicit declaration of function ‘getline’ [-Wimplicit-function-declaration]
characters = getline(&str_input,&bufsize,stdin);
Since your buffer has limited size, then using fgets(3) is fine. fgets() returns NULL on failure to read a line, and appends a newline character at the end of the buffer.
In terms of preventing numerical characters from being in your buffer, you can simply create another buffer, and only add non-numerical characters to it. You could just delete the numerical characters from your original buffer, but this can be a tedious procedure if you are still grasping the basics of C. Another method would be just to read single character input with getchar(3), which would allow you assess each character and simply ignore numbers. THis method is by far the easiest to implement.
Since you asked for an example of using fgets(), here is some example code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#define INPUTSIZE 108
int main(void) {
char str_input[INPUTSIZE], characters[INPUTSIZE];
size_t slen, char_count = 0;
printf("Enter input:\n");
if (fgets(str_input, INPUTSIZE, stdin) != NULL) {
/* removing newline from fgets() */
slen = strlen(str_input);
if (slen > 0 && str_input[slen-1] == '\n') {
str_input[slen-1] = '\0';
} else {
fprintf(stderr, "Number of characters entered exceeds buffer size\n");
exit(EXIT_FAILURE);
}
/* checking if string is valid */
if (*str_input == '\0') {
fprintf(stderr, "No input found\n");
exit(EXIT_FAILURE);
}
printf("Buffer: %s\n", str_input);
/* only adding non-numbers */
for (size_t i = 0; str_input[i] != '\0'; i++) {
if (!isdigit(str_input[i])) {
characters[char_count++] = str_input[i];
}
}
/* terminating buffer */
characters[char_count] = '\0';
printf("New buffer without numbers: %s\n", characters);
}
return 0;
}
Example input:
Enter input:
2ttt4y24t4t3t2g
Output:
Buffer: 2ttt4y24t4t3t2g
New buffer without numbers: tttytttg
Update:
You could just use this even simpler approach of ignoring non-number characters:
char str_input[INPUTSIZE];
int ch;
size_t char_count = 0;
while ((ch = getchar()) != EOF && ch != '\n') {
if (!isdigit(ch)) {
if (char_count < sizeof(str_input)) {
str_input[char_count++] = ch;
}
}
}
str_input[char_count] = '\0';
If you're using Linux, I would use the getline() function to get a whole line of text, then verify it. If it is not valid input, I would in a loop ask the user to enter a line of text again and again until you the input is acceptable.
If not using Linux, well, your best bet is probably to reimplement getline(). You can also use fgets() if you find a limited-size buffer acceptable. I don't find limited-size buffers acceptable, so that's why I prefer getline().
getline() is used according to the way explained in its man page: http://man7.org/linux/man-pages/man3/getdelim.3.html
Basically, your loop should be something similar to:
char *buf = NULL;
size_t bufsiz = 0;
while (1)
{
if (getline(&buf, &bufsiz, stdin) < 0)
{
handle_error();
}
if (is_valid(buf))
{
break;
}
printf("Error, please re-enter input\n");
}
use_buffer(buf);
free(buf);
Well that's not possible. Numbers are string too. But you can set loop to look for numbers and print error. like this :
char *str = "ab234cid20kd", *p = str;
while (*p) { // While there are more characters to process...
if (isdigit(*p)) { // Upon finding a digit, ...
printf("Numbers are forbidden");
return 0;
} else {
p++;
}
}

proper use of scanf in a while loop to validate input

I made this code:
/*here is the main function*/
int x , y=0, returned_value;
int *p = &x;
while (y<5){
printf("Please Insert X value\n");
returned_value = scanf ("%d" , p);
validate_input(returned_value, p);
y++;
}
the function:
void validate_input(int returned_value, int *p){
getchar();
while (returned_value!=1){
printf("invalid input, Insert Integers Only\n");
getchar();
returned_value = scanf("%d", p);
}
}
Although it is generally working very well but when I insert for example "1f1" , it accepts the "1" and does not report any error and when insert "f1f1f" it reads it twice and ruins the second read/scan and so on (i.e. first read print out "invalid input, Insert Integers Only" and instead for waiting again to re-read first read from the user, it continues to the second read and prints out again "invalid input, Insert Integers Only" again...
It needs a final touch and I read many answers but could not find it.
If you don't want to accept 1f1 as valid input then scanf is the wrong function to use as scanf returns as soon as it finds a match.
Instead read the whole line and then check if it only contains digits. After that you can call scanf
Something like:
#include <stdio.h>
int validateLine(char* line)
{
int ret=0;
// Allow negative numbers
if (*line && *line == '-') line++;
// Check that remaining chars are digits
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1; // Remember that at least one legal digit was found
++line;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin)) // Read the whole line
{
if (validateLine(line)) // Check that the line is a valid number
{
// Now it should be safe to call scanf - it shouldn't fail
// but check the return value in any case
if (1 != sscanf(line, "%d", &x))
{
printf("should never happen");
exit(1);
}
// Legal number found - break out of the "while (y<5)" loop
break;
}
else
{
printf("Illegal input %s", line);
}
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Input
1f1
f1f1
-3
Output
Please Insert X value
Illegal input 1f1
Please Insert X value
Illegal input f1f1
Please Insert X value
Illegal input
Please Insert X value
x=-3
Another approach - avoid scanf
You could let your function calculate the number and thereby bypass scanf completely. It could look like:
#include <stdio.h>
int line2Int(char* line, int* x)
{
int negative = 0;
int ret=0;
int temp = 0;
if (*line && *line == '-')
{
line++;
negative = 1;
}
else if (*line && *line == '+') // If a + is to be accepted
line++; // If a + is to be accepted
while (*line && *line != '\n')
{
if (!isdigit(*line)) return 0; // Illegal char found
ret = 1;
// Update the number
temp = 10 * temp;
temp = temp + (*line - '0');
++line;
}
if (ret)
{
if (negative) temp = -temp;
*x = temp;
}
return ret;
}
int main(void) {
char line[256];
int i;
int x , y=0;
while (y<5)
{
printf("Please Insert X value\n");
if (fgets(line, sizeof(line), stdin))
{
if (line2Int(line, &x)) break; // Legal number - break out
printf("Illegal input %s", line);
}
y++;
}
if (y<5)
printf("x=%d\n", x);
else
printf("no more retries\n");
return 0;
}
Generally speaking, it is my opinion that you are better to read everything from the input (within the range of your buffer size, of course), and then validate the input is indeed the correct format.
In your case, you are seeing errors using a string like f1f1f because you are not reading in the entire STDIN buffer. As such, when you go to call scanf(...) again, there is still data inside of STDIN, so that is read in first instead of prompting the user to enter some more input. To read all of STDIN, you should do something the following (part of code borrowed from Paxdiablo's answer here: https://stackoverflow.com/a/4023921/2694511):
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // Used for strtol
#define OK 0
#define NO_INPUT 1
#define TOO_LONG 2
#define NaN 3 // Not a Number (NaN)
int strIsInt(const char *ptrStr){
// Check if the string starts with a positive or negative sign
if(*ptrStr == '+' || *ptrStr == '-'){
// First character is a sign. Advance pointer position
ptrStr++;
}
// Now make sure the string (or the character after a positive/negative sign) is not null
if(*ptrStr == NULL){
return NaN;
}
while(*ptrStr != NULL){
// Check if the current character is a digit
// isdigit() returns zero for non-digit characters
if(isdigit( *ptrStr ) == 0){
// Not a digit
return NaN;
} // else, we'll increment the pointer and check the next character
ptrStr++;
}
// If we have made it this far, then we know that every character inside of the string is indeed a digit
// As such, we can go ahead and return a success response here
// (A success response, in this case, is any value other than NaN)
return 0;
}
static int getLine (char *prmpt, char *buff, size_t sz) {
int ch, extra;
// Get line with buffer overrun protection.
if (prmpt != NULL) {
printf ("%s", prmpt);
fflush (stdout);
}
if (fgets (buff, sz, stdin) == NULL)
return NO_INPUT;
// If it was too long, there'll be no newline. In that case, we flush
// to end of line so that excess doesn't affect the next call.
// (Per Chux suggestions in the comments, the "buff[0]" condition
// has been added here.)
if (buff[0] && buff[strlen(buff)-1] != '\n') {
extra = 0;
while (((ch = getchar()) != '\n') && (ch != EOF))
extra = 1;
return (extra == 1) ? TOO_LONG : OK;
}
// Otherwise remove newline and give string back to caller.
buff[strlen(buff)-1] = '\0';
return OK;
}
void validate_input(int responseCode, char *prompt, char *buffer, size_t bufferSize){
while( responseCode != OK ||
strIsInt( buffer ) == NaN )
{
printf("Invalid input.\nPlease enter integers only!\n");
fflush(stdout); /* It might be unnecessary to flush here because we'll flush STDOUT in the
getLine function anyway, but it is good practice to flush STDOUT when printing
important information. */
responseCode = getLine(prompt, buffer, bufferSize); // Read entire STDIN
}
// Finally, we know that the input is an integer
}
int main(int argc, char **argv){
char *prompt = "Please Insert X value\n";
int iResponseCode;
char cInputBuffer[100];
int x, y=0;
int *p = &x;
while(y < 5){
iResponseCode = getLine(prompt, cInputBuffer, sizeof(cInputBuffer)); // Read entire STDIN buffer
validate_input(iResponseCode, prompt, cInputBuffer, sizeof(cInputBuffer));
// Once validate_input finishes running, we should have a proper integer in our input buffer!
// Now we'll just convert it from a string to an integer, and store it in the P variable, as you
// were doing in your question.
sscanf(cInputBuffer, "%d", p);
y++;
}
}
Just as a disclaimer/note: I have not written in C for a very long time now, so I do apologize in advance if there are any error in this example. I also did not have an opportunity to compile and test this code before posting because I am in a rush right now.
If you're reading an input stream that you know is a text stream, but that you are not sure only consists of integers, then read strings.
Also, once you've read a string and want to see if it is an integer, use the standard library conversion routine strtol(). By doing this, you both get a confirmation that it was an integer and you get it converted for you into a long.
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
bool convert_to_long(long *number, const char *string)
{
char *endptr;
*number = strtol(string, &endptr, 10);
/* endptr will point to the first position in the string that could
* not be converted. If this position holds the string terminator
* '\0' the conversion went well. An empty input string will also
* result in *endptr == '\0', so we have to check this too, and fail
* if this happens.
*/
if (string[0] != '\0' && *endptr == '\0')
return false; /* conversion succesful */
return true; /* problem in conversion */
}
int main(void)
{
char buffer[256];
const int max_tries = 5;
int tries = 0;
long number;
while (tries++ < max_tries) {
puts("Enter input:");
scanf("%s", buffer);
if (!convert_to_long(&number, buffer))
break; /* returns false on success */
printf("Invalid input. '%s' is not integer, %d tries left\n", buffer,
max_tries - tries);
}
if (tries > max_tries)
puts("No valid input found");
else
printf("Valid input: %ld\n", number);
return EXIT_SUCCESS;
}
ADDED NOTE: If you change the base (the last parameter to strtol()) from 10 to zero, you'll get the additional feature that your code converts hexadecimal numbers and octal numbers (strings starting with 0x and 00 respectively) into integers.
I took #4386427 idea and just added codes to cover what it missed (leading spaces and + sign), I tested it many times and it is working perfectly in all possible cases.
#include<stdio.h>
#include <ctype.h>
#include <stdlib.h>
int validate_line (char *line);
int main(){
char line[256];
int y=0;
long x;
while (y<5){
printf("Please Insert X Value\n");
if (fgets(line, sizeof(line), stdin)){//return 0 if not execute
if (validate_line(line)>0){ // check if the string contains only numbers
x =strtol(line, NULL, 10); // change the authentic string to long and assign it
printf("This is x %d" , x);
break;
}
else if (validate_line(line)==-1){printf("You Have Not Inserted Any Number!.... ");}
else {printf("Invalid Input, Insert Integers Only.... ");}
}
y++;
if (y==5){printf("NO MORE RETRIES\n\n");}
else{printf("%d Retries Left\n\n", (5-y));}
}
return 0;}
int validate_line (char *line){
int returned_value =-1;
/*first remove spaces from the entire string*/
char *p_new = line;
char *p_old = line;
while (*p_old != '\0'){// loop as long as has not reached the end of string
*p_new = *p_old; // assign the current value the *line is pointing at to p
if (*p_new != ' '){p_new++;} // check if it is not a space , if so , increment p
p_old++;// increment p_old in every loop
}
*p_new = '\0'; // add terminator
if (*line== '+' || *line== '-'){line++;} // check if the first char is (-) or (+) sign to point to next place
while (*line != '\n'){
if (!(isdigit(*line))) {return 0;} // Illegal char found , will return 0 and stop because isdigit() returns 0 if the it finds non-digit
else if (isdigit(*line)){line++; returned_value=2;}//check next place and increment returned_value for the final result and judgment next.
}
return returned_value; // it will return -1 if there is no input at all because while loop has not executed, will return >0 if successful, 0 if invalid input
}

Data validation in C - ensuring the input is in a correct format

I want to write a code to ensure that the users input only 1 digit. If a user enters something like "0 1 3" I want my program to read an error message which I have no idea how to do. Anyone has an idea how to approach this? My current code just takes in the first number if a user enters bunch of numbers with a space in between.
Please see my code below. Thanks :D
//Prompt the user to enter the low radius with data validation
printf("Enter the low radius [0.0..40.0]: ");
do
{
ret = scanf("%lf", &lowRadius);
//type validation
if (ret != 1)
{
int ch = 0;
while (((ch = getchar()) != EOF) && (ch != '\n'));
printf("Wrong input. Please enter one numerical value: ");
}
//range validation
else if((lowRadius < 0 || lowRadius > 40))
{
printf("Incorrect value. Please enter in range 0-40: ");
}
else break;
} while ((ret != 1) || (lowRadius < 0 || lowRadius > 40));//end while lowRadius
If you read the line into a string, then analyse it, you avoid the problem of hanging on unsupplied input. You have done most of the work already, but this shows how to trap too much input. It works by scanning a string after the double to pick up any more input. The return value from sscanf tells you if there was, because it returns the number of items successfully scanned.
#include <stdio.h>
#include <stdlib.h>
void err(char *message)
{
puts(message);
exit(1);
}
int main(void)
{
double lowRadius = 0.0;
char inp[100];
char more[2];
int conv;
if(fgets(inp, sizeof inp, stdin) == NULL) {
err("Input unsuccesful");
}
conv = sscanf(inp, "%lf %1s", &lowRadius, more); // conv is number of items scanned
if(conv != 1) {
err("One input value is required");
}
if(lowRadius < 0.0 || lowRadius > 40.0) {
err("Number out of range");
}
printf("%f\n", lowRadius);
return 0;
}
I'm unsure about your stipulation of a single digit, since that won't allow your maximum value to be entered.
Read a whole line and convert it with strtod.
Alexander has the right approach, but doesn't give much detail. Here is how I would do it, using getline() to read the input, and then strspn() plus strtod() to parse the input that was read. If you are not familiar with working with pointers, this will be difficult to understand - but if you are learning C, you'll get there eventually:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void) {
double lowRadius;
char *lineptr = NULL;
size_t n;
char *startptr;
char *endptr;
char *ws = " \t\n"; /* possible whitespace characters */
printf("Enter the low radius [0.0..40.0]: ");
while(1) {
/* free lineptr if set - neeeded if we iterate on error input */
if( lineptr ) {
free(lineptr);
lineptr = NULL;
}
/* now read a line of input */
while( getline(&lineptr, &n, stdin) == -1 ) {
/* error returned, just retry */
continue;
}
/* skip over any leading whitespace */
startptr = lineptr + strspn(lineptr,ws);
/* Now try to convert double */
lowRadius = strtod(startptr, &endptr);
if( endptr==startptr || endptr[strspn(endptr,ws)] != 0 ) {
/* either no characters were processed - e.g., the
line was empty, or there was some non-whitespace
character found after the number. */
printf( "Wrong input. Please enter one numerical value: ");
} else if( (lowRadius < 0.0) || (lowRadius > 40.0) ) {
printf( "Incorrect value. Please enter in range 0-40: " );
} else {
if( lineptr ) free(lineptr);
break;
}
}
printf( "value entered was %lf\n", lowRadius );
}

How to verify a password to have at least one uppercase, lowercase and number in C?

What should i do to make it keep looping until it have at least one uppercase, lowercase and number ?
I'm stuck, really stuck...
char password[100][15];
i=1;
printf("Password [3..10]: ");
gets(password[i]);
while (strlen(password[i])>10 || strlen(password[i])<3 || ) {
do{
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 number\nPassword [3..10]: ");
gets(password[i]);
} while (strlen(password[i])>10 || strlen(password[i])<3 );
This should work:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int is_legal(char *p) {
int number = 0, lower = 0, upper = 0, length = 0;
for( ; *p; p++) {
number += isdigit(*p);
lower += islower(*p);
upper += isupper(*p);
length++;
}
return number > 0 && lower > 0 && upper > 0 && length > 3 && length < 10;
}
char *my_gets(char *buf, int bufsize, FILE *file) {
if(fgets(buf, bufsize, file) == 0) {
return 0;
}
int n = strlen(buf);
if(buf[n-1] == '\n') buf[n-1] = 0;
return buf;
}
int get_password(char *buf, int bufsize, FILE *file) {
printf("Password [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
while(is_legal(buf) == 0) {
printf(" Password must contain at least 1 uppercase, 1 lowercase, and 1 umber\nPassword [3..10]: ");
if(my_gets(buf, bufsize, file) == 0) {
return -1;
}
}
return 0;
}
int main(void) {
char password[100][15];
int i = 0;
if(get_password(password[i], sizeof(password[i]), stdin) != 0) {
fprintf(stderr, "Error getting password\n");
exit(1);
}
return 0;
}
Use this regular expression:
^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$
It says that you must have at least one lowercase character, one uppercase character and at least one number PLUS it is less typing than the ctype method.
Example:
#include <regex.h>
int main (int argc, char *argv[])
{
regex_t regex;
int regexResult = regcomp(&regex, "^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$", 0);
regexResult = regexec(&regex, passwordVariableHere, 0, NULL, 0);
if (!regex)
{
// Match
}
}
Look at ctype.h header. Examine every character of password until all conditions (upper, lower, digit) are met. If you reach end of password string and any of conditions are unsatisfied, password is wrong.
Maybe it's an easy way to check the characters position in the ASCII table. You can check all characters as numbers between 65 and 90 for uppsercase characters and the same for lowercase.
For a number you could use atoi() function from standard c library.
Or another possibility is using functions from ctype.h: islower(), isupper() or isdigit().
I don't get very well why you are using an array of 15-chars long passwords, but I suppose your criteria refers to just one of those password and not to the others: you want to check that a password has requirements to be considered a "good" password; this is my understanding. Then...
The function gets is rather unsafe. Avoid using it.
The idea is to ask for a password, check it and loop if it does not fit your criteria. There's not a single way to do it of course.
// include files for I/O funcs
#include <stdio.h>
for(;;)
{
printf("insert pwd: ");
gets(buffer); // argh I've said: don't use this
if ( !pass_criteria(buffer) ) {
printf("criteria are ....\n");
} else break;
}
Then pass_criteria could be something like
// include files for strlen and is* funcs
#include <ctype.h>
#include <string.h>
int pass_criteria(const char *buf)
{
int upcount, lowcount, numcount;
if (strlen(buf) < minimum_pass_len ||
strlen(buf) > max_pass_len) return 0; // 0 being false
for (int i = 0; i < strlen(buf); ++i) {
if (isdigit(buf[i]) numcount++;
if (isupper(buf[i]) upcount++;
if (islower(buf[i]) lowcount++;
}
return numcount > 0 && upcount > 0 && lowcount > 0;
}
It's easy to change criteria, e.g. if you want at least 2 number (digit), put numcount > 1 and so on.
Instead of gets
Gets is dangerous for buffer overflow. Try using e.g. fgets like this:
fgets(buffer, buffer_size, stdin);
where buffer_size is the size of your buffer (15 in your case, but avoid using a literal constant; prefer a proper #define or use sizeof, e.g. sizeof (password[0]). Note also that fgets does not discard final newline.

C - Integer Input Validation Code

I have the following code in C:
#include "stdafx.h"
#include <stdlib.h>
#include <cstring>
#include <ctype.h>
int main()
{
char buffer[20];
int num;
bool valid = true;
printf("Please enter a number\n");
fgets(buffer, sizeof(buffer), stdin);
printf("\n\n");
if(!isdigit(buffer[0])) //Checking if the first character is -
{
if(buffer[0] != '-')
{
valid = false;
}
else
{
if(!isdigit(buffer[1]))
{
valid = false;
}
}
}
char *pend = strrchr(buffer, '\n'); //Replacing the newline character with '\0'
if (pend != NULL)
{
*pend = '\0';
}
for (int i = 1; i < strlen(buffer); i++) //Checking that each character of the string is numeric
{
if (!isdigit(buffer[i]))
{
valid = false;
break;
}
}
if(valid == false)
{
printf("Invalid input!");
}
else
{
num = atoi(buffer);
printf("The number entered is %d", num);
}
getchar();
}
Basically, the code ensures that the user input is a positive or negative whole number. No letters, floating point numbers etc. are allowed.
The code works perfectly and does its job well.
However, the code is too long and I have to implement it in a number of programs. Is there a simple way to perform all of the above in C? Maybe a shorter alternative that ensures that the input is:
i) not a letter
ii) a positive or negative WHOLE number
bool valid = false;
char *c = buffer;
if(*c == '-'){
++c;
}
do {
valid = true;
if(!isdigit(*c)){
valid = false;
break;
}
++c;
} while(*c != '\0' && *c != '\n');
Note: this will not handle hex values, but will pass octal (integers starting in 0)
I also have to agree that this should be placed in a common library and called as a function.
Although some people have pointed out that strtol may not give you the errors you need, this is a very common type of thing to do, and therefore it does exist in the standard library:
http://www.cplusplus.com/reference/cstdio/sscanf/
#include <stdio.h>
// ....
valid = sscanf (buffer,"%d",&num);
Another comment is that you should not be afraid of writing complicated and useful code, and modularizing it. Create a library for the input parsing routines you find useful!

Resources