Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Command line argument validation in C

Tags:

c

int

I have a program that needs to get an int from the user from the command line

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

My only problem is that I need to check whether argv is an int. If it isn't, I need to return an error. How can I do that? I have to check if the input is an int before using atoi. Can someone help me?

like image 340
Ohhh Avatar asked Jun 18 '26 07:06

Ohhh


2 Answers

Here's one way, using strtol and checking the end of the string:

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

int
main(int argc,char **argv)
{
    char *cp;
    long lval;
    int val;

    // skip over program name
    --argc;
    ++argv;

    if (argc < 1) {
        fprintf(stderr,"main: no argument specified\n");
        exit(1);
    }

    cp = *argv;
    if (*cp == 0) {
        fprintf(stderr,"main: argument an empty string\n");
        exit(1);
    }

    lval = strtol(cp,&cp,10);
    if (*cp != 0) {
        fprintf(stderr,"main: argument '%s' is not an integer -- '%s'\n",
            *argv,cp);
        exit(1);
    }

    val = (int) lval;

    // NOTE: just going for extra credit here ;-)
    // ensure number fits in a int (since strtol returns long and that's 64
    // bits on a 64 bit machine)
#if 1
    if (val != lval) {
        fprintf(stderr,"main: argument '%s' (with value %ld) is too large to fit into an integer -- truncated to %d\n",
            *argv,lval,val);
        exit(1);
    }
#endif

    printf("val=%d\n",val);

    return 0;
}

UPDATE:

Minor: Code does not detect conversion overflow of strtol() Code incorrectly assumes range of long more than int. If same range, if (val != lval) is always true. Suggest looking at errno, INT_MAX,INT_MIN

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <limits.h>

int
main(int argc,char **argv)
{
    char *cp;
    long lval;
    int val;

    // skip over program name
    --argc;
    ++argv;

    if (argc < 1) {
        fprintf(stderr,"main: no argument specified\n");
        exit(1);
    }

    cp = *argv;
    if (*cp == 0) {
        fprintf(stderr,"main: argument an empty string\n");
        exit(1);
    }

    errno = 0;
    lval = strtol(cp,&cp,10);

    if (*cp != 0) {
        fprintf(stderr,"main: argument '%s' is not an integer -- '%s'\n",
            *argv,cp);
        exit(1);
    }

    // on a 32 bit machine, entering 2147483648 will produce a non-zero errno
    if (errno) {
        fprintf(stderr,"main: argument '%s' parse error -- '%s'\n",
            *argv,strerror(errno));
        exit(1);
    }

    // on a 64 bit machine, entering 2147483648 will not produce an error, so
    // we should check the range ourselves
    if ((lval < INT_MIN) || (lval > INT_MAX)) {
        fprintf(stderr,"main: argument '%s' range error -- %ld outside of range (%ld to %ld)\n",
            *argv,lval,(long) INT_MIN,(long) INT_MAX);
        exit(1);
    }

    val = (int) lval;

    // NOTE: just going for extra credit here ;-)
    // ensure number fits in a int (since strtol returns long and that's 64
    // bits on a 64 bit machine)
    // FIXME -- with above tests this can never be true (i.e. fault), so
    // I've nop'ed it -- left in to show prior/original test
#if 0
    if (val != lval) {
        fprintf(stderr,"main: argument '%s' (with value %ld) is too large to fit into an integer -- truncated to %d\n",
            *argv,lval,val);
        exit(1);
    }
#endif

    printf("val=%d\n",val);

    return 0;
}
like image 120
Craig Estey Avatar answered Jun 19 '26 21:06

Craig Estey


Command line argument validation in C

I need to check whether argv is an int

  1. Test first if argv[] contains a string by checking argc.
    for (int a = 1; a < argc; a++) {
      int_validation(argv[a]);
    }
  1. Attempt conversion using strtol()

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

void int_validation(const char *s) {
  // If leading space not OK
  // isspace() only valid in unsigned char range and EOF.
  if (isspace(*(unsigned char *)s)) {
    puts("Fail - leading spaces");
    return;
  }

  // Convert
  int base = 0;  // Use 10 for base 10 only input
  char *endptr;
  errno = 0;
  long val = strtol(s, &endptr, base);

  if (s == endptr) { // When endptr is same as s, no conversion happened.
    puts("Fail - no conversion");
    return;
  }      
 
  // detect overflow
  if (errno == ERANGE || val < INT_MIN || val > INT_MAX) {
    errno = ERANGE;
    puts("Fail - overflow");
    return;
  }      

  // If trailing space OK, seek pass them
  while (isspace(*(unsigned char *)endptr)) {
    endptr++;
  }

  // If trailing non-numeric text bad
  if (*endptr) {
    puts("Fail - overflow");
    return;
  }

  printf("Success %d\n", (int) val);
  return;
}

Adjust return type and messages as desired.


Typically input like "1e5" or "123.0", although mathematically a whole number, is not consider valid int input. Additional code needed to allow those.

like image 35
chux - Reinstate Monica Avatar answered Jun 19 '26 20:06

chux - Reinstate Monica



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!