我为凯撒的密码写了一个密码,这个密码有效,除了我不能密码超过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-这个常量表达式在实际中解析为“环绕”。
... + keya... % ('z' - 'a' + 1)a% 26z`。

关于c - 想做凯撒的密码,但不能更改最后两个字符,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/57655966/

10-09 18:38