c - CS50 Vigenere, code is almost done but I don't know what's missing?
问题描述
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
int main(int argc, string argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
string plaintext = get_string();
printf("ciphertext: ");
string key = argv[1];
for (int i = 0, t = 0, n = strlen(plaintext); i < n; i++, t++)
{
// if it's no letter, then:
if (!isalpha(plaintext[i]) && plaintext[i] != ' ')
{
printf("False");
return 1;
}
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1;
}
if (strlen(key) > number)
{
number = 0;
}
if (isupper(plaintext[i]))
{
printf("%c", (((plaintext[i] - 65) + key[number]) % 26) + 65);
}
//if it is lowercase
else if (islower(plaintext[i]))
{
printf("%c", (((plaintext[i] - 97) + key[number]) % 26) + 97);
}
else
{
printf("%c", plaintext[i]);
}
}
printf("\n");
}
So there's something missing with my code. When I do ./vigenere baz
and then type as plaintext: Hello, world!
, I get ciphertext: ByffiFalse
. I should be getting iekmo, vprke!
Also, when I type ./vigenere hello
, and then type bye
as the plaintext, I get ciphertext bye
too while it should be icp
. Can someone figure out what's missing or wrong with my code?
解决方案
您的代码最大的两个问题是计算正确的密钥差异值(您不是)和密钥推进。我将按相反的顺序讨论它们。
键前进应该从第一个键字符开始,然后一个接一个地前进,处理每个纯文本。当关键位置到达字符串末尾时,它会重新启动。最基本的伪代码是
char *keyp = argv[1];
for (loop through plainttext)
{
if (*keyp == 0) // reached the terminator ?
keyp = argv[1]; // then reset to beginning.
//... process the current plain text character, using *keyp
//... as the next key character to use.
// advance key to next position (possibly conditionally)
++keyp;
}
但是您的代码没有这样做。相反,它会立即推进键,这意味着您从第二个字符开始。
int number = 0;
if (isalpha(plaintext[i]))
{
number += 1; // HERE. first pass will use key[1]. it should be key[0]
}
if (strlen(key) > number) // this is backward
{
number = 0;
}
其次,也许更重要的是,如果 Vigenere 密码有效地使用了方形着色表,那么这一点很重要。请参阅此链接以获取图片。您正在编码的算法的重点是使用数学来表现该表的存在。偏移量是重要的部分。当您进行此计算时:
(((plaintext[i] - 65) + key[number]) % 26) + 65
实际上应该是这样的:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
考虑添加关键字符的作用。举个例子:
key: baz
plaintext: Hello, World!
您计算的第一个密文字符将是:
((('H' - 'A') + 'a') % 26) + 'A'
注意:'a'
那里是因为你的第一次通过被打破了,记得吗?紧缩如下
(((7) + 97) % 26) + 'A'
((105) % 26) + 'A'
(1 % 26) + 'A'
1 + 'A'
'B'
这正是你得到的。但它错了。这是错误的,因为这是错误的:
(((plaintext[i] - 'A') + key[number]) % 26) + 'A'
^^^^^^^^^^^
那是输入字符的原始 ascii 值。它应该是 1..26 之间的计算值。简而言之,您没有正确调整按键输入。
假设解决方案
以下假设密钥始终为小写。它还修复了您的 first-skip 逻辑,并使用 cs50.h 解耦(坦率地说,我认为这弊大于利)。最后,它使用 `char* 来跟踪接下来使用哪个关键字符。我将支持混合大小写输入键的任务留给您:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
// two arguments
if (argc != 2)
{
printf("Give two arguments\n");
return 1;
}
printf("plaintext: ");
char pt[256] = { 0 };
if (fgets(pt, sizeof pt, stdin))
{
// get the plaintext length
size_t ptlen = strlen(pt);
// remove trailing newline if present, and adjust ptlen
if (ptlen > 0 && pt[ptlen - 1] == '\n')
pt[--ptlen] = 0;
// the key we're using. intially at the start
char *key = argv[1];
for (size_t i = 0; i < ptlen; ++i)
{
// reset key if prior iteration landed on terminator
if (!*key)
key = argv[1];
if (isalpha((unsigned char)pt[i]))
{
if (isupper((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'A') + (*key-'a')) % 26) + 'A');
++key;
}
//if it is lowercase
else if (islower((unsigned char)pt[i]))
{
printf("%c", (((pt[i] - 'a') + (*key-'a')) % 26) + 'a');
++key;
}
else
{
fputc(pt[i], stdout);
}
}
else
{
fputc(pt[i], stdout);
}
}
fputc('\n', stdout);
}
else
{
perror("Failed to read string");
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
输出自./progname baz
plaintext: Hello, World!
Iekmo, Vprke!
推荐阅读
- javascript - 使用选项卡正确显示表格
- python - 如何在 if elif 语句中递减
- reactjs - 如何在 React Js 的 Material UI Table Component 中按“DateAdded”对表格进行排序?
- sql - Postgres 从 JSONB 更新 INTEGER 列
- c# - SessionState.SessionStateItemCollection.get_Item(Int32) 处的 IIS 工作进程 NullReferenceException
- python - Python:使用 re.substitute 代替模板时保持行格式(断线)
- amazon-web-services - 审核 AWS CloudWatch 和 SNS 通知
- python - 关于从n个元素中找出m个元素的所有组合的算法分析问题
- python - 如何在 Pytorch 中保存灰度图像?
- httpwebrequest - 为什么证书在使用 .NET Core 2 时为空,但在 .NET Framework 4.6.2 中运行良好?