【问题标题】:Checking to make sure argv[1] is an integer c++检查以确保 argv[1] 是整数 c++
【发布时间】:2013-04-15 22:21:41
【问题描述】:

对于我的程序,我必须确保用户只输入一个正整数。例如,如果用户输入 12hi 它不应该运行程序并打印到 std 错误。我不太确定如何实现。

int main(int argc, char *argv[])   
{ 
    if(atoi(argv[1]) < 1)
    {
        cerr << "ERROR!"<< endl;
        return 1;
    }
    return 0;
}

【问题讨论】:

  • 您当前的实现有问题吗?如果是这样,请告诉我们您的实施与您的要求有何不同。
  • atoi 不够成熟,无法在这里给出正确答案。看strtol
  • 到目前为止,这仅检查它是否为正数,我找不到检查它是否为整数的方法,例如:如果您从 argv 收到 28,则 main 应该返回 0 但如果您收到 28abc,main 应该返回 false。
  • 在你考虑检查argv[1]之前,你需要检查argc的值。考虑一下如果你在没有参数的情况下运行你的程序会发生什么。而且您至少缺少几个必需的#include 指令。
  • 我只是没有把它们都包括进去,argc 已经检查过了,而且所有的#includes 都在.h 文件中

标签: c++ integer argv argc


【解决方案1】:

既然您显然不反对使用标准 C 库, 函数

long strtol (const char* str, char** endptr, int base)

来自&lt;cstdlib&gt; 足以确保 命令行参数是一个(长)整数,带有一个可选的 “-”或“+”前缀,仅此而已。你只需要 检查char * 存储在endptr 返回地址“\0”上, 它告诉您该函数已使用整个参数。

#include <cstdlib>
#include <iostream>

using namespace std;

int main(int argc, char *argv[])   
{
    if (argc < 2) {
        return 1;
    }

    char * endp;
    long i = strtol(argv[1],&endp,10);
    if (!*endp) {
        cout << "The value of \"" << argv[1] << "\" is " << i << endl;
        return 0;
    }
    cerr << "\"" << argv[1] << "\" is not an integer" << endl;
    return 1;
}

稍后 ...或迎合史蒂夫·杰索普的 cmets:

#include <cstdlib>
#include <iostream>
#include <climits>

using namespace std;

int main(int argc, char *argv[])   
{
    if (argc < 2) {
        return 1;
    }

    char * endp;
    long i = strtol(argv[1],&endp,10);

    if (*endp) {
        cerr << "\"" << argv[1] << "\" is not an integer :(" << endl;
        return 1;
    }
    if (endp == argv[1]) {
        cerr << "Empty string passed :(" << endl;
        return 1;
    }
    if (i < 0) {
        cerr << "Negative " << i << " passed :(" << endl;
        return 1;
    }
    if (i <= INT_MAX) {
        cout << "Non-negative int " << i << " passed :)" << endl;
    } else {
        cout << "Non-negative long " << i << " passed :)" << endl;
    }
    return 0;

}

包装函数将是为了这种程度的区分。那里 仍然是接受ULONG_MAX 输入的非常极端的情况 作为LONG_MAX

【讨论】:

  • +1,但是有一个错误是您没有正确处理argv[1] 指向空字符串的情况。还有一个可能的改进,您可能希望在输入字符串表示的值超出long 范围的情况下打印不同的消息。
【解决方案2】:

好的,我修改后的答案。 sscanf 的行为与我想象的不一样,而 strtol 提供了非常便携的最佳类 C 解决方案。

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

int main(int argc, char* argv[])
{
  for (int i=1; i < argc; i++){
      char* end;
      long val = strtol(argv[i], &end, 10);
      if (argc >= 2 && !end[0] && val >= 0){
          printf("%s is valid\n", argv[i]);
      } else {
          printf("%s is invalid\n", argv[i]);
      }
  }
  return 0;
}

示例输出: ./a.out 10 -1 32 1000 f -12347 +4 --10 10 垃圾

10 is valid
-1 is valid
32 is valid
1000 is valid
f is invalid
-12347 is valid
+4 is invalid
--10 is invalid
10rubbish is invalid

