CS50 Pset 2-ceasar密码

时间:2019-05-23 09:52:01

标签: c cs50 caesar-cipher

它没有显示我想要显示的是输入文本的加密版本,而是符号,正如我猜想的那样,看起来有点像“?”在终端输出。谁能帮我找到我错过或做错的事吗?

#include <cs50.h>
#include <stdio.h>
#include <string.h>

int main(int argc, string argv[])
{
    if (argc == 2)
    {
        string ptext = get_string("plaintext: ");
        int key = (int) argv[1];
        printf("ciphertext: ");
        for (int i = 0, n = strlen(ptext); i < n; i++)
        {
            printf("%c", (( ptext[i] + key ) % 26);
        } 
        printf("\n");
    }
    else
    {
        printf("Invalid input. \n");
    }

}

我希望'hello'的输出为'ifmmp',但实际上不是。

2 个答案:

答案 0 :(得分:0)

此代码是错误的:

int key = (int) argv[1];

argvstring的数组,在CS50中仅是模糊的char *指针。

5.1.2.2.1 Program startup of the C standard

  

在程序启动时调用的函数称为main。该实现没有为此函数声明任何原型。它应使用返回类型int且没有参数来定义:

    int main(void) { /* ... */ }
     

或具有两个参数(尽管可以使用任何名称,但在此处称为argc和argv,因为它们是声明它们的函数的局部名称):

    int main(int argc, char *argv[]) { /* ... */ }
     

或同等学历; ...

因此argv[1]是一个char *指针值,然后将其分配给一个int值。那会占用一些内存的地址(例如argv[1]中的值为0xFF0403220020480C),并试图将其填充到int变量key的可能4个字节中(这种情况下将被赋予截断值0x0020480C。)

这似乎不是您想要做的。

(IMO,您的问题是一个很好的例子,说明为什么CS50对char *类型的string进行混淆是一个非常糟糕的主意。如果不理解指针和{{ 1}}终止的NUL字符串可通过char指针访问,而char *的混淆使之变得更加困难。)

如果您想convert a string to a numeric value,则可能需要something like strtol()never use atoi() as it has no error checking and its use can invoke undefined behavior):

string

对于尝试使用此代码的任何人,练习都省略适当的标题;-)

请注意,我将char firstCharNotConverted; // set errno to zero as strtol() errno = 0; long key = strtol( argv[ 1 ], &firstCharNotConverted, 0 ); // if errno is now non-zero, the call to strtol() failed (per Linux man page) // need to examine key and the contents of firstCharNotConverted // to figure out why if ( errno != 0 ) { ... } 用于long,因为如果将返回值强制转换为key,则无法对strtol()进行正确的错误检查。 / p>

错误检查int可能会有些复杂,因为返回的值(并在上面的代码中分配给strtol())可以是任何值,并且不可能存在不合法的值{{1 key可以返回的}}值表示错误,因此要进行正确的错误检查,您需要检查longstrtol()的值以正确确定是否确实发生了错误。 Linux man page指出:

  

由于strtol()可以合法地返回0,LONG_MAX或LONG_MIN          (对于strtoll()为LLONG_MAX或LLONG_MIN)是否成功,          调用程序应在调用之前将errno设置为0,然后          通过检查errno是否具有一个错误来确定是否发生了错误          通话后返回非零值。

在调用errno之后,您需要检查firstCharNotConvertedstrtol()还是key的{​​{1}}等于LONG_MIN下溢或上溢,或者如果LONG_MAXerrno,则需要检查ERANGE的内容,以确定转换失败的原因。请注意,如果key为零,并且0不等于firstCharNotConverted,则输入字符串已从零正确转换。

您的Ceaser密码实现也不正确:

key

只会打印出从firstCharNotConvertedargv[ 1 ]之间的值的字符-在ASCII字符集中不是字母。

这里已经发布了许多Ceaser密码问题,因此我不会编写代码。有关一个示例问题,请参见Caesar's Cipher Code

答案 1 :(得分:0)

问题出在这里printf("%c", (( ptext[i] + key ) % 26);。特别是% 26。它肯定看起来像问题集:

  

更正式地说,如果p是一些纯文本(即未加密的消息),   pi是p中的第i个字符,k是密钥(即,a   非负整数),则密文c中的每个字母ci为   计算为

     

ci =(pi + k)%26

     

其中%26在这里表示“除以26所得的余数。”

但是,pset继续说:

  

认为A(或a)为0,B(或b)为1,…,H(或h)为7,I(或i)为   8,…,Z(或z)为25。

问题在于字符ptext[i]ascii value of the letter,而不是“字母索引”。

也许可以在实验室的伪代码部分中查看扰流板,尤其是#5:

  

遍历明文的每个字符:

     
      
  • 如果是大写字母,请将其旋转,保留大小写,然后打印出旋转的字符
  •   
  • 如果是小写字母,请将其旋转,保留大小写,然后打印出旋转的字符
  •   
  • 如果都不是,则按原样打印字符
  •   

您可能会发现walkthrough(来自课程的早期迭代)很有帮助。