了解 "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.

问题陈述link:https://cs50.harvard.edu/x/2020/psets/2/caesar/

如果代码遇到 不是 数字的字符,您可以提前中断循环:

   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;
}

您正在使确认程序的第一个参数全是数字的逻辑复杂化。你真的有三个任务:

  1. 验证至少给出了一个参数;
  2. 遍历参数以验证每个字符都是数字;
  • 如果找到非数字,输出错误,显示用法,return EXIT_FAILURE (1)
  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 charEOF 的值,以便强制转换为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

检查一下,如果您还有其他问题,或者我以任何方式误读了您的问题,请告诉我。