这一直在推动我的整个C ++类坚果,我们都没有能够找到解决这个问题的可靠方案。
我们通过终端通过argv* [1]
将信息传递给我们的计划。我们会调用我们的程序./main 3
,程序将运行3
次。
问题出现在我们验证输入时,我们试图覆盖我们所有的基础,对于大多数我们都很好,就像输入的字母字符,负数,0等等。但是什么不断传递是int
,后跟str
,例如./main 3e
或./main 1.3
。我试过this
(Ashwin的回答引起了我的注意)但它似乎没有用,或者至少我无法在我的代码中实现它。
这是我现在的代码:
int main(int argc, char * argv[]){
if (!argv[1]) exit(0);
int x = atoi(argv[1]);
if (!x or x <= 0) exit(0);
// I would like to add another exit(0); for when the input mixes numbers and letters or doubles.
for (int i = 0; i < x; i++){
// rest of the main func.
}
答案 0 :(得分:2)
尽管有标题,听起来你真正想做的是检查输入参数中的每个字符是否都是数字。您可以通过迭代来实现这一点,使用std::isdigit
检查每个元素是否为数字。
这是使用std::all_of
算法的草图:
size_t len = strlen(argv[1]);
bool ok = std::all_of(argv[1], argv[1] + len,
[](unsigned char c) { return std::isdigit(c); } );
如果需要,您可以为'0'
的第一个元素添加额外的检查。
答案 1 :(得分:0)
如果要将字符串转换为数字并验证整个字符串是否为数字,则可以使用strtol
代替atoi
。作为额外的奖励,strtol
正确检查溢出,并为您提供指定是否需要十六进制/八进制转换的选项。
这是一个简单的实现,记录了所有错误(来自这样的函数的打印错误消息不是一个好主意;我只是为了紧凑而做了)。更好的选择可能是返回错误枚举而不是bool,但此函数返回std::pair<bool, int>
:(false, <undefined>)
或(true, value)
:
std::pair<bool, int> safe_get_int(const char* s) {
char* endptr;
bool ok = false;
errno = 0; /* So we can check ERANGE later */
long val = strtol(s, &endptr, 10); /* Don't allow hex or octal. */
if (endptr == s) /* Includes the case where s is just whitespace */
std::cout << "You must specify some value." << '\n';
if (*endptr != '\0')
std::cout << "Argument must be an integer: " << s << '\n';
else if (val < 0)
std::cout << "Argument must not be negative: " << s << '\n';
else if (errno == ERANGE || val > std::numeric_limits<int>:max())
std::cout << "Argument is too large: " << s << '\n';
else
ok = true;
return std::make_pair(ok, ok ? int(val) : 0);
}
一般来说,哲学术语,当你有一个像strtol
(或者,就此而言,fopen
)这样的API来检查错误并在发生错误时拒绝请求时,它会更好编程样式“尝试然后检查错误返回”,而不是“尝试预测错误,只有尝试看起来没问题”。第二种策略“使用前检查”受到漏洞的困扰,包括安全漏洞(当然不是这种情况,但请参阅TOCTOU进行讨论)。它也没有真正帮助你,因为你必须检查错误返回,以防你的预测器不够准确。
当然,您需要确信有问题的API在输入错误时没有未定义的行为,因此阅读官方文档。在这种情况下,atoi
确实在输入错误时有UB,但strtol
没有。 (atoi
:“如果无法表示该值,则行为未定义。”;与strtol
对比