如何在 vigenere cipherkey cs50 pset2 中重用(循环)密钥
How to reuse(loop) key in vigenere cipherkey cs50 pset2
我正在为 Vigenere 密码编写程序。我让程序成功地打印了密文。但是,我不能循环键。所以如果我的密钥是 '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");
}
}
你选择的单字母变量名很奇怪;它使使用您的代码变得更加困难。我也不喜欢长名称,但喜欢中等长度的变量名称(2-8 个字符——除了一些程式化的单字母名称(c
、i
、j
、k
, p
, s
) — 通常是合适的)。
你遇到了麻烦,因为如果你的键是 6 个字符而你的字符串是 24 个字母字符,由于循环结构,你将尝试输出 144 个字母字符。您只需要一个循环遍历纯文本中的字符。你有一个单独的变量,它在密钥的长度上循环,当它 运行 结束时重置回开始。在此代码中,密钥长度在 keylen
中(您使用了 d
),密钥的偏移量(索引)在 keyoff
中(您使用了 c
)——但是密钥仍在 a
中,因为那是您使用的。留给我自己的设备,我可能会使用 text
(或者 plain
)代替 b
,textlen
代替 f
,并且我将使用 i
而不是 e
作为循环变量。如果我想使用短索引,我可能会使用 k
而不是 keyoff
。我也可以在原地编辑字符串并在末尾打印整个字符串。
此代码还确保密钥中的字母字符为小写。它不能确保密钥都是 alpha;可以说,这样做应该是微不足道的,因为无论如何都会扫描密钥。就目前而言,这是 GIGO 的情况——垃圾进,垃圾出。
代码通过减去a
或A
将输入字母(a-z
或A-Z
)转换为'offset into the alphabet',将关键字母转换为字母表中的偏移量,将两个偏移量以 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;
}
当编译成程序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.
$
我生成了一个 8 个字母的 运行dom 密钥(它是 GZlfmTMk
)和 运行 一些 'complete alphabet' 字符串上的代码:
$ 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.
$
(我会注意到在使用 GCC 7.1.0 的 Mac 运行ning macOS Sierra 10.12.6 上,此代码链接不包括(新的)CS50 库 - 那里是一个系统函数get_string()
,与CS50版本的接口不同,满足参考,但导致程序崩溃。但是,man get_string
没有记录,所以我不确定系统是什么这个名字的功能实际上是这样;我没有更积极地追逐它,也没有发现问题有多广泛。这让我很头疼,旧的 CS50 库没有。抱怨…)
像这样修复
#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]) != '[=10=]'; ++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]) != '[=10=]'; ++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);
}
我正在为 Vigenere 密码编写程序。我让程序成功地打印了密文。但是,我不能循环键。所以如果我的密钥是 '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");
}
}
你选择的单字母变量名很奇怪;它使使用您的代码变得更加困难。我也不喜欢长名称,但喜欢中等长度的变量名称(2-8 个字符——除了一些程式化的单字母名称(c
、i
、j
、k
, p
, s
) — 通常是合适的)。
你遇到了麻烦,因为如果你的键是 6 个字符而你的字符串是 24 个字母字符,由于循环结构,你将尝试输出 144 个字母字符。您只需要一个循环遍历纯文本中的字符。你有一个单独的变量,它在密钥的长度上循环,当它 运行 结束时重置回开始。在此代码中,密钥长度在 keylen
中(您使用了 d
),密钥的偏移量(索引)在 keyoff
中(您使用了 c
)——但是密钥仍在 a
中,因为那是您使用的。留给我自己的设备,我可能会使用 text
(或者 plain
)代替 b
,textlen
代替 f
,并且我将使用 i
而不是 e
作为循环变量。如果我想使用短索引,我可能会使用 k
而不是 keyoff
。我也可以在原地编辑字符串并在末尾打印整个字符串。
此代码还确保密钥中的字母字符为小写。它不能确保密钥都是 alpha;可以说,这样做应该是微不足道的,因为无论如何都会扫描密钥。就目前而言,这是 GIGO 的情况——垃圾进,垃圾出。
代码通过减去a
或A
将输入字母(a-z
或A-Z
)转换为'offset into the alphabet',将关键字母转换为字母表中的偏移量,将两个偏移量以 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;
}
当编译成程序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.
$
我生成了一个 8 个字母的 运行dom 密钥(它是 GZlfmTMk
)和 运行 一些 'complete alphabet' 字符串上的代码:
$ 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.
$
(我会注意到在使用 GCC 7.1.0 的 Mac 运行ning macOS Sierra 10.12.6 上,此代码链接不包括(新的)CS50 库 - 那里是一个系统函数get_string()
,与CS50版本的接口不同,满足参考,但导致程序崩溃。但是,man get_string
没有记录,所以我不确定系统是什么这个名字的功能实际上是这样;我没有更积极地追逐它,也没有发现问题有多广泛。这让我很头疼,旧的 CS50 库没有。抱怨…)
像这样修复
#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]) != '[=10=]'; ++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]) != '[=10=]'; ++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);
}