这是可行的,因为 strtol 会将参数转换为 long int。然后如果 end[0] 不在字符串的末尾,它将是非零的,这意味着它会抛出 10rubbish 的错误,但对于像 10 这样的值是可以的。当然我们只想要正整数,我已经在该集合中包含值 0。

atoi() 本身还不够好,因为它会在失败时返回零。 0 可能是有效的输入。

sscanf() 本身也不够好,因为它会成功转换像 10rubbish 这样的字符串并返回值 10。

我意识到 op 只需要 argv[1],这个答案会扫描所有提供的 args,只是为了显示大量有效和无效条目的输出。

【讨论】:

  • "u" 上没有格式说明符%,这并不算诽谤。
  • strtol 可以正常工作,因为您将指针传递给指针,它将填充传递信息的末尾。确认这是字符串的结尾。 " 如果 endptr 不为 NULL,则 strtol() 将第一个无效字符的地址存储在 *endptr 中。但是,如果根本没有数字,则 strtol() 将 str 的原始值存储在 *endptr 中。(因此,如果 * str 在返回时不是\0' but **endptr is \0',整个字符串都是有效的。)"
  • err true,我已经很久没有使用 strtol 了。修复了丢失的 % - 哎呀。
  • 该解决方案不允许程序检测 OP 希望拒绝的负整数参数。负整数参数将被接受并转换为无符号,例如“-12567”将给出val = 4294954729
【解决方案3】:

我是 C++ 新手,如果有错误请不要喷我,但你不能抛出异常并允许用户重新更正输入吗?

我已经学会了几种处理错误的方法:

  1. If/Else 处理
  2. 断言
  3. 抛出异常

1.如果/否则 #包括

int main(int argc, int **argv) {
    if (!isdigit(argv[1])) {
        // handle code if it's not a digit.
        return 0;
    }
}

这可能是最简单的确认方法


2.断言 #包括

int main(int argc, int *argv[]) {
    assert(isdigit(argv[1]));
}

* 如果 argv[1] 不是数字,断言将终止程序

3.投掷 #包括

using namespace std;

class Except {};

int main(int argc, int **argv) {
    try {
        isdigit(argv[1]);
        throw Except();
        // this code will not be executed
        // if argv[1] is not a digit
    }
    catch (Except) {
        cout << "argv[1] is not a digit.";
        // handle exception or rethrow
    } 
}

绝对值得注意的是,抛出异常将创建堆栈跟踪,并且在抛出异常和捕获异常的块之间的所有代码都不会被执行。

【讨论】:

  • isdigit 在字符而非字符数组级别工作。所以 isdigit(argv[1]) 即使编译也不会按照你的想法去做。
【解决方案4】:

您可以尝试检查argv[1] 中的所有字符是否都是数字(可能带有前导减号)。可以使用标准库函数isdigit()进行检查。

http://www.cplusplus.com/reference/cctype/isdigit/

基于 OP 实际代码的完整解决方案(也可在http://codepad.org/SUzcfZYp 获得):

#include <stdio.h>          // printf()
#include <stdlib.h>         // atoi()
#include <ctype.h>          // isdigit()

int main(int argc, char *argv[])   
{ 
    if( argc != 2 ) {
        return 0;
    }

    char * pWord = argv[ 1 ];
    char c = 0;
    for( int i = 0; c = pWord[ i ], c ; ++i ) {
        if( ! isdigit( c ) ) {
            return 0;
        }
    }

    int argvNum = atoi( argv[ 1 ] );
    printf( "argc = %d, argv[ 1 ] = %s, argvNum = %d\n",
        argc, argv[ 1 ], argvNum );
}

【讨论】:

    【解决方案5】:

    将其传递给std::istringstream 并确保所有数据均已处理:

    if (a_argc > 1)
    {
        std::istringstream in(a_argv[1]);
        int i;
        if (in >> i && in.eof())
        {
            std::cout << "Valid integer\n";
        }
    }
    

    通过http://ideone.com/8bEYJq查看在线演示。

    【讨论】:

    • 这正是我想要的
    猜你喜欢
    • 1970-01-01
    • 2012-11-16
    • 1970-01-01
    • 1970-01-01
    • 2013-10-22
    • 2015-01-09
    • 1970-01-01
    • 2023-01-04
    • 1970-01-01
    相关资源
    最近更新 更多