这是我试图用于;验证密钥";部分,尝试仅在参数为数字时返回成功。然而,当我运行程序时,有些数字被认为是错误的。我不明白为什么。
~/pset2/caesar/ $ ./caesar 9
Usage: ./caesar key
~/pset2/caesar/ $ ./caesar 45
Success
45
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[]) {
int n = atoi(argv[1]);
if (argc == 2 && isdigit(argv[1][n])) {
printf("Successn%sn", argv[1]);
return 0;
} else {
printf("Usage: ./caesar keyn");
return 1;
}
您的错误在这里:
if (argc == 2 && isdigit(argv[1][n])) {
这一行没有意义,您正在检查第一个参数的第n个字符是否是一个数字,但(1(您甚至不知道第一个参数是否有足够的字符(n
由atoi
返回,因此它可以任意大(,(2(您没有检查参数的所有数字。
如果你想检查给程序的第一个参数中的每个字符都是一个数字,你可以用两种方法:
遍历每个字符并使用
isdigit()
:进行检查#include <stdio.h> #include <ctype.h> int main(int argc, char **argv) { char *c; if (argc != 2) { fputs("Usage: ./prog <key>n", stderr); return 1; } for (c = argv[1]; *c != ' '; c++) { if (!isdigit(*c)) { fputs("Usage: ./prog <key>n", stderr); return 1; } } printf("Success!n%sn", argv[1]); return 0; }
使用类似
strtol
的函数(而不是atoi
,因为它不会发出错误信号(。使用strtol
还可以自动检查数字是否在可以存储在long
中的值范围内(如果不在,则返回LONG_MIN
或LONG_MAX
,并适当设置errno
(。#include <stdio.h> #include <stdlib.h> #include <errno.h> #include <limits.h> int main(int argc, char **argv) { long num; char *endp; if (argc != 2) { fputs("Usage: ./prog <key>n", stderr); return 1; } errno = 0; num = strtol(argv[1], &endp, 10); if (endp == argv[1] || *endp != ' ' || errno == ERANGE) { fputs("Usage: ./prog <key>n", stderr); return 1; } printf("Success!n%ldn", num); return 0; }
选项2的优点是已经为您转换了数字,所以我建议您不要选择选项1注意如果给定字符串以-
(例如-123
(开头,则strtol
可能返回负值:如果不允许负数,则可能需要检查该值。
strspn
并检查它是否包含整个字符串。在几乎所有情况下,strspn
都会比任何手动编码版本更快,除非您将验证和转换结合起来。
这是你的代码,带有一个验证函数,可以做到这一点:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int validate_arg(const char *s) {
size_t len;
len = strspn(s, "0123456789");
return len > 0 && !s[len];
}
int main(int argc, string argv[]) {
int n = atoi(argv[1]);
if (argc == 2 && validate_arg(argv[1])) {
printf("Successn%sn", argv[1]);
return 0;
} else {
printf("Usage: ./caesar keyn");
return 1;
}
}
附带说明:最好使用无符号类型,并使用strtoul
转换数字。
当我运行程序时,一些数字被认为是错误的。
使用类似"123"
的输入参数,下面的代码尝试检查3个字符参数的第123个字符是否为数字。访问"123"
之外的argv[1]
是未定义的行为(UB(-错误。
int n = atoi(argv[1]);
if (... isdigit(argv[1][n])) ... // UB
测试输入是否全部为数字:
使用
argv[1]
检查之前的预期参数数。测试字符串
argv[1][]
的每个字符。
样品
int main(int argc, string argv[]) {
if (argc == 2) {
const char *digit = argv[1];
while (*digit >= '0' && *digit <= '9') {
digit++;
}
// If code reached the end of the string?
if (*digit == ' ') {
printf("Successn%sn", argv[1]);
return 0;
}
}
printf("Usage: ./caesar keyn");
return 1;
}
代码也可以使用isdigit()
,最好使用unsigned char
值调用:
const unsigned char *digit = argv[1];
while (isdigit(*digit)) {
digit++;
}