了解 "Pset 2: Caesar" CS50 中的代码
Understanding "Pset 2: Caesar" code in CS50
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string cmd = argv[1];
for (int i = 0, n = strlen(cmd); i<n ; i++)
{
if (isdigit(cmd[i]))
{
continue;
}
else
{
printf("Usage: %s key \n", argv[0]);
}
}
}
else
{
printf("Usage: %s key \n", argv[0]);
}
}
我正在学习 CS50 课程,并且遇到了“Pset2:Caesar”问题。我可以接受命令行参数并检查它们是否为数字。
我面临的问题是,在检查参数的有效性后,我希望程序 return 该值。我想检查给定的输入是否仅为数字。如果是,我希望程序使用该数字参数值来计算密码。问题是_我正在使用循环来检查输入,我必须使用 continue;
我很困惑,因为如果我删除 continue;
程序将无法完成密钥验证任务。
示例:如果我将 continue;
替换为 printf("True\n");
,程序在输入 20
后打印 TrueTrue
。在给出 20x
作为输入后,我得到 TrueTrueUsage: ./Caesar key
而理想情况下,它应该只有 return Usage: ./Caesar key
.
如果代码遇到 不是 数字的字符,您可以提前中断循环:
if ( !isdigit( cmd[i] ) )
{
printf("Usage: %s key \n", argv[0]);
break;
}
还有函数 strtol()
将参数转换为整数。它会为您处理错误。
#include <stdio.h>
//#include <cs50.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
if (argc == 2)
{
char *error_at = NULL;
long rotation = strtol( argv[1], &error_at, 10 );
if ( rotation == 0 )
{
if ( error_at != argv[1] )
fprintf( stderr, "A rotation of zero is ineffective\n" );
else if ( error_at == argv[1] )
fprintf( stderr, "That's not a number!\n" );
exit( 1 );
}
else
{
// Cypher is limited to A-Z
rotation %= 26;
printf( "DEBUG: rotation is %ld\n", rotation );
}
}
else
{
printf ("Usage: %s key \n", argv[0]);
exit( 1 );
}
return 0;
}
您正在使确认程序的第一个参数全是数字的逻辑复杂化。你真的有三个任务:
- 验证至少给出了一个参数;
- 遍历参数以验证每个字符都是数字;
- 如果找到非数字,输出错误,显示用法,return
EXIT_FAILURE
(1
)
- 有效参数 -- 输出键。
虽然检查 (argc == 2)
以在命令行上只需要一个参数是完全没问题的,但至少考虑一下需要什么通常会很有帮助。在那里您至少需要一个参数,因此检查 (argc < 2)
确定缺少参数,但如果您采用其他可选参数,则不会阻止输入超过 1 个参数。例如:
if (argc < 2 ) { /* validate 1 argument given */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s key (all digits)\n", argv[0]);
return 1;
}
(注意: 出错时,不需要 else
语句。只需处理错误并退出。这样可以在其余部分节省一定程度的缩进你的代码。)
验证每个字符都是一个数字需要简单地遍历每个字符并使用 isdigit()
检查。你不需要 strlen()
。在 C 中,字符串以 nul 终止字符 '[=23=]'
终止(其 ASCII 值为 0
)。要循环一个字符串,您只需要:
string cmd = argv[1]; /* assing to cmd */
for (int i = 0; cmd[i]; i++) /* loop over each char in cmd */
if (isdigit((unsigned char)cmd[i]) == 0) { /* if non-digit, handle error */
fprintf (stderr, "error: '%c' is non-digit.\n"
"usage: %s key (all digits)\n", cmd[i], argv[0]);
return 1;
}
(注意:再次,当达到需要退出的错误条件时,不需要else
,只需处理错误并退出)
还要注意传递给 isdigit()
宏的值(对于所有 ctype.h
宏)必须具有 unsigned char
或 EOF
的值,以便强制转换为unsigned char
是必要的。看man 3 isalpha(明白一个char
的值永远在unsigned char
以内,但要早点养成好习惯)
验证所有字符都是数字后,剩下的就是输出您的密钥。总而言之,您将拥有:
#include <stdio.h>
#include <ctype.h>
#include <cs50.h>
int main (int argc, char **argv) {
if (argc < 2 ) { /* validate 1 argument given */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s key (all digits)\n", argv[0]);
return 1;
}
string cmd = argv[1]; /* assing to cmd */
for (int i = 0; cmd[i]; i++) /* loop over each char in cmd */
if (isdigit((unsigned char)cmd[i]) == 0) { /* if non-digit, handle error */
fprintf (stderr, "error: '%c' is non-digit.\n"
"usage: %s key (all digits)\n", cmd[i], argv[0]);
return 1;
}
printf ("key: %s\n", cmd); /* output good key */
}
例子Use/Output
没有参数:
$./bin/pset2_ceaser
error: insufficient input,
usage: ./bin/pset2_ceaser key (all digits)
无效参数:
$ ./bin/pset2_ceaser 123foo
error: 'f' is non-digit.
usage: ./bin/pset2_ceaser key (all digits)
良好的输入:
$ ./bin/pset2_ceaser 12345
key: 12345
检查一下,如果您还有其他问题,或者我以任何方式误读了您的问题,请告诉我。
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
int main(int argc, string argv[])
{
if (argc == 2)
{
string cmd = argv[1];
for (int i = 0, n = strlen(cmd); i<n ; i++)
{
if (isdigit(cmd[i]))
{
continue;
}
else
{
printf("Usage: %s key \n", argv[0]);
}
}
}
else
{
printf("Usage: %s key \n", argv[0]);
}
}
我正在学习 CS50 课程,并且遇到了“Pset2:Caesar”问题。我可以接受命令行参数并检查它们是否为数字。
我面临的问题是,在检查参数的有效性后,我希望程序 return 该值。我想检查给定的输入是否仅为数字。如果是,我希望程序使用该数字参数值来计算密码。问题是_我正在使用循环来检查输入,我必须使用 continue;
我很困惑,因为如果我删除 continue;
程序将无法完成密钥验证任务。
示例:如果我将 continue;
替换为 printf("True\n");
,程序在输入 20
后打印 TrueTrue
。在给出 20x
作为输入后,我得到 TrueTrueUsage: ./Caesar key
而理想情况下,它应该只有 return Usage: ./Caesar key
.
如果代码遇到 不是 数字的字符,您可以提前中断循环:
if ( !isdigit( cmd[i] ) )
{
printf("Usage: %s key \n", argv[0]);
break;
}
还有函数 strtol()
将参数转换为整数。它会为您处理错误。
#include <stdio.h>
//#include <cs50.h>
#include <stdlib.h>
int main( int argc, char *argv[] )
{
if (argc == 2)
{
char *error_at = NULL;
long rotation = strtol( argv[1], &error_at, 10 );
if ( rotation == 0 )
{
if ( error_at != argv[1] )
fprintf( stderr, "A rotation of zero is ineffective\n" );
else if ( error_at == argv[1] )
fprintf( stderr, "That's not a number!\n" );
exit( 1 );
}
else
{
// Cypher is limited to A-Z
rotation %= 26;
printf( "DEBUG: rotation is %ld\n", rotation );
}
}
else
{
printf ("Usage: %s key \n", argv[0]);
exit( 1 );
}
return 0;
}
您正在使确认程序的第一个参数全是数字的逻辑复杂化。你真的有三个任务:
- 验证至少给出了一个参数;
- 遍历参数以验证每个字符都是数字;
- 如果找到非数字,输出错误,显示用法,return
EXIT_FAILURE
(1
)
- 有效参数 -- 输出键。
虽然检查 (argc == 2)
以在命令行上只需要一个参数是完全没问题的,但至少考虑一下需要什么通常会很有帮助。在那里您至少需要一个参数,因此检查 (argc < 2)
确定缺少参数,但如果您采用其他可选参数,则不会阻止输入超过 1 个参数。例如:
if (argc < 2 ) { /* validate 1 argument given */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s key (all digits)\n", argv[0]);
return 1;
}
(注意: 出错时,不需要 else
语句。只需处理错误并退出。这样可以在其余部分节省一定程度的缩进你的代码。)
验证每个字符都是一个数字需要简单地遍历每个字符并使用 isdigit()
检查。你不需要 strlen()
。在 C 中,字符串以 nul 终止字符 '[=23=]'
终止(其 ASCII 值为 0
)。要循环一个字符串,您只需要:
string cmd = argv[1]; /* assing to cmd */
for (int i = 0; cmd[i]; i++) /* loop over each char in cmd */
if (isdigit((unsigned char)cmd[i]) == 0) { /* if non-digit, handle error */
fprintf (stderr, "error: '%c' is non-digit.\n"
"usage: %s key (all digits)\n", cmd[i], argv[0]);
return 1;
}
(注意:再次,当达到需要退出的错误条件时,不需要else
,只需处理错误并退出)
还要注意传递给 isdigit()
宏的值(对于所有 ctype.h
宏)必须具有 unsigned char
或 EOF
的值,以便强制转换为unsigned char
是必要的。看man 3 isalpha(明白一个char
的值永远在unsigned char
以内,但要早点养成好习惯)
验证所有字符都是数字后,剩下的就是输出您的密钥。总而言之,您将拥有:
#include <stdio.h>
#include <ctype.h>
#include <cs50.h>
int main (int argc, char **argv) {
if (argc < 2 ) { /* validate 1 argument given */
fprintf (stderr, "error: insufficient input,\n"
"usage: %s key (all digits)\n", argv[0]);
return 1;
}
string cmd = argv[1]; /* assing to cmd */
for (int i = 0; cmd[i]; i++) /* loop over each char in cmd */
if (isdigit((unsigned char)cmd[i]) == 0) { /* if non-digit, handle error */
fprintf (stderr, "error: '%c' is non-digit.\n"
"usage: %s key (all digits)\n", cmd[i], argv[0]);
return 1;
}
printf ("key: %s\n", cmd); /* output good key */
}
例子Use/Output
没有参数:
$./bin/pset2_ceaser
error: insufficient input,
usage: ./bin/pset2_ceaser key (all digits)
无效参数:
$ ./bin/pset2_ceaser 123foo
error: 'f' is non-digit.
usage: ./bin/pset2_ceaser key (all digits)
良好的输入:
$ ./bin/pset2_ceaser 12345
key: 12345
检查一下,如果您还有其他问题,或者我以任何方式误读了您的问题,请告诉我。