为啥我的 vigenere.c 不工作?

Posted

技术标签:

【中文标题】为啥我的 vigenere.c 不工作?【英文标题】:Why is my vigenere.c not working?为什么我的 vigenere.c 不工作? 【发布时间】:2014-11-14 01:23:54 【问题描述】:

我不断更改此代码的循环部分,我的 check50 总是失败。我不知道发生了什么事。以下是我的代码:

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

int main(int argc, string argv[])

    // declare variables
    int cipherText;

    if (argc != 2)
    
        printf("Usage: ./vigenere keyword");
        printf("\n");
        return 1;
    
    // keyword is the second command line argument
    string key = argv[1];
    int keylen = strlen(argv[1]);

    // iterate through keyword to check if alphabetical
    for (int i = 0, n = strlen(argv[1]); i < n; i++)
    
        if ((key[i] >= '0') && (key[i] <= '9'))
        
            printf("Keyword must consist only of letters.");
            return 1;
        
    

    // get the plaintext
    string plainText = GetString();

    // encypher - iterate over the characters in string, print each one encrypted
    for (int i = 0, j = 0, n = strlen(plainText); i < n; i++, j++)
    
        // start the key again if key shorter than plainText
        if (j >= strlen(key))
        
            j = 0;
        

        // skip key[j] if plainText[i] is not an alpha character
        if (!isalpha(plainText[i]))
        
            j = (j-1);
        

        // makes Aa = 0, Zz = 25 for the uppercase letters
        if (isupper(key[j]))
        
            key[j] = (key[j] - 'A');
        

        // makes Aa = 0, Zz = 25 for lowercase letters
        else if (islower(key[j]))
        
            key[j] = (key[j] - 'a');
        


        if (isupper(plainText[i]))
        
            cipherText = (plainText[i] - 'A');
            cipherText = ((cipherText + key[j%keylen])%26) + 'A';
            printf("%c", cipherText);
        

        else if (islower(plainText[i]))
        
            cipherText = (plainText[i] - 'a');
            cipherText = ((cipherText + key[j%keylen])%26 + 'a');
            printf("%c", cipherText);
        

        else 
        
            printf("%c", plainText[i]);
           
    
    printf("\n");
    return 0;


有人回答:“第一个 for 循环有问题。条件是检查 i &gt; keylen,而应该检查 i &lt; keylen”。

同样在计算下一个输出值时,步骤应该是

(p[i]-65) 产生一个介于 0 和 25 之间的数字 添加 (key[i % keylen]) 得到一个介于 0 和 50 之间的数字 应用模 26,使数字介于 0 和 25 之间(这是缺少的步骤) 然后加65得到输出”

这就是我试图做的。

【问题讨论】:

【参考方案1】:

鉴于此代码:

int keylen = strlen(argv[1]);

// iterate through keyword to check if alphabetical
for (int i = 0, n = strlen(argv[1]); i < n; i++)

    if ((key[i] >= '0') && (key[i] <= '9'))
    
        printf("Keyword must consist only of letters.");
        return 1;
    

您在循环中的测试将数字识别为“不是字母”(这是有效的),但忽略标点符号、空格等。您可能应该使用if (!isalpha(key[i])) 进行测试(并且在错误消息中打印错误字符是礼貌的,它应该打印在标准错误上,而不是标准输出上,并且应该以换行符结尾:

        fprintf(stderr, "Keyword must consist only of letters (%c found at %d)\n",
                key[i], i+1);

您可以改进它,使其不会尝试使用%c 打印不可打印的字符,但这是朝着正确方向迈出的一大步。

你真的不需要在循环中设置n;你只是在循环之前设置了keylen,所以你可以写:

for (int i = 0; i < keylen; i++)

但是,这主要是装饰性的。你真正的问题在这里:

    // start the key again if key shorter than plainText
    if (j >= strlen(key))
    
        j = 0;
    

    // makes Aa = 0, Zz = 25 for the uppercase letters
    if (isupper(key[j]))
    
        key[j] = (key[j] - 'A');
    

    // makes Aa = 0, Zz = 25 for lowercase letters
    else if (islower(key[j]))
    
        key[j] = (key[j] - 'a');
    

您在每次迭代时通过密钥修改密钥字符串。但不幸的是,如果密钥中的任何字母是aA,您已将其转换为'\0',这意味着strlen(key) 返回的答案与之前不同。因此,您应该使用keylen 代替strlen()。 AFAICS,如果没有aA,那部分代码是可以的。

后来,你有:

    if (isupper(plainText[i]))
    
        cipherText = (plainText[i] - 'A');
        cipherText = ((cipherText + key[j%keylen])%26) + 'A';
        printf("%c", cipherText);
    

j % keylen 是多余的; j 已被限制为 0 .. keylen-1。与小写文本的代码类似。

将这些更改放在一起,并使用fgets() 模拟一个GetString() 函数,我得到:

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

typedef char *string;

static char *GetString(void)

    static char buffer[4096];
    if (fgets(buffer, sizeof(buffer), stdin) == 0)
    
        fprintf(stderr, "EOF detected in GetString()\n");
        exit(EXIT_SUCCESS);
    
    buffer[strlen(buffer) - 1] = '\0';
    return buffer;


int main(int argc, string argv[])

    // declare variables
    int cipherText;

    if (argc != 2)
    
        printf("Usage: ./vigenere keyword");
        printf("\n");
        return 1;
    
    // keyword is the second command line argument
    string key = argv[1];
    int keylen = strlen(argv[1]);

    // iterate through keyword to check if alphabetical
    for (int i = 0; i < keylen; i++)
    
        if (!isalpha(key[i]))
        
            printf("Keyword must consist only of letters (%c at %d)\n",
                   key[i], i+1);
            return 1;
        
    

    // get the plaintext
    string plainText = GetString();

    // encypher - iterate over the characters in string, print each one encrypted
    for (int i = 0, j = 0, n = strlen(plainText); i < n; i++, j++)
    
        // start the key again if key shorter than plainText
        if (j >= keylen)
        
            j = 0;
        

        // skip key[j] if plainText[i] is not an alpha character
        if (!isalpha(plainText[i]))
        
            j = (j - 1);
        

        // makes Aa = 0, Zz = 25 for the uppercase letters
        if (isupper(key[j]))
        
            key[j] = (key[j] - 'A');
        
        // makes Aa = 0, Zz = 25 for lowercase letters
        else if (islower(key[j]))
        
            key[j] = (key[j] - 'a');
        

        if (isupper(plainText[i]))
        
            cipherText = (plainText[i] - 'A');
            cipherText = ((cipherText + key[j]) % 26) + 'A';
            printf("%c", cipherText);
        
        else if (islower(plainText[i]))
        
            cipherText = (plainText[i] - 'a');
            cipherText = ((cipherText + key[j]) % 26 + 'a');
            printf("%c", cipherText);
        
        else
        
            printf("%c", plainText[i]);
        
    
    printf("\n");
    return 0;

示例运行:

$ ./vigenere bakedalaska
What a wonderful world! The news is good, and the Vigenere cipher is solved.
Xhkx d wznvorguv arrwd! Lre oegw ls rogn, aod dlh Vtgwxese mmshpr ac splfig.
$

【讨论】:

以上是关于为啥我的 vigenere.c 不工作?的主要内容,如果未能解决你的问题,请参考以下文章

如何让我的 Vigenère 密码处理消息中的空格?

如何让我的 Vigenère Cipher 忽略原始消息中的空格

c_cpp CS50 vigenere.c

PHP 中的 Vigenère 表

Python Vigenère密码不起作用

JavaScript 中的 Vigenère 密码显示或 � 字符