如何在Vigenere密码CS50 pset2中重用(循环)密钥 [英] How to reuse(loop) key in vigenere cipherkey 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屋!