检查第一个参数是否是仅由十进制数字组成的有效数字
Check if first argument is a valid number consisting of only decimal digits
这是我尝试用于“验证密钥”部分的代码,以便仅当参数为数字时才尝试 return 成功。但是,当我 运行 我的程序时,一些数字被认为是错误的。我不明白为什么。
~/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("Success\n%s\n", argv[1]);
return 0;
} else {
printf("Usage: ./caesar key\n");
return 1;
}
你的错误在这里:
if (argc == 2 && isdigit(argv[1][n])) {
这一行没有意义,您正在检查第一个参数的 n-th 字符是否为数字,但是 (1) 您甚至不知道第一个参数是否有足够的字符 (n
由 atoi
编辑 return,因此它可以任意大)和 (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 != '[=11=]'; c++) {
if (!isdigit(*c)) {
fputs("Usage: ./prog <key>\n", stderr);
return 1;
}
}
printf("Success!\n%s\n", argv[1]);
return 0;
}
使用像 strtol
这样的函数( 而不是 atoi
,因为它确实不是信号错误)。使用 strtol
还可以自动检查数字是否在可以存储在 long
中的值范围内(如果不在,LONG_MIN
或 LONG_MAX
是 returned 并且 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 != '[=12=]' || errno == ERANGE) {
fputs("Usage: ./prog <key>\n", stderr);
return 1;
}
printf("Success!\n%ld\n", num);
return 0;
}
选项 2 的优点是已经为您转换了数字,因此我建议您选择选项 1。注意 strtol
可以 return如果给定的字符串以 -
开头(例如 -123
),则为负值:如果您不允许使用负数,则可能需要检查一下。
when I run my program, some numbers are considered wrong.
使用像 "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 == '[=11=]') {
printf("Success\n%s\n", argv[1]);
return 0;
}
}
printf("Usage: ./caesar key\n");
return 1;
}
代码也可以使用 isdigit()
,最好用 unsigned char
值调用:
const unsigned char *digit = argv[1];
while (isdigit(*digit)) {
digit++;
}
验证此类输入的正确方法是使用 strspn
并检查它是否吃掉了整个字符串。在几乎所有情况下,strspn
都比任何 hand-coded 版本都快,除非您将验证和转换结合起来。
这是你的代码,其中的验证函数正是这样做的:
#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("Success\n%s\n", argv[1]);
return 0;
} else {
printf("Usage: ./caesar key\n");
return 1;
}
}
Side-note:最好用无符号类型,用strtoul
.
转换数
这是我尝试用于“验证密钥”部分的代码,以便仅当参数为数字时才尝试 return 成功。但是,当我 运行 我的程序时,一些数字被认为是错误的。我不明白为什么。
~/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("Success\n%s\n", argv[1]);
return 0;
} else {
printf("Usage: ./caesar key\n");
return 1;
}
你的错误在这里:
if (argc == 2 && isdigit(argv[1][n])) {
这一行没有意义,您正在检查第一个参数的 n-th 字符是否为数字,但是 (1) 您甚至不知道第一个参数是否有足够的字符 (n
由 atoi
编辑 return,因此它可以任意大)和 (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 != '[=11=]'; c++) { if (!isdigit(*c)) { fputs("Usage: ./prog <key>\n", stderr); return 1; } } printf("Success!\n%s\n", argv[1]); return 0; }
使用像
strtol
这样的函数( 而不是atoi
,因为它确实不是信号错误)。使用strtol
还可以自动检查数字是否在可以存储在long
中的值范围内(如果不在,LONG_MIN
或LONG_MAX
是 returned 并且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 != '[=12=]' || errno == ERANGE) { fputs("Usage: ./prog <key>\n", stderr); return 1; } printf("Success!\n%ld\n", num); return 0; }
选项 2 的优点是已经为您转换了数字,因此我建议您选择选项 1。注意 strtol
可以 return如果给定的字符串以 -
开头(例如 -123
),则为负值:如果您不允许使用负数,则可能需要检查一下。
when I run my program, some numbers are considered wrong.
使用像 "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 == '[=11=]') {
printf("Success\n%s\n", argv[1]);
return 0;
}
}
printf("Usage: ./caesar key\n");
return 1;
}
代码也可以使用 isdigit()
,最好用 unsigned char
值调用:
const unsigned char *digit = argv[1];
while (isdigit(*digit)) {
digit++;
}
验证此类输入的正确方法是使用 strspn
并检查它是否吃掉了整个字符串。在几乎所有情况下,strspn
都比任何 hand-coded 版本都快,除非您将验证和转换结合起来。
这是你的代码,其中的验证函数正是这样做的:
#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("Success\n%s\n", argv[1]);
return 0;
} else {
printf("Usage: ./caesar key\n");
return 1;
}
}
Side-note:最好用无符号类型,用strtoul
.