我为凯撒的密码写了一个密码,这个密码有效,除了我不能密码超过8个字母,我也不能处理空格。它显示“>>”这个符号而不是空格。另外,我想在代码的第二个函数中进行二进制搜索,但我不知道我是否做过。
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char caesar (char x, char alphabets[]);
int j;
int main()
{
char* plain_text = malloc (10 * sizeof(char) + 1);
int key, num;
char* cipher_text = malloc (10 * sizeof(char) + 1);
printf("Plain text: ");
gets(plain_text);
printf("\nThe plain text is: ");
puts(plain_text);
printf("\nKey: ");
scanf("%d", &key);
num = (int)key;
if (key != num)
{
return 1;
}
int i;
char alphabets[] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z'};
for (i=0;i<=strlen(plain_text);i++)
{
char x = plain_text[i];
caesar(x, alphabets);
cipher_text[i] = alphabets[j+key];
printf("%c", cipher_text[i]);
}
free(plain_text);
}
char caesar (char x, char alphabets[])
{
if(x == alphabets[13])
{
return 13;
}
for(j = 1; j <= 13; j++)
{
if(x == alphabets[j])
{
return j;
}
}
for(j = 13; j <= strlen (alphabets); j++)
{
if(x == alphabets[j])
{
return j;
}
}
}
最佳答案
caesar()
似乎只是以一种非常复杂的方式返回数组中字符b到z的位置,而完全忽略了a!此外,因为alphabets
不是以空结尾的字符串strlen()
在任何情况下都不是有效的操作。“加密”是由alphabets[j+key]
中的main()
完成的(不正确),使得caesar()
的命名特别糟糕,因为这根本不是它所做的。
以下函数将返回alphabet
中任何字符的密码,并保留任何其他字符不变:
char caesar( char x, int key )
{
const char alphabet[] = {'a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x',
'y','z'};
char cipher = x ;
for( int i = 0;
cipher == x && i < sizeof( alphabet );
i++ )
{
if( alphabet[i] == x )
{
cipher = alphabet[(i + key) % sizeof( alphabet )] ;
}
}
return cipher ;
}
将
key
传递到ceasar()
比传递常量alphabet
更有意义,并且在alphabet
是“已知”的地方执行加密。正如您所做的那样,在caesar()
和main()
之间分割密码步骤是一个糟糕的设计,缺乏内聚性,并且具有不必要的耦合。如果字符
x
出现在alphabet
中,它将被alphabet[(i + key) % sizeof( alphabet )] ;
修改。这就添加了原来的key
,但也添加了“环绕”(模运算),因此例如,对于%
,key = 1
环绕到z
,而不是像代码一样引用a
数组末尾以外的一个字节。关键的是,如果它没有出现在alphabet
中,它是未修改的-这就是为什么alphabet
是用cipher
初始化的。当x
被修改时(cipher
),或者当cipher != x
结束时,循环退出。然后在
alphabet
的迭代中:for (i = 0; i <= strlen(plain_text); i++ )
{
cipher_text[i] = caesar( plain_text[i], key ) ;
}
这里的
plain_text
是不寻常的,但是这里它确保了nul终结符被复制到<= strlen()
-它不会被cipher_text
修改。请注意,上面的解决方案只加密小写文本(与原始代码一样)。在您的代码中还有其他问题和不明智的实践,在注释中讨论过,但可能与您的问题没有直接关系,但是使用上述函数,以下完整的实现解决了大多数问题:
#include <stdio.h>
#include <string.h>
char caesar( char x, int key ) ;
#define MAX_TEXT 128
int main()
{
char plain_text[MAX_TEXT] = "" ;
char cipher_text[MAX_TEXT] = "" ;
printf( "Plain text: " );
fgets( plain_text, MAX_TEXT, stdin ) ;
printf( "\nThe plain text is: %s\n", plain_text ) ;
printf( "Key: " ) ;
int key = 0 ;
scanf( "%d", &key );
for( size_t i = 0; i <= strlen( plain_text ); i++ )
{
cipher_text[i] = caesar( plain_text[i], key ) ;
}
printf( "\nThe cipher text is: %s\n", cipher_text ) ;
return 0 ;
}
例子:
Plain text: abc, xyz
The plain text is: abc, xyz
Key: 1
The cipher text is: bcd, yza
允许大写字母的修改:
#include <ctype.h>
char caesar( char x, int key )
{
const char alphabet[] = {'a','b','c','d','e','f','g','h',
'i','j','k','l','m','n','o','p',
'q','r','s','t','u','v','w','x',
'y','z'};
char cipher = x ;
for( int i = 0;
cipher == x && i < sizeof( alphabet );
i++ )
{
if( alphabet[i] == tolower( x ) )
{
cipher = alphabet[(i + key) % sizeof( alphabet )] ;
if( isupper( x ) )
{
cipher = toupper( cipher ) ;
}
}
}
return cipher ;
}
在这里,测试忽略了大小写,然后当匹配失败时,如果
caesar()
是大写,则应用alphabet[i] == tolower( x )
生成大写密码。示例输出:
Plain text: aBc, XyZ 123
The plain text is: aBc, XyZ 123
Key: 1
The cipher text is: bCd, YzA 123
注意,不是在for循环中测试
cipher = toupper( cipher )
,而是在循环中分配x
之后可以cipher = x
-减少测试的数量-但是arguably breaks structured programming“规则”-我不会批评其他人使用它,但这不是我的偏好。在这种情况下,您还可以使用break
来完全跳过循环,但它具有针对重音字符的实现定义的行为,例如,如果您要扩展支持的“字母表”,它可能无法按预期工作。如果您只使用字母表中的字符a到z,则可以进一步简化,其中可以使用字符代码值算术确定密码:
char caesar( char x, int key )
{
char cipher = tolower( x ) ;
if( isalpha( x ) )
{
cipher = ((cipher - 'a') + key) % ('z' - 'a' + 1) + 'a' ;
if( isupper( x ) )
{
cipher = toupper( cipher ) ;
}
}
return cipher ;
}
严格地说,这假设字符a到z在目标字符集中是连续的,但对于任何可能在其上运行此代码的系统(即,不是IBM z系列大型机或各种仿古大型机/小型计算机),这是普遍的,如果不是,则
cipher
阵列解决方案仍然有效。我指出这一点仅仅是因为,否则有人会对它发表评论,好像它真的是一个问题。要解释表达式:
isalpha(x)
:alphabet
-减去“a”的代码,得到字符cipher = ((cipher - 'a') + key) % ('z' - 'a' + 1) + 'a'
到(cipher - 'a')
的值0到25。a
-添加“shift”键z
-这个常量表达式在实际中解析为“环绕”。... + key
a... % ('z' - 'a' + 1)
a% 26
z`。关于c - 想做凯撒的密码,但不能更改最后两个字符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57655966/