简体   繁体   English

关于CS50 pset2 vigenere

[英]About CS50 pset2 vigenere

Why my code would not skip the space and it led to wrong encryption sequence? 为什么我的代码不会跳过空格并导致错误的加密顺序?

When I check with an example "Hello, World!", my code counted the space also and converted to "Iekmo, Wnslc!" 当我查看示例“ Hello,World!”时,我的代码也计算了空间,并转换为“ Iekmo,Wnslc!”。 instead of "Iekmo, Vprke!" 而不是“ Iekmo,Vprke!” using the key "baz" 使用键“巴兹”

Can someone explain the logic behind? 有人可以解释背后的逻辑吗? Many thanks! 非常感谢!

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

//getting user encryption key


int main(int argc, string argv[])
{

    if (argc != 2)
    {
        printf("Usage: ./vigenere keyword\n");
        return 1;
    }
    //check if all are alphabeticals
    else 
    {
           for (int i = 1; i < argc; i++)
        {
            for (int j = 0; j < strlen(argv[i]); j++)
            {
                if (isalpha(argv[i][j]) == false)
                {                
                    printf("Usage: ./vigenere keyword\n");
                    return 1;
                }
            }
        }
    }  


    //getting plaintext divide it into each character
    string pt = get_string("plaintext: ");

    printf("ciphertext: ");
    //convert to ciphertext
    //C = (P + k) % 26
    for (int r = 0; r < strlen(pt); r++)
    {                           
        if (isupper(pt[r]))
        {
            //making loop with j group corresponding to keyword
            int j = r % strlen(argv[1]);
            int key = tolower(argv[1][j]) - 97;
            printf("%c", (pt[r] - 65 + key) % 26 + 65);
        }
        else if (islower(pt[r]))
        {
            //making loop with j group corresponding to keyword
            int j = r % strlen(argv[1]);
            int key = tolower(argv[1][j]) - 97;
            printf("%c", (pt[r] - 97 + key) % 26 + 97);
        }
        else
        {
            printf("%c", pt[r]);
        }

     }            
       printf("\n");       

}

The problem is with the calculation of j here int j = r % strlen(argv[1]); 问题在于在这里计算j int j = r % strlen(argv[1]); . The index of the key is not related to r (the index of the message). 关键字的索引与r (消息的索引)无关。 Program needs to iterate through the key based solely on (length of) the key. 程序需要仅根据密钥(的长度)来遍历密钥。 You need to increment it each time you "use" a key index, and "wrap" it so it doesn't go past the end. 每次“使用”键索引时,都需要增加它,然后“包装”它,以使它不会超出结尾。 You might consider declaring j before the r loop; 您可以考虑在r循环之前声明j increment j whenever you use a key index (hint: j++ ); 每当使用键索引时,递增j(提示: j++ ); and "wrap" j with modulo operator (hint: j % strlen(argv[1] ). I leave the actual code to you. 然后用模运算符“包装” j(提示: j % strlen(argv[1] )。我将实际代码留给您。

It's a lot easier to show than explain: 显示起来比解释容易得多:

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

int main(int argc, char **argv)
{
    if (argc != 2)
    {
        fprintf(stderr, "Usage: %s keyword\n", argv[0]);
        return 1;
    }

    for (int i = 1; i < argc; i++)
    {
        for (int j = 0; argv[i][j] != '\0'; j++)
        {
            if (isalpha(argv[i][j]) == false)
            {                
                fprintf(stderr, "%s: non-alphabetic character '%c' (%d) in key\n",
                        argv[0], argv[i][j], argv[i][j]);
                return 1;
            }
        }
    }

    string pt = get_string("plaintext:  ");

    printf("ciphertext: ");
    int k = 0;
    int keylen = strlen(argv[1]);
    for (int r = 0; pt[r] != '\0'; r++)
    {                           
        if (isupper(pt[r]))
        {
            int j = k++ % keylen;
            int key = tolower(argv[1][j]) - 'a';
            printf("%c", (pt[r] - 'A' + key) % 26 + 'A');
        }
        else if (islower(pt[r]))
        {
            int j = k++ % keylen;
            int key = tolower(argv[1][j]) - 'a';
            printf("%c", (pt[r] - 'a' + key) % 26 + 'a');
        }
        else
        {
            printf("%c", pt[r]);
        }

     }            
     printf("\n");       
     return 0;
}

Example run: 示例运行:

$ ./vig89 baz
plaintext:  Hello, World!
ciphertext: Iekmo, Vprke!
$

As I noted in a comment, you need to separate 'position in string, r ' from 'encrypted character number'. 正如我在评论中指出的那样,您需要将“字符串中的位置r ”与“加密的字符编号”分开。 You need an extra variable that you only increment when the character is alphabetic. 您需要一个额外的变量,仅当该字符是字母时才递增。

In the code above, k is the extra variable ( keylen is another, but it simply records the length of the key rather than repeatedly calling strlen() ). 在上面的代码中, k是额外的变量( keylen是另一个变量,但它只是记录键的长度,而不是重复调用strlen() )。 The value in k is incremented when it is known that the character is a letter and not otherwise. 当已知字符是字母时, k的值将递增,否则不会增加。

I observe that it might be sensible to process argv[1] so that you don't have to do the tolower() conversion each time; 我观察到处理argv[1]可能是明智的,这样您就不必每次都进行tolower()转换。 you could do that while validating the keyword. 您可以在验证关键字时执行此操作。

I've also reported errors on standard error, and not used strlen() in the condition part of the loops. 我还报告了有关标准错误的错误,并且没有在循环的条件部分中使用strlen() While the cost is not prohibitive if you're dealing with 3-letter keys, if you start calculating the length of a string that's 20 KiB long on each iteration, you might start to spot the overhead (unless the compiler manages to optimize it away — it might, it might not). 尽管使用3个字母的键的代价并不高昂,但如果您开始计算每次迭代的字符串长度为20 KiB,那么您可能会发现开销(除非编译器设法对其进行优化) -可能会,也可能不会)。 I've also aligned the plain text and the cipher text in the I/O. 我还将I / O中的纯文本和密文对齐。

There are quite a lot of other changes that could/should be made. 还有很多其他可以/应该进行的更改。 For example, the first for (int i = 1; …) loop is not needed; 例如,不需要第一个for (int i = 1; …)循环; you only have one argument so you only need the inner for (int j = 0; …) loop. 您只有一个参数,因此只需要内部for (int j = 0; …)循环。 It is also more idiomatic to use if (!isalpha(argv[i][j])) than to compare the result with false , especially since the isalpha macro is not guaranteed to return 0 or 1 (it returns zero or non-zero) – so changing if (isalpha(argv[i][j]) == false) to if (isalpha(argv[i][j] != true) would not be reliable. I'd probably create a simple variable char *key = argv[1]; (or string key = argv[1]; in the context of CS50, though I'm not convinced that the CS50 typedef char *string; is a good idea) and use that in the program. 使用if (!isalpha(argv[i][j]))比将结果与false进行比较也更惯用,尤其是因为isalpha宏不能保证返回0或1(它返回零或非零) )–因此将if (isalpha(argv[i][j]) == false)更改为if (isalpha(argv[i][j] != true)是不可靠的。我可能会创建一个简单的变量char *key = argv[1]; (或string key = argv[1];在CS50的上下文中,尽管我不认为CS50 typedef char *string;是个好主意),并在程序中使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM