【问题标题】:Understanding "Pset 2: Caesar" code in CS50了解 CS50 中的“Pset 2: Caesar”代码
【发布时间】:2020-11-20 21:24:55
【问题描述】:
#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”问题。我可以获取命令行参数并检查它们是否为数字。

我面临的问题是,在检查参数的有效性之后,我希望程序返回该值。我想检查给定的输入是否只是数字。如果是,我希望程序使用该数值参数值来计算密码。问题是_我使用循环来检查输入,我必须使用continue; 我很困惑,因为如果我删除continue;,程序将无法验证密钥的任务。

示例:如果我将continue; 替换为printf("True\n");,程序在输入20 后打印TrueTrue。输入20x 后,我得到TrueTrueUsage: ./Caesar key,而理想情况下,它应该只返回Usage: ./Caesar key

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

【问题讨论】:

  • @kiner_shah 这是今年版本的问题。
  • 您只需在for 循环内的else 块中的printf 之后添加return 1。此外,您不会从 main 返回任何整数 - 它的返回类型是 int
  • 无需打印“True”。之前有continue 声明对吗?这是正确的——如果cmd[i] 是一个数字,你需要使用continueif (isdigit(cmd[i])) { continue; } else { printf("Usage: %s key\n", argv[0]); return 1; }

标签: c loops command-line-arguments cs50


【解决方案1】:

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

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

【讨论】:

    【解决方案2】:

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

    1. 验证是否给出了至少一个参数;
    2. 循环参数以验证每个字符是否为数字;
    • 如果找到非数字,则输出错误,显示用法,返回EXIT_FAILURE (1)
    1. 有效参数——输出键。

    虽然检查(argc == 2) 以在命令行上只需要一个参数是完全可以的,但至少考虑一下需要什么通常是有帮助的。您至少需要一个参数,因此检查(argc &lt; 2) 可以识别缺少参数,但如果您采用其他可选参数,则不会阻止输入多个参数。例如:

        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 终止字符 '\0'(其 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 */
    }
    

    使用/输出示例

    没有参数:

    $./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
    

    如果您还有其他问题,或者我以任何方式误解了您的问题,请查看并告诉我。

    【讨论】:

    • 我根据我目前所学的修改了代码,它可以工作。但是,当我尝试将值返回给主函数时,我收到错误use of undeclared identifier 'key'。我已经完成了另一个问题并且没有遇到这个错误。老实说,我是编程新手,我不知道如何返回值或声明函数。代码:codeshare.io/anyv11>
    • 是的,您必须将cmd 中的内容转换为int,然后返回该值。 (使用sscanf() 将最容易进行转换,但建议使用strtol() 对转换进行全面错误检查)"key" 只是printf 格式字符串的一部分,而不是声明的变量。此外,虽然您可以从函数返回任何值,但您只能将 01main() 返回到您的 shell。这就是 C 提供 2 个宏,EXIT_SUCCESS (0) 和 EXIT_FAILURE (1`) 的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多