如何在Vigenere密码CS50 pset2中重用(循环)密钥 [英] How to reuse(loop) key in vigenere cipherkey cs50 pset2

查看:110
本文介绍了如何在Vigenere密码CS50 pset2中重用(循环)密钥的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在为Vigenere密码编写程序。我使程序成功打印了密文。但是,我无法循环播放密钥。因此,如果我的密钥是'abc'并且我的纯文本是hello,它应该显示'hfnlp'而不是'hfn'。

I was making a program for Vigenere cipher. 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'.

#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");
}
}


推荐答案

您的单字母变量名称的选择是奇怪的;这使得使用代码变得更加困难。我也不喜欢长名称,而是中等长度的变量名称(2-8个字符,除了一些程式化的单字母名称( c i j k p s )-通常是合适的)。

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).

您遇到了麻烦,因为如果您的key是6个字符,而字符串是24个字母字符,由于循环结构,您将尝试输出144个字母字符。您只需要一个循环即可遍历纯文本中的字符。您有一个单独的变量,该变量在密钥的长度上循环,用完后会重置为开始。在这段代码中,密钥长度在 keylen 中(您使用了 d ),而偏移量(索引)在密钥中位于 keyoff (您使用的是 c )中-但密钥仍位于 a ,因为这就是您所使用的。留给我自己的设备,我可能会使用 text (或者也许是 plain )代替 b textlen 代替 f ,而我会使用 i 而不是 e 作为循环变量。如果要使用短索引,可以使用 k 而不是 keyoff 。我也可以原位编辑字符串,并在末尾打印整个字符串。

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. 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. 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. If I wanted to use short indexes, I might use k instead of keyoff. I might also edit the string in situ and print the whole string at the end.

此代码还可以确保键中的字母小写。它不能确保键全为字母;这样做应该是很容易的,因为无论如何都要扫描密钥。就目前情况而言,这是GIGO的一种情况-垃圾进,垃圾出。

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.

代码转换输入字母( az AZ )减去'$code> a 或 A ,将关键字母转换成字母的偏移量,将两个偏移量模26(字母中的字母数)相加,然后将偏移量转换成适当大小写的字母。

The code converts the input letter (a-z or A-Z) 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.

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

编译为程序时 vc41 并运行,它产生例如:

When compiled to the program vc41 and run, it produces, for example:

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

我生成了一个8个字母的随机密钥(它是 GZlfmTMk ),然后在多个完整字母字符串上运行代码:

I generated an 8-letter random key (it was GZlfmTMk) and ran the code on a number of 'complete alphabet' strings:

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

(我会在运行macOS Sierra 10.12的Mac上传递它。 6使用GCC 7.1.0,此代码链接而未包括(新)CS50库—有一个系统函数 get_string()与CS50版本具有不同的接口,满足引用但使程序崩溃。但是, man get_string 并未对此进行记录,因此我不确定该名称的系统功能实际上是做什么的;我还没有'没有更积极地追逐它,或者发现了问题的严重性。这让我很头疼,旧的CS50库没有。抱怨[...]

(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…)

这篇关于如何在Vigenere密码CS50 pset2中重用(循环)密钥的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