为什么我的代码不会跳过空格并导致错误的加密顺序?
当我查看示例“ Hello,World!”时,我的代码也计算了空间,并转换为“ Iekmo,Wnslc!”。而不是“ Iekmo,Vprke!”使用键“ baz”
有人可以解释背后的逻辑吗?非常感谢!
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
//getting user encryption key
int main(int argc, string argv[])
{
if (argc != 2)
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
//check if all are alphabeticals
else
{
for (int i = 1; i < argc; i++)
{
for (int j = 0; j < strlen(argv[i]); j++)
{
if (isalpha(argv[i][j]) == false)
{
printf("Usage: ./vigenere keyword\n");
return 1;
}
}
}
}
//getting plaintext divide it into each character
string pt = get_string("plaintext: ");
printf("ciphertext: ");
//convert to ciphertext
//C = (P + k) % 26
for (int r = 0; r < strlen(pt); r++)
{
if (isupper(pt[r]))
{
//making loop with j group corresponding to keyword
int j = r % strlen(argv[1]);
int key = tolower(argv[1][j]) - 97;
printf("%c", (pt[r] - 65 + key) % 26 + 65);
}
else if (islower(pt[r]))
{
//making loop with j group corresponding to keyword
int j = r % strlen(argv[1]);
int key = tolower(argv[1][j]) - 97;
printf("%c", (pt[r] - 97 + key) % 26 + 97);
}
else
{
printf("%c", pt[r]);
}
}
printf("\n");
}
答案 0 :(得分:1)
问题在于此处{
"presets": [
"es2015",
"react"
]
}
的j的计算。键的索引与int j = r % strlen(argv[1]);
(消息的索引)无关。程序需要仅根据密钥(的长度)来遍历密钥。每次“使用”键索引时,都需要增加它,然后“包装”它,以使它不会超出结尾。您可以考虑在r
循环之前声明j
;每当您使用键索引时,递增j(提示:r
);并用模运算符“包装” j(提示:j++
)。我将实际代码留给您。
答案 1 :(得分:1)
显示起来比解释容易得多:
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, char **argv)
{
if (argc != 2)
{
fprintf(stderr, "Usage: %s keyword\n", argv[0]);
return 1;
}
for (int i = 1; i < argc; i++)
{
for (int j = 0; argv[i][j] != '\0'; j++)
{
if (isalpha(argv[i][j]) == false)
{
fprintf(stderr, "%s: non-alphabetic character '%c' (%d) in key\n",
argv[0], argv[i][j], argv[i][j]);
return 1;
}
}
}
string pt = get_string("plaintext: ");
printf("ciphertext: ");
int k = 0;
int keylen = strlen(argv[1]);
for (int r = 0; pt[r] != '\0'; r++)
{
if (isupper(pt[r]))
{
int j = k++ % keylen;
int key = tolower(argv[1][j]) - 'a';
printf("%c", (pt[r] - 'A' + key) % 26 + 'A');
}
else if (islower(pt[r]))
{
int j = k++ % keylen;
int key = tolower(argv[1][j]) - 'a';
printf("%c", (pt[r] - 'a' + key) % 26 + 'a');
}
else
{
printf("%c", pt[r]);
}
}
printf("\n");
return 0;
}
示例运行:
$ ./vig89 baz
plaintext: Hello, World!
ciphertext: Iekmo, Vprke!
$
正如我在评论中指出的那样,您需要将“字符串位置r
”与“加密字符号”分开。您需要一个额外的变量,该变量仅在字符为字母时才递增。
在上面的代码中,k
是额外的变量(keylen
是另一个变量,但它只是记录密钥的长度,而不是重复调用strlen()
)。如果知道该字符是字母,则k
中的值将递增。
我注意到处理argv[1]
可能是明智的,这样您就不必每次都进行tolower()
转换;您可以在验证关键字的同时这样做。
我还报告了有关标准错误的错误,并且没有在循环的条件部分中使用strlen()
。尽管使用3个字母的键的代价并不高昂,但如果您开始计算每次迭代的字符串长度为20 KiB,那么您可能会发现开销(除非编译器设法对其进行优化) -可能会,也可能不会)。我还将I / O中的纯文本和密文对齐。
还有很多其他可能/应该进行的更改。例如,不需要第一个for (int i = 1; …)
循环;您只有一个参数,因此只需要内部for (int j = 0; …)
循环。使用if (!isalpha(argv[i][j]))
比将结果与false
进行比较也更惯用了,尤其是因为不能保证isalpha
宏返回0或1(它返回零或非零)。 –因此将if (isalpha(argv[i][j]) == false)
更改为if (isalpha(argv[i][j] != true)
是不可靠的。我可能会创建一个简单的变量char *key = argv[1];
(或者在CS50的背景下创建string key = argv[1];
,尽管我不认为CS50 typedef char *string;
是个好主意),并在程序。