简体   繁体   English

如何在Vigenere密码CS50 pset2中重用(循环)密钥

[英]How to reuse(loop) key in vigenere cipherkey cs50 pset2

I was making a program for Vigenere cipher. 我正在为Vigenere密码编写程序。 I made the program print the cipher text successfully. 我使程序成功打印了密文。 But, I can't loop the key. 但是,我无法循环播放密钥。 so if my key was 'abc' and my plain text was hello, it should print 'hfnlp' not 'hfn'. 因此,如果我的密钥是'abc'而我的纯文本是hello,则应打印'hfnlp'而不是'hfn'。

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

int main(int argc, string argv[])
{
    if(argc != 2)
    {
        printf("\aError\n");
        return 1;
    }
    else
    {
        string a = argv[1]; // converts argv[1]

        printf("plaintext: ");
        string b = get_string(); // takes the plaintext

        printf("ciphertext: ");

        for(int c = 0, d = strlen(a); c < d; c++)
        {
            for(int e = 0, f = strlen(b); e < f; e++)
            {
                if(islower(a[c]))
                    {
                        printf("%c\n",  b[e] + ( (a[c] - 97) % 26) ); // works for lowercase letters
                        return 0;
                    }
                    else if(isupper(a[i]))
                    {
                        printf("%c\n",  b[e] + ( (a[c] - 65) % 26) ); // works for uppercase letter
                    }
                    else
                    {
                         printf("%c", b[e]); // works for non alphabetical inputs
                    }

                    if(true)
                        break;
            }
   }

    printf("\n");
}
}

Your choice of single-letter variable names is odd; 您选择的单字母变量名称很奇怪; it makes it harder to work with your code. 这使得使用代码变得更加困难。 I'm not a fan of long names either, but intermediate length variable names (2-8 characters — except for some stylized single-letter names ( c , i , j , k , p , s ) — is typically appropriate). 我也不喜欢长名称,而是中等长度的变量名(通常使用2-8个字符-除了一些风格化的单字母名称( cijkps ))。

You've got trouble because if your key is 6 characters and your string is 24 alphabetic characters, you'll attempt output 144 alphabetic characters because of the loop structure. 您遇到了麻烦,因为如果您的键是6个字符,而字符串是24个字母字符,则由于循环结构,您将尝试输出144个字母字符。 You only need a single loop that iterates over the characters in the plain text. 您只需要一个循环即可遍历纯文本中的字符。 You have a separate variable that cycles over the length of the key, resetting back to the start when it runs out. 您有一个单独的变量,该变量在密钥的长度上循环,用完后会重置为开始。 In this code, the key length is in keylen (you used d ) and the offset (index) into the key is in keyoff (you used c ) — but the key is still in a because that's what you used. 在此代码中,键长为keylen (使用d ),键的偏移量(索引)在keyoff (使用c )中,但是键仍在a因为这就是您所使用的。 Left to my own devices, I'd probably use text (or maybe plain ) in place of b , textlen in place of f , and I'd use i instead of e for the loop variable. 留给我自己的设备,我可能会使用text (或者也许是plain )代替b ,使用textlen代替f ,并且我将i而不是e用作循环变量。 If I wanted to use short indexes, I might use k instead of keyoff . 如果我想使用短索引,可以使用k而不是keyoff I might also edit the string in situ and print the whole string at the end. 我也可以原位编辑字符串,并在最后打印整个字符串。

This code also ensures that the alpha characters in the key are in lower case. 此代码还确保键中的字母字符为小写。 It doesn't ensure that the key is all alpha; 它不能确保键全为字母; it arguably should and it would be trivial to do so since the key is scanned anyway. 这样做应该是很容易的,因为无论如何都要扫描密钥。 As it stands, it is a case of GIGO — garbage in, garbage out. 就目前而言,这是GIGO的一种情况-垃圾进,垃圾出。

The code converts the input letter ( az or AZ ) into an 'offset into the alphabet' by subtracting a or A , converts the key letter into an offset into the alphabet, adds the two offsets modulo 26 (number of letters in the alphabet), and converts the offset back into a letter of the appropriate case. 该代码通过减去aA将输入字母( azAZ )转换为“字母偏移量”,将关键字母转换为字母偏移量,将两个偏移量模26(字母中的字母数)相加,并将偏移量转换回适当大小写的字母。

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

