C语言中的命令行参数验证

x6492ojm  于 2022-12-22  发布在  其他
关注(0)|答案(6)|浏览(161)

我有一个程序,需要从命令行从用户那里获取int

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

我唯一的问题是我需要检查argv是否是int。如果不是,我需要返回一个错误。我该怎么做呢?我必须在使用atoi之前检查输入是否是int。有人能帮助我吗?

5cg8jx4n

5cg8jx4n1#

下面是一种方法,使用strtol并检查字符串的结尾:

#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;
}
    • 更新日期:**

次要:代码未检测strtol()的转换溢出代码错误地假定long范围大于int。如果范围相同,则if (val != lval)始终为true。建议查看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;
}
kninwzqo

kninwzqo2#

C语言中的命令行参数验证
我需要检查argv是否是整型
1.首先通过检查argc来测试argv[]是否包含字符串。

for (int a = 1; a < argc; a++) {
      int_validation(argv[a]);
    }

1.尝试使用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;
}

根据需要调整返回类型和消息。
通常,"1e5""123.0"等输入虽然在数学上是整数,但不被视为有效的int输入。

jtoj6r0c

jtoj6r0c3#

您可以尝试使用strtol()转换参数,如果值不可解析或解析后的值,它将返回0
您还可以使用第二个参数对输入进行更详细的验证,您可以区分错误的输入或0输入,因为在这两种情况下返回的值都是0

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

int main(int argc, char *argv[])
{
    long parsed_value = 0;
    int value = 0;
    //for  command + 1 argument
    if (argc == 2)
    {    
        errno = 0;
        char *end_ptr;
        parsed_value = strtol(argv[1], &end_ptr, 10);
        //argument check, overflow, trailing characters, underflow,  errno 
        if(*end_ptr == argv[1][0] || *end_ptr != '\0' || errno == ERANGE 
            || parsed_value < INT_MIN || parsed_value > INT_MAX){
            fprintf(stderr, "Invalid argument");
            return EXIT_FAILURE;
        }
    }
    else{
        fprintf(stderr, "Wrong number of arguments, %d provided, 2 needed", argc);
        return EXIT_FAILURE;
    }
    //otherwise the value was parsed correctly
    value = parsed_value;
    printf("%d", value);
}
acruukt9

acruukt94#

使用isdigit测试参数的字符是否为“digit-ness”,然后根据结果转换(或不转换)参数。例如:

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

bool is_all_digits(char *s)
{
    bool b = true;

    for( ; *s ; ++s)
        if(!isdigit(*s))
        {
            b = false;
            break;
        }

    return b;
}

int main(int argc, char *argv[])
{
    for(int i = 0 ; i < argc ; ++i)
    {
        if(is_all_digits(argv[i]))
            printf("argv[%d] is an integer = %d\n", i, atoi(argv[i]));
        else
            printf("argv[%d] is not an integer \"%s\"\n", i, argv[i]);
    }

    return 0;
}

使用命令行参数运行时

123 "Not a number" 456.789 "Not another number" 10

产生以下输出:

argv[0] is not an integer "./a.out"
argv[1] is an integer = 123
argv[2] is not an integer "Not a number"
argv[3] is not an integer "456.789"
argv[4] is not an integer "Not another number"
argv[5] is an integer = 10

正如其他人所指出的,is_all_digits并不保证表示整数的字符串可以使用atoi或任何其他例程进行解析,但您可以根据自己的需要随意修改它。:-)

wlsrxk51

wlsrxk515#

作为strtol()(即 * 规范答案 *)的替代方法,您可以使用isdigit() function执行 * 手工 * 验证,同时检查 * 前导符号字符 *(+-):

#include <ctype.h>
#include <bool.h>

bool isValidInteger( char * str )
{
    bool ret = true;

    if( str )
    {
        char p = str;

        for( int i=0; str[i] != 0; i++ )
        {
            if ( !isdigit( str[i] ) )
            {
                if( i == 0 && ( str[i] == '+' || *p == '-' ) && str[i+1] )
                    continue;
                ret = false;
                break;
            }
        }
    }
    else
    {
        return false;
    }

    return ret;
}

这个实现依赖于输入字符串以空结尾的事实,但是因为每个argv[N]都是以空结尾的字符串,所以我们可以很好地处理。
用法:

if ( isValidInteger( argv[1] ) )
{
    int par = atoi( argv[1] );
}

注意(1):这个验证器不检查超过int范围(从INT_MININT_MAX)的输入值,这是一个在很多情况下可以接受的限制。
注(2):此函数不像strto*那样进行前导空格的修剪,如果需要此功能,可以在for-loop的顶部添加这样的检查:

bool flag = true;

if( str[i] == ' ' )
    continue;

flag = false;

通过这种方式,空格是可以容忍的,但只能在flag设置为false之前,即遇到第一个非空格字符时。

hfyxw5xn

hfyxw5xn6#

试试这个。我会让你按自己喜欢的方式对错误消息进行排序:

#define TRUE  1
#define FALSE 0

int is_integer( char *s )
{
  int i = 0 ;
  int is_digit;
  int is_sign;

  while ( s[i] != '\0' )
  {
    // this test makes the assumption that the code points for
    // decimal digits are contiguous. True for ASCII/UNICODE and EBCDIC.
    // If you're using some other bizarro encoding, you're out of luck.

    is_digit = s[i] >= '0' && s[i] <= '9' ? TRUE : FALSE ;
    is_sign  = i == 0 && s[i] == '-'      ? TRUE : FALSE ;

    if ( !is_digit && !is_sign )
    {
      return FALSE;
    }

    ++i;
  }

  return TRUE;
}

int main( int argc, char *argv[] )
{
  int  i    = 0    ;
  int  cc   = 0    ; // assume success;

  for ( i = 0 ; i < argc ; ++i )
  {
    if ( !is_integer(argv[i]) )
    {
      cc  = 1;
    }
  }

  return cc; // exit code 0 is success; non-zero exit code is failure.
}

相关问题