2

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

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

5 回答 5

6

将其传递给 astd::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上的在线演示。

于 2013-04-22T21:35:34.187 回答
1

好的,我修改后的答案。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 10rubbish

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,只是为了显示大量有效和无效条目的输出。

于 2013-04-22T21:33:58.820 回答
1

由于您显然不反对使用标准 C 库,因此该函数

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

from<cstdlib>足以确保命令行参数是一个(长)整数,带有可选的“-”或“+”前缀,仅此而已。您只需要检查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;
}

稍后......或迎合史蒂夫杰索普的评论:

#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

于 2013-04-22T22:34:09.520 回答
0

您可以尝试检查其中的所有字符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 );
}
于 2013-04-22T21:24:37.407 回答
-1

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

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

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

1.如果/否则#include

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

这可能是最简单的方法来确保


2.断言#include

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

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

3.抛出#include

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
    } 
}

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

于 2013-04-23T00:44:44.693 回答