int main(int argc, string argv[])
{
    if (argc != 2 || strlen(argv[1]) == 0)
    {
        fprintf(stderr, "Usage: %s key < text\n", argv[0]);
        return 1;
    }

    string a = argv[1];
    int keylen = strlen(a);
    for (int i = 0; i < keylen; i++)
        a[i] = tolower((unsigned char)a[i]);
    printf("key: %s\n", a);

    printf("plaintext: ");
    string b = get_string();

    printf("ciphertext: ");

    int keyoff = 0;
    // Step through each character of the plain text.  Encrypt each
    // alpha character with the (lower-case) key letter at a[keyoff],
    // incrementing keyoff.  Don't increment key offset when processing
    // non-alpha data.
    for (int e = 0, f = strlen(b); e < f; e++)
    {
        if (islower(b[e]))
            printf("%c", ((b[e] - 'a') + (a[keyoff++] - 'a')) % 26 + 'a');
        else if (isupper(b[e]))
            printf("%c", ((b[e] - 'A') + (a[keyoff++] - 'a')) % 26 + 'A');
        else
            printf("%c", b[e]);
        if (keyoff >= keylen)
            keyoff = 0;
    }
    printf("\n");
    return 0;
}

When compiled to the program vc41 and run, it produces, for example: 当编译为程序vc41并运行时,它将产生例如:

$ vc41 abcdef
key: abcdef
plaintext: The quick brown Fox jumped over the lazy Dog.
ciphertext: Tig tyncl dusbn Gqa nzmqgg saes vki qaaa Gsl.
$

I generated an 8-letter random key (it was GZlfmTMk ) and ran the code on a number of 'complete alphabet' strings: 我生成了一个8个字母的随机密钥(它是GZlfmTMk ),并在许多“完整字母”字符串上运行了代码:

$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: Pack my box with five dozen liquor jugs.
ciphertext: Vznp yr nyd vtyt yufk czeqg xswtzw vnsc.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: The five boxing wizards jump quickly.
ciphertext: Zgp kuoq luwtss pujgqox vnyz wtthwek.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: How vexingly quick daft zebras jump.
ciphertext: Nnh aqquxmkj vgbou jzqy lxnbgr uzyi.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: Bright vixens jump; dozy fowl quack.
ciphertext: Hqtltm hsddyx vnyz; jnkd rhiv wtlhw.
$ vc41 GZlfmTMk
key: gzlfmtmk
plaintext: The quick brown fox jumps over the lazy dog.
ciphertext: Zgp vgbou hqzbz yah ptxue hhox ssj xtli jnr.
$

(I'll note in passing that on a Mac running macOS Sierra 10.12.6 using GCC 7.1.0, this code links without including the (new) CS50 library — there is a system function get_string() that has a different interface to the CS50 version that satisfies the reference but crashes the program. However, it isn't documented by man get_string , so I'm not sure what the system function of that name actually does; I haven't chased it more actively, or found out how extensive the problem is. That caused me a headache that the old CS50 library didn't. Grumble…) (我会指出,在运行使用GCC 7.1.0的macOS Sierra 10.12.6的Mac上,此代码链接不包含(新的)CS50库-系统功能get_string get_string()接口与该接口不同满足参考要求但导致程序崩溃的CS50版本,但是它没有被man get_string ,因此我不确定该名称的系统功能实际上是做什么的;我还没有更积极地追踪它,或者没有发现问题的严重性。这让我很头疼,旧的CS50库没有。

fix like this 像这样修复

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

int main(int argc, string argv[]){
    if(argc != 2 || !*argv[1]){
        printf("\aError:The number of command arguments is incorrect.\n");
        printf("Usage: %s key_string\n", argv[0]);
        return 1;
    }
    //Since it is `return 1;` in the if-statement, 
    //the else clause is unnecessary (unnecessarily deepening the nest)
    string key = argv[1];//It does not convert.
    size_t i, key_len;
    unsigned char curr_char;
    for(i = 0; (curr_char = key[i]) != '\0'; ++i){
        if(!isalpha(curr_char)){
            printf("\aError:Only the alphabet can be specified as the key.\n");
            return 1;
        }
        key[i] -= islower(curr_char) ? 'a' : 'A';//Convert to Deviation
    }
    key_len = i;
    i = 0;

    printf("plaintext : ");
    string plain = get_string();

    printf("ciphertext: ");

    for(size_t j = 0; (curr_char = plain[j]) != '\0'; ++j){//Scan of plain text should be the main loop.
        if(isalpha(curr_char)){
            char base_char = islower(curr_char) ? 'a' : 'A';//Avoid using magic numbers

            putchar(base_char + (curr_char - base_char + key[i]) % 26);//Make the same process one
            if(++i == key_len)
                i = 0;//reset key index
        } else {
            putchar(curr_char);//non alphabetical inputs
        }
    }
    printf("\n");
    free(plain);
}

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

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