为啥我的 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 > keylen
,而应该检查 i < 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');
您在每次迭代时通过密钥修改密钥字符串。但不幸的是,如果密钥中的任何字母是a
或A
,您已将其转换为'\0'
,这意味着strlen(key)
返回的答案与之前不同。因此,您应该使用keylen
代替strlen()
。 AFAICS,如果没有a
或A
,那部分代码是可以的。
后来,你有:
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 不工作?的主要内容,如果未能解决你的问题,请参考以下文章