对于我的程序,我必须确保用户只输入一个正整数。例如,如果用户输入 12hi 它不应该运行程序并打印到 std 错误。我不太确定如何实现这一点。
int main(int argc, char *argv[])
{
if(atoi(argv[1]) < 1)
{
cerr << "ERROR!"<< endl;
return 1;
}
return 0;
}
将其传递给 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上的在线演示。
好的,我修改后的答案。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,只是为了显示大量有效和无效条目的输出。
由于您显然不反对使用标准 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
。
您可以尝试检查其中的所有字符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 );
}
我是 C++ 新手,所以如果这是错误的,请不要激怒我,但你不能抛出异常并允许用户重新更正输入吗?
我学会了几种处理错误的方法:
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]));
}
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
}
}
绝对值得注意的是,抛出异常将创建堆栈跟踪,并且在抛出异常和捕获异常的块之间的所有代码都不会被执行。