所以我在第2周解决替代任务。我已经做了大部分的程序和它的工作原理;但是,它不能仅为一个加密密钥工作,即:-
DWUSXNPQKEGCZFJBTLYROHIAVM
check50中使用的所有其他键都给出了所需的输出,除了这个。
输入: -
The quick brown fox jumps over the lazy dog
和输出:-
Rqx tokug wljif nja eozby ohxl rqx cdzv sjp
我刚刚使用了debug50命令,看到字母'o'和'z'完全跳过了字母检查。下面是我的大部分代码:
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
bool check_validity(string key, int key_length);
string encrypt(string key, string input);
char key_char[26];
int main(int argc, string argv[])
{
int count = argc;
// Exit Status if key is not given.
if (count < 2 || count > 2)
{
printf("Usage: ./substitution keyn");
return 1;
}
string key = argv[1];
int key_length = strlen(key);
bool valid = check_validity(key, key_length);
// Exit Status if key is invalid.
if (valid == false)
{
return 1;
}
// transfering the key in an array.
for (int i = 0; i < 26; i++)
{
key_char[i] = tolower(key[i]);
}
string input = get_string("plaintext: ");
string output = encrypt(key, input);
printf("ciphertext: %sn", output);
}
// Check validity.
bool check_validity(string key, int key_length)
{
// this function is working perfectly fine so removed it
}
string encrypt(string key, string input)
{
string output = input;
int index;
for (int i = 0, n = strlen(input); i < n; i++)
{
// Check if the current char is an alphabet or not.
if ((key[i] >= 65 && key[i] <= 90) || (key[i] >= 97 && key[i] <= 122))
{
// Check if the current char is lowercase or uppercase.
if (islower(input[i]))
{
index = input[i] - 97;
output[i] = tolower(key_char[index]);
}
else if (isupper(input[i]))
{
index = input[i] - 65;
output[i] = toupper(key_char[index]);
}
}
}
return output;
}
在encrypt
函数中,for循环下的条件用于检查当前字符是否仅为字母,但对于'o'和'z',这只是被跳过,我不知道为什么。有人能解释一下吗?
主要问题在于条件:
if ((key[i] >= 65 && key[i] <= 90) || (key[i] >= 97 && key[i] <= 122))
既然您使用isupper()
和islower()
以及toupper()
和tolower()
函数(宏),那么也没有理由不使用isalpha()
。但是你索引的是键,而不是输入字符串。对于长消息(超过26个字符),您将在密钥字符串之外进行扫描。并且键中的所有字符都是字母—验证确保。
修复这个很容易:
if (isalpha(input[i]))
然后我被告知key
不在encrypt()
函数中使用,因为您使用key_char
进行索引,这是一个全局变量。这可以通过两种方式修复:
- 将
key
参数改为encrypt()
- 使
key_char
成为main()
的局部变量,并将其作为key传递给encrypt()
,然后将encrypt()
中对key_char
的引用更改为key
。
使用全局变量通常是要避免的,所以我选择了第二个选项。
还有一些其他的清理-在标准错误上报告错误,而不是标准输出,在使用消息中使用实际的程序名称,在main()
中使用更少的变量等。
令人费解的是,您使用<ctype.h>
中的函数/宏的随机组合,如isupper()
,islower()
,tolower()
,toupper()
(但不是isalpha()
)以及使用常数,如65
,90
,97
,122
。尽可能使用这些功能;使用'A'
和'a'
,而不是65
和97
。
使用if (count != 2)
比写出等价的if (count < 2 || count > 2)
更简单。以稍微不同的方式,您的循环for (int i = 0, n = strlen(input); i < n; i++)
可以更简单为for (int i = 0; input[i] != ' '; i++)
。
存在混淆的小风险,因为输入字符串和输出字符串实际上是相同的字符串,即输入字符串。它基本上是无害的,但你在加密过程中破坏了原始文件。
#include <assert.h>
的使用和check_validity()
中的断言(最好将其重命名为is_valid_key()
)确保了参数被使用,即使它是一个虚拟函数。这对于使用默认编译选项编译代码是必要的。我还对标准输入进行了代码循环,而不是在读取一行后停止。
#include <assert.h>
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
bool check_validity(string key, int key_length);
string encrypt(string key, string input);
int main(int argc, string argv[])
{
// Exit if key is not given or extra arguments are given
if (argc != 2)
{
fprintf(stderr, "Usage: %s keyn", argv[0]);
return 1;
}
string key = argv[1];
// Exit Status if key is invalid.
if (!check_validity(key, strlen(key)))
{
return 1;
}
// transfering the key in an array.
char key_char[26];
for (int i = 0; i < 26; i++)
{
key_char[i] = tolower(key[i]);
}
string input;
while ((input = get_string("plaintext: ")) != NULL)
{
string output = encrypt(key_char, input);
printf("ciphertext: %sn", output);
}
putchar('n');
return 0;
}
// Check validity.
bool check_validity(string key, int key_length)
{
// this function is working perfectly fine so removed it
// assert uses the otherwise unused arguments
assert(key != 0 && key_length >= 0);
return true;
}
string encrypt(string key, string input)
{
string output = input;
int index;
for (int i = 0; input[i] != ' '; i++)
{
// Check if the current char is an alphabet or not.
//if ((key[i] >= 65 && key[i] <= 90) || (key[i] >= 97 && key[i] <= 122))
if (isalpha(input[i]))
{
// Check if the current char is lowercase or uppercase.
if (islower(input[i]))
{
index = input[i] - 'a';
output[i] = tolower(key[index]);
}
else if (isupper(input[i]))
{
index = input[i] - 'A';
output[i] = toupper(key[index]);
}
}
}
return output;
}
示例输出
我的终端将echoctl
设置为回显控制字符,因此^D
。我叫程序sc97
signature
,部分是因为我有我自己的一个项目叫做signature
做不同的工作。
$ ./sc97 DWUSXNPQKEGCZFJBTLYROHIAVM
plaintext: The quick brown fox jumps over the lazy dog.
ciphertext: Rqx tokug wljif nja eozby jhxl rqx cdmv sjp.
plaintext: Pack my box with five dozen liquor jugs.
ciphertext: Bdug zv wja ikrq nkhx sjmxf cktojl eopy.
plaintext: The five boxing wizards jump quickly.
ciphertext: Rqx nkhx wjakfp ikmdlsy eozb tokugcv.
plaintext: How vexingly quick daft zebras jump.
ciphertext: Qji hxakfpcv tokug sdnr mxwldy eozb.
plaintext: Bright vixens jump; dozy fowl quack.
ciphertext: Wlkpqr hkaxfy eozb; sjmv njic todug.
plaintext: Glib jocks quiz nymph to vex dwarf.
ciphertext: Pckw ejugy tokm fvzbq rj hxa sidln.
plaintext: ^D
$./sc97 DWUSXNPQKEGCZFJBTLYROHIAVM Antwerp
Usage: ./sc97 key
$ ./sc97
Usage: ./sc97 key
$ signature -dspl < src/data-files/alphabetic-phrases
abcdefghijklmnopqrstuvwxyz The quick brown fox jumps over the lazy dog.
abcdefghijklmnopqrstuvwxyz Pack my box with five dozen liquor jugs.
abcdefghijklmnopqrstuvwxyz The five boxing wizards jump quickly.
abcdefghijklmnopqrstuvwxyz How vexingly quick daft zebras jump.
abcdefghijklmnopqrstuvwxyz Bright vixens jump; dozy fowl quack.
abcdefghijklmnopqrstuvwxyz Glib jocks quiz nymph to vex dwarf.
$