8

Signature of isdigit

int isdigit(int c);

Signature of atoi

int atoi(const char *nptr);

I just wanted to check whether the command line argument passed was an integer or not.Here is the C Code:

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

int main(int argc, char *argv[])
{
    if (argc == 1)
        return -1;

    printf ("Hai, you have executed the program : %s\n", argv[0]);
    if (isdigit(atoi(argv[1])))
        printf ("%s is a number\n", argv[1]);
    else
        printf ("%s is not a number\n", argv[1]);
    return 0;
}

But the output is not as expected, when I am passing a valid number:

$ ./a.out 123
Hai, you have executed the program : ./a.out
123 is not a number
$ ./a.out add
Hai, you have executed the program : ./a.out
add is not a number

I couldn't figure out the error.

0aslam0
  • 1,797
  • 5
  • 25
  • 42
  • More obvious and simple, thread safe example you may find here ["How to check if a string is a number?"](https://stackoverflow.com/questions/16644906/how-to-check-if-a-string-is-a-number/44452860#44452860) – Dennis V Jun 18 '17 at 07:57

8 Answers8

22

When you refer argv[1], it refers to a character array containing value 123. isdigit function is defined for a single character input.

So to handle with this situation, it is better to define a function as follows:

bool isNumber(char number[])
{
    int i = 0;

    //checking for negative numbers
    if (number[0] == '-')
        i = 1;
    for (; number[i] != 0; i++)
    {
        //if (number[i] > '9' || number[i] < '0')
        if (!isdigit(number[i]))
            return false;
    }
    return true;
}
niyasc
  • 4,440
  • 1
  • 23
  • 50
15
if (isdigit(atoi(argv[1]))) 

will be:

if (isdigit(atoi("123")))

which will be:

if (isdigit(123))

which will be:

if ( 0 )

since 123 represents the ASCII character '{'.

R Sahu
  • 204,454
  • 14
  • 159
  • 270
2

I thought I'd add something to the answers already here. In addition to checking for numbers in base 10, I thought it would be useful to check for and allow hexadecimal numbers as well. I also allow negative numbers.

I also added a few things to check for bad input (e.g. null pointer, letters inside of a string representing a decimal number, or invalid letters inside a string representing a hexadecimal number).

Note that I use the to_lower(char c) function to ensure that letters representing hexadecimal will be lower case, just for convenience.

I return 1 (or true) if the string is a valid number, 0 if it isn't. If it is a valid number, I store the base inside the parameter base.

// Return 1 if str is a number, 0 otherwise.
// If str is a number, store the base (10 or 16) in param base.
static int is_number(char *str, int *base)
{
    // Check for null pointer.
    if (str == NULL)
        return 0;

    int i;
    int len = strlen(str);

    // Single character case.
    if (len == 1)
    {
        *base = 10;
        return isdigit(str[0]);
    }

    // Hexadecimal? At this point, we know length is at least 2.
    if ((str[0] == '0') && (str[1] == 'x'))
    {
        // Check that every character is a digit or a,b,c,d,e, or f.
        for (i = 2; i < len; i++)
        {
            char c = str[i];
            c = to_lower(c);
            if (!(
                (c >= '0' && c <= '9') || 
                (c >= 'a' && c <= 'f')))
                return 0;
        }
        *base = 16;
    }
    // It's decimal.
    else
    {
        i = 0;
        // Accept signs.
        if (str[0] == '-' || str[0] == '+')
            i = 1;

        // Check that every character is a digit.
        for (; i < len; i++)
        {
            if (!isdigit(str[i]))
                return 0;
        }
        *base = 10;
    }
    return 1;
}

I used this function like this:

int base, num;
if (is_number(str, &base)
    num = strtol(str, NULL, base);
mgarey
  • 733
  • 1
  • 5
  • 19
0

I don't know what isdigit exactly does, but due to name I think it should take a char argument, check for the char being a digit, is it?

I would write like this: (omitted the function shell, just show the core code)

char* p = argv[1];
while (*p != '\0')
{
    if (*p<'0' || *p>'9')
    {
        printf("%s is not a number", argv[1]);
        return 0;
    }
    p++;
}
printf("%s is a number", argv[1]);
return 0;
dbush
  • 205,898
  • 23
  • 218
  • 273
Cherry
  • 153
  • 11
  • btw, you don't need to know what the number is, right? So why use `atoi`? Better not to overuse function – Cherry Mar 25 '15 at 06:19
  • When I looked at the signature of `isdigit` , I saw that it accepts integer input. So I wanted to convert the argument to integer (if the argument was indeed an integer)and then do the check. But the idea was flawed. Moreover `atoi` has no error checking. – 0aslam0 Mar 25 '15 at 06:28
0

isdigit() function checks for a digit character ('0' to '9') which of course depends on ASCII values. Now value returned from your atoi does not fall within ASCII value between '0' to '9'. so it is showing that it is not a number.

Chintan Patel
  • 310
  • 1
  • 2
  • 11
0

Here is the simplest solution which also checks if users enters more than two arguments

// check for valid key
{
    for (int i = 0, n = strlen(argv[1]); i < n; i++)
    {
        if (!isdigit(argv[1][i]))
        {
            return false;
        }
    }
    return true;
}
Super Kai - Kazuya Ito
  • 22,221
  • 10
  • 124
  • 129
ammar
  • 1
  • 2
0

The speciality of isdigit function is- checks: 0 through 9 only. And when it detects a number beyond 9, immediately maps them with their respective ASCII character(if exists). Like, in your case, for '123' it is mapping to '{'.

So, we need to loop through char by char, to check, is it non-numeric? And whenever a non-numeric is found, just return the 1.

    for (int i=0; i<strlen(argv[1]); i++)
{
    if (isdigit(argv[1][i]) == 0)
    {
        printf("Error,Non Numeric Entry!\n");
        return 1;

    }

}
codebae
  • 103
  • 1
  • 7
-1
// Since There is an implicit conversion from const char* to std::string
// You May use this simplified version of the check_string instead

     bool isNumeric(const string str) 
    {
        // loop Through each character in the string
        for(char x:  str)
            if(!isdigit(x)) // Check if a single character "x" its a digit
            return false;  // if its not return false 

      return true; // else return true
    }