Search code examples
cgetoptatoi

C Using isdigit to check if optarg is a digit


If optarg (the argument after the flag -s, from Getop library) isn't a digit, I want an error message to be printed and the program terminated, and if it is a digit, size needs to be set to optarg. The problem I have is while a command like the -s r will hit the error message, -s 2 will also, meaning it's interpreting the 2 as a string.

Debugging with for -s 2

#1 printf("%d",atoi(optarg));
#2 printf("%d",isdigit(atoi(optarg)));

I get the int value 2 for line #1, and an int value of 0 for line #2.

So I was wondering why isdigit(atoi(optarg))) gives me a 0, when atoi(optarg) gives me an int. Is there a better way to check if optarg is an int?

int main (int argc, char *argv[]){


int size;
char option;
size = 0;
const char *optstring;
optstring = "rs:pih";

 while ((option = getopt(argc, argv, optstring)) != EOF) {
    switch (option) {
        case 'r':
            type_set = 1;
            break;
        **case 's':
            capacity_set = 1;
            if(isdigit(atoi(optarg))==0){
                fprintf(stderr,"Argument after -s needs to be an int\n");
                return 0;
            }**
            else{
                size = atoi(optarg);
            }
             break;

        default{
        return 0;
        }  

Solution

  • isdigit takes a character and tells you if it is a digit. atoi takes a string (char *) and returns the number that the string represents. So when you call isdigit(atoi(... you're taking a number and treating it as a character. Since the charater codes for digits are 48..57, any number other than one of those will return false.

    You probably want isdigit(*optarg) -- this will tell you if the first character of the argument (string) is a digit character. Of course, this only looks at the first character, so you might want isdigit(optarg[0]) && optarg[1] == 0 instead.

    If you want to accept a number rather than a digit (and only a number), strtol works much better than atoi as it allows you to check for failures. Something like:

    char *end;
    errno = 0;
    size = strtol(optarg, &end, 10);
    while (isspace(*end)) ++end;
    if (errno || *end) {
        // an error occurred on conversion, or there is extra cruft
        // after a number in the argument.
        fprintf(stderr,"Argument after -s needs to be an int\n");
        return 0; }