check that command line input is numeric

戏子无情 提交于 2019-12-24 03:12:12

问题


I'm new to C and want to write a simple programme to be called with exactly two command line arguments (the first one being the programme's name, the second one being a string). I have validated the number of arguments and now want to validate the input only contains digits.

#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <cs50.h>

int main(int argc, string argv[])
{
    if (argc == 2)
        {
            for (int i = 0, n = strlen(argv[1]); i < n; i++)
            {
                if isdigit(argv[1][i])
                {
                    printf("Success!\n");
                }
                else
                    {
                    printf("Error. Second argument can be numbers only\n");
                    return 1;
                    }    
            }
    else
        {
            printf("Error. Second argument can be numbers only\n");
            return 1;
        }
}

While the above code doesn't throw errors, it doesn't correctly validate the input and I can't figure out why. Could someone point me in the right direction?

Thanks a lot in advance and all the best


回答1:


if (argc != 2)

must be

if (argc == 2)

Doing

if isdigit(argv[1][i])
{
  printf("Success!\n");
}

you will print "Success" 4 times if the number has 4 digits, better to do something like :

for (int i = 0, n = strlen(argv[1]); i < n; i++)
{
   if (!isdigit(argv[1][i])
   {
     printf("Error. Second argument can be numbers only\n");
     return 1;
   }    
 }
 printf("Success!\n");
 return 0;

Example :

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

int main(int argc, char * argv[])
{
  if (argc == 2)
  {
    int i, n;

    for (i = 0, n = strlen(argv[1]); i < n; i++)
    {
      if (!isdigit(argv[1][i]))
      {
        printf("Error. Second argument can be numbers only\n");
        return 1;
      }
    }
    printf("Success!\n");
  }
  else {
    puts("argument is missing");
    return 1;
  }

  return 0;
}

Compilation and executions :

pi@raspberrypi:/tmp $ gcc -pedantic -Wextra c.c
pi@raspberrypi:/tmp $ ./a.out 
argument is missing
pi@raspberrypi:/tmp $ ./a.out az
Error. Second argument can be numbers only
pi@raspberrypi:/tmp $ ./a.out 12
Success!
pi@raspberrypi:/tmp $ ./a.out 12a
Error. Second argument can be numbers only
pi@raspberrypi:/tmp $ 

Execution under valgrind :

pi@raspberrypi:/tmp $ valgrind ./a.out 123
==2051== Memcheck, a memory error detector
==2051== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==2051== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==2051== Command: ./a.out 123
==2051== 
Success!
==2051== 
==2051== HEAP SUMMARY:
==2051==     in use at exit: 0 bytes in 0 blocks
==2051==   total heap usage: 1 allocs, 1 frees, 1,024 bytes allocated
==2051== 
==2051== All heap blocks were freed -- no leaks are possible
==2051== 
==2051== For counts of detected and suppressed errors, rerun with: -v
==2051== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)



回答2:


While you can rely on looping over the characters checking if each isdigit(), if your purpose is to use the numeric value the argument represents, you may as well use strtol/strtoul to convert the value to a signed/unsigned value and rely on the robust error reporting to tell you exactly what occurred during conversion and what, if any, portion of the argument was made up of non-digits.

The strtoX family of function(s) take a pointer to the string of digits and the address for an endptr as parameters (as well as the base for integer conversions). The function attempts to convert digits to a number updating endptr to point to the first character after the last digit successfully converted. This allows you to determine whether your argument was made up of leading digits, whether those fit within the range for the type of conversion attempted, and whether any additional characters exist after the last digit converted.

A short example explains:

#include <stdio.h>
#include <stdlib.h>     /* for strtol */
#include <errno.h>      /* errno - for strtol validation */

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

    char *endptr;   /* end pointer for strtol */
    long l;

    if (argc < 2) { /* validate at least one argument provided */
        fprintf (stderr, "error: insufficient arguments provided.\n"
                         "usage: %s number\n", argv[0]);
        return 1;
    }

    errno = 0;                          /* zero errno before call */
    l = strtol (argv[1], &endptr, 0);   /* attempt converstion to long */

    if (endptr == argv[1]) {    /* check if digits were converted */
        fprintf (stderr, "error: no digits converted in '%s'.\n", endptr);
        return 1;
    }
    else if (errno) {           /* check for error in conversion */
        perror ("strtol-argv[1]");
        return 1;
    }

    printf ("number provided: %ld\n", l);   /* output number */

    if (*endptr)    /* endptr not pointing to `'\0'`, chars remain */
        printf ("\nadditional characters following number: '%s'.\n", endptr);

    return 0;
}

Example Use/Output

$ ./bin/strtolarg 123456
number provided: 123456

$ ./bin/strtolarg -123456
number provided: -123456

$ ./bin/strtolarg "val=123456"
error: no digits converted in 'val=123456'.

$ ./bin/strtolarg "123456=val"
number provided: 123456

additional characters following number: '=val'.

Look things over and let me know if you have questions.



来源:https://stackoverflow.com/questions/54653523/check-that-command-line-input-is-numeric

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!