【问题标题】:Caesar Cipher: Correct encryption but output missing spaces and punctuations凯撒密码:正确加密但输出缺少空格和标点符号
【发布时间】:2014-06-04 12:39:40
【问题描述】:

我从昨天开始一直在努力,经过一番努力,我成功地加密了消息。但是,我的输出缺少空格。

据我了解,发生这种情况的原因是因为我正在使用 isalpha()、isupper() 和 islower() 命令,因此忽略了原始输入中的空格。

能否请教我如何保留原来的空格和标点符号?

以下是我的代码 - 它远非优雅,任何风格的 cmet 也将受到赞赏!

(另外,虽然有很多关于 Caesar Cipher 的问题,但没有一个可以解决这个问题。由于这是我编程的第一周,我很难理解其中的语法。)

我的算法中有一个明显的错误,如果给定某些参数,它会导致输出错误的值。例如,k 为 13,输入第 13 个字母(我认为是 m)之后的任何内容都会输出一些非常奇怪的内容。 我会修改这个并很快回来!在那之前,对我的代码持保留态度!

# include <cs50.h> 
# include <stdio.h> 
# include <stdlib.h>
# include <string.h>
# include <ctype.h>


int main(int argc, string argv[])

{
    if (argc != 2)
    {
        printf("Please enter a valid number of arguments! \n");
        return 1;
    }

    string num = argv[1];
    int k = atoi(num);

        if (k < 0)
            {
                printf("Please enter a valid number! \n");
                return 1;
            }

    printf("Please type the message which needs to be encrypted: ");
    string p = GetString();

        for (int i = 0, n = strlen(p); i < n; i++)
        {
            int oldletter = p[i];
            int result1 = (oldletter + k);
            int result2 = (oldletter - 65 + k);
            int result3 = (result2) % 26;
            int result4 = (oldletter - 97 + k);
            int result5 = (result4) % 26;

                if (isalpha(p[i]) && isupper(p[i]) && k < 26)
                {
                    printf("%c", result1);
                }

                if (isalpha(p[i]) && isupper(p[i]) && k >= 26) 
                {
                    int result7 = (result3 + oldletter); 
                    printf("%c", result7);
                }


                if (isalpha(p[i]) && islower(p[i]) && k < 26)
                {
                    printf("%c", result1);
                }

                if (isalpha(p[i]) && islower(p[i]) && k >= 26)
                {
                    int result8 = (result5 + oldletter); 
                    printf("%c", result8);
                }

        }
        printf("\n");
}

更正代码,正常工作:SPOILERS AHEAD

# include <cs50.h> 
# include <stdio.h> 
# include <stdlib.h>
# include <string.h>
# include <ctype.h>

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Please enter a valid number of arguments! \n");
        return 1;
    }

    string num = argv[1];
    int k = atoi(num);

    if (k < 0)
        {
            printf("Please enter a valid number! \n");
            return 1;
        }

    printf("Message: ");
    string p = GetString();

        for (int i = 0, n = strlen(p); i < n; i++)
        {
            int oldletter = p[i];
            int result1 = (oldletter - 65 + k);
            int result2 = (result1) % 26;
            int result3 = (oldletter - 97 + k);
            int result4 = (result3) % 26;


                if (isalpha(p[i]) && isupper(p[i])) 
                {
                    int result5 = (result2 + 65); 
                    printf("%c", result5);
                }


                else if (isalpha(p[i]) && islower(p[i]))
                {
                    int result6 = (result4 + 97); 
                    printf("%c", result6);
                }

                else 
                {
                    printf("%c", p[i]);
                }

        }
        printf("\n");
}

【问题讨论】:

  • 这真的是 C 吗? C 中没有 string 类型,您正在使用 C++ 编程。
  • @unwind 这实际上是 C,我自己采用了哈佛 CS50 的在线版本,他们在课程的第一部分将定义字符串类型为 char *,使其更“简单”并且不要让学生对星号和指针感到好奇。
  • 注意:不需要isalpha(p[i])isupper(p[i])islower(p[i])。 “isalpha 函数测试任何 isupper 或 islower 为真的字符,......” §7.4.1.2
  • @chux 这是课程工作人员的决定,我只是想提供一些信息,即它实际上是 C 代码。至于未定义的行为,您可以在一个预先配置和修改过的 32 位 fedora 版本的虚拟机中进行所有编程,并使用相同的编译器。因此,工作人员对实际实施有一些断言。测试输入全是0-127 ascii 范围,所以肯定在unsigned char 范围内。
  • @chux 至于支持工作人员做出的“简化”决定,这取决于每个人是否同意。我只想指出,这实际上只是他们参加的第一门介绍课程,他们在课程开始几周后就带走了字符串的魔力并谈论指针。

标签: c encryption cs50 caesar-cipher


【解决方案1】:

当人们实现这一点时,我看到的一个常见缺陷是直接使用 ascii 值。考虑做一个字母数组,你可以得到你当前字母在其中的位置,然后确定修改后的字母应该是什么。

想象一下,使用 ascii 解决方案为此添加一个 '%' 字符,你最终会得到大量特殊的 if。如果您愿意,您可以在这种情况下选择忽略空格/等,我个人会将它们添加到字母数组中,这样密文就不会显示空格(给出提示)。

【讨论】:

  • 这是个好主意。然后,您可以使用(current_index +/- shift)%26 轻松根据需要更改索引。
【解决方案2】:

您可能应该将ifelse if 链接在一起,如果在您的情况下前一个条件已经为真,则无需评估 if 条件。这也将允许在 isalphafalse 时执行最终的 else 情况,就像在有空格的情况下一样。

只需将 if 条件更改为:

if (isalpha(p[i]) && isupper(p[i]) && k < 26)
{
    printf("%c", result1);
}

else if (isalpha(p[i]) && isupper(p[i]) && k >= 26) 
{
    int result7 = (result3 + oldletter); 
    printf("%c", result7);
}


else if (isalpha(p[i]) && islower(p[i]) && k < 26)
{
    printf("%c", result1);
}

else if (isalpha(p[i]) && islower(p[i]) && k >= 26)
{
    int result8 = (result5 + oldletter); 
    printf("%c", result8);
}

else
{
    printf("%c", p[i]);
}

我想指出,您的逻辑非常复杂,您还应该选择比您当前使用的 result* 变量更好的名称,在编程可读性和可维护性方面非常重要。由于您在那里编写的小程序,您可以轻松完成作业而无需考虑它们,但这是一个好习惯。

我还参加了这门课程(之前有 C 经验)并上传了我的最终解决方案,供您在完成后进行比较/改进。只是一个警告,我使用了一个函数,不确定在这个问题集之前是否已经解释过,但至少应该在不久之后解释一下。这是我的解决方案:http://pastebin.com/vJqPY6Ne

【讨论】:

  • 非常感谢!这很有帮助! :)
  • @boametaphysica 我在最后添加了一小部分关于可读性和我对这个问题的解决方案,以便在你完成后与改进进行比较。此外,由于您更新了遇到逻辑问题的问题,您可能应该自己确定问题并尝试解决它(仅在出于学习考虑遇到特定问题时才提出问题)。
  • 我已经完成了我的版本,刚刚浏览了你的代码。你的代码绝对比我的优雅得多。我很想使用这些功能。教授确实在本周问题集的第一堂课中介绍了它,但没有深入研究它,因为主要关注的是数组和循环。再次感谢!
猜你喜欢
  • 1970-01-01
  • 2014-03-07
  • 2013-03-13
  • 1970-01-01
  • 1970-01-01
  • 2014-04-11
  • 2016-08-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多