【问题标题】:ASCII ROT13 cipher results in incorrect charactersASCII ROT13 密码导致不正确的字符
【发布时间】:2021-11-01 02:46:08
【问题描述】:

我一直在努力学习 C,并决定做一个加密项目。我想对该项目使用 ROT 13 加密,但我遇到了一个错误。该代码应该检查索引位置words[i] 处的字符的值并比较其值。如果它在 97-122 的范围内 ('a' - 'z'),请运行代码并添加加密。然而,我了解到,当我想替换像“z”这样的字母并将其移动 6 个位置时,它不起作用。将其移动 5 个位置确实有效。请看下面的代码:

#include <stdio.h>
#include <string.h>

int main(){
    char words[25]= "ABC MNO XYZ";

    printf("%s \n", words);
    printf("size of 'words' is %d \n", strlen(words));

    int size_t = strlen(words);

    for (int i=0; i < size_t; i++){
        printf("%c \n", words[i]);
    }

    printf("unencrypted ends here... \n\nStarts the cipher\n");

    //converts array to lowercase for ascii purposes
    for (int i=0; i < size_t; i++){
        words[i]= tolower(words[i]);
    }

    for (int i=0; i < size_t; i++)
    {
        char res = 'z';
        if(words[i]>=97 && words[i]<=122)
        {
            words[i] = words[i]+6;
            while(words[i] > 122)
            {
                res = words[i]-res;
                printf("The value of res is: %d\n", res);
                words[i]=96;
                words[i]= words[i]+res;
            }
        }

        //'res' ascii value equals 122
        //if words[i] is more than 122 (z), subtract 122 from it and store it in res
        //restart words[i] at position before 'a', then add res
        //not sure why but after 122 + 6 or more positions, does not reset to a char before 'a'
        //gives those weird chars at 128+ ascii locations

        printf("%c \n", words[i]);
    }

    return 0;
}

【问题讨论】:

  • 你不应该真的使用size_t作为变量名,它是标准库中变量类型的名称
  • 从这封信中减去'a'。加13(对于rot13),如果结果>=26,再减26。再加'a'得到最终结果。

标签: c encryption ascii rot13


【解决方案1】:

@user3386109 已经评论了您的问题的解决方案:

从字母中减去“a”。加 13(对于 rot13),然后减去 26 如果结果 >= 26。则添加 'a' 得到最终结果。

但这里解释了为什么将 5 添加到 words[i] 有效而 6 无效:

将 5 添加到 words[i] 有效但添加 6 无效的主要原因是因为在您的情况下,char 已签名(范围 -128 到 127),因此如果 words[i]char)等于122,加6(128)超出signed char的范围。

由于words[i] 永远不会是负数,请尝试使用unsigned char 而不是char

最后但并非最不重要的一点,size_t 是 C 中的一种数据类型,尽量避免将其用作变量名。

【讨论】:

    【解决方案2】:

    问题是char 可能的范围是 [-128, 127],这就是为什么添加 5 有效,但添加 6 会导致超出范围的分配。一种解决方案是首先将 char 转换为更大的类型,例如 int,但还有更好的方法:

    for (int i=0; i < size_t; i++)
    {
        if (islower(words[i]))
            words[i] = (words[i] - 'a' + 13) % 26 + 'a';
    
        printf("%c \n", words[i]);
    }
    

    这将获取字符,使其成为 0 到 25 之间的值,应用移位,获取余数来处理字母表的环绕,最后再次添加 'a' 以将值转换回 ASCII 'a''z' 范围。
    这仍然会将char 隐式转换为int 类型,因为'a'13ints,但现在我们不再需要if 语句,它清楚地表明我们正在使用取模值26.

    有关char 范围和促销类型的更多信息,请参阅here。请注意,将超出范围的值分配给有符号整数实际上是实现定义的行为

    一些额外的建议

    • main 的典型签名(不使用参数)是 int main(void)
    • 要使用tolower,请包含ctype.h 标头。
    • 不要使用名为size_t 的标识符。这是 C 中使用的一种类型,在 many commonly used headers 中是 typedef'd。
    • 使用'a''z' 使代码比使用97122 更容易理解。要检查 char 是否为小写,请使用 islower
    • strlen 函数返回size_t 类型的值。正确的格式说明符不是%d,而是%zu

    【讨论】:

      猜你喜欢
      • 2013-04-10
      • 2016-06-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多