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.

1

8 Answers 8

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(const 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;
}
Sign up to request clarification or add additional context in comments.

6 Comments

You could use isdigit here to make it look better.
@niyasc How would you modify it check for negative numbers also?
@0aslam0; Check whether first character is zero or not. I will edit my code for negative number as well.
@niyasc Don't you mean number[i] != '\0' in the for loop?
@aa8y \0, the terminating character is represented by zero in ascii.
|
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 '{'.

3 Comments

OK. isdigit(x) ; here x can be from 0, 1, 2,...9 only?
No, only for '0', '1', etc. The integer value for them are 48 - 57.
That is a new piece of info.
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);

Comments

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.

Comments

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;

2 Comments

btw, you don't need to know what the number is, right? So why use atoi? Better not to overuse function
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.
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;
}

Comments

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;

    }

}

Comments

-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
    }  

1 Comment

This is C, not C++

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.