【问题标题】:Cs50 Vigenere code gives unexpected output when using the proper ASCII Values使用正确的 ASCII 值时,Cs50 Vigenere 代码给出了意外的输出
【发布时间】:2018-09-11 04:52:03
【问题描述】:

我已经为 cs50 中的 Vigenere 问题编写了这段代码。 但是,当我打印使用 58 和 90 而不是 65 和 97 的加密字母时,它并没有按预期工作。(A 和 a 的 ASCII 值)

这样做会给我想要的结果,但我不明白为什么会这样。减去“a”或“A”时,它给了我错误的加密文本,这对我来说没有任何意义。

我查找了一些不同的解决方案,它们都用 'a' 或 'A' 减去以获得字母索引,但是这样做对我不起作用。

我真的不明白为什么我必须在我的代码中使用这些值也许任何人都可以帮助我了解哪里出了问题或我的逻辑错误在哪里。

提前致谢。

编辑:我改变了

k[z] = tolow(k[z]); to k[z] = toupper(k[z] - 'A');

我也变了

printf("%c",(((p[j]- 58) + k[l % strlen(k)]) % 26) + 'A'); to printf("%c",(((p[j]- 'A' -6) + k[l % strlen(k)]) % 26) + 'A');

-6 是因为这给了我正确的输出,这意味着某些东西仍然关闭

关键:培根

明文:上午十一点在公园见我

预期输出:Negh zf av huf pcfx bt gzrwep oz

-6 的实际输出:Negh zf av huf pcfx bt gzrwep oz

没有-6的实际输出:Tkmn fl gb nal vild hz mfxckv uf

不知何故,所有值都偏离了 -6,我不知道为什么

k.size() 也给了我错误,所以我保留了 strlen()。

int main(int argc,string argv[])
{

//checks if only one argument was typed
if (argc != 2)
{
    printf("Error");
    return 1;
}

//assigns the keyword argv[1] to k
string k = argv[argc -1];
//check if key is alphabetical only
for (int i = 0 , n = strlen(k); i < n; i++)
{
    if(!isalpha(k[i]))
    {
        printf("Key is not alphabetical");
        return 1;
    }
}
printf("Key Valid\n");
//convert key to lowercase only
for(int z = 0; k[z]; z++)
{
    k[z] = tolower(k[z]);
}

string p = get_string("Plaintext: ");
//iterate over p
//l is incremented only when the char is alphabetical and is used as index for k
for (int j = 0,l = 0 , o = strlen(p);j < o ;j++)
{

    if(isalpha(p[j]))
    {
        if(isupper(p[j]))
        {
            //print enciphered letter
            printf("%c",(((p[j]- 58) + k[l % strlen(k)]) % 26) + 'A');
        }
        else if(islower(p[j]))
        {
            //print enciphered letter
            printf("%c",(((p[j]- 90) + k[l % strlen(k)]) % 26 ) + 'a');
        }
        //increment so that next char in k is used
        l++;
    }
    else
    {
        //print unchanged
        printf("%c",p[j]);
    }
}

return 0;
}

【问题讨论】:

  • 如果你转换输入键toupper而不是tolower会发生什么?大写在历史上是一种默认设置(旧的 FORTRAN 代码全部大写),因此字母通常被规范化为大写而不是小写。但是对于字母 A,key 实际上应该具有值 0,因此转换实际上应该是 toupper(k[z]) - 'A',然后应该不涉及任何魔术常量。
  • get_string 函数是什么?你的输入是什么?你的预期输出是什么?你的实际输出是多少?
  • 继续我的第一条评论,如果你使用- 'A' 部分那么你不能使用strlen(k) 并且必须使用k.size(),因为值零可以是字符串的一部分并且strlen 认为值零作为字符串终止符,但 string::size() 没有。
  • 我改变了 k[z] = tolower(k[z]);到 k[z] = toupper(k[z] - 'A');我也改变了 printf("%c",(((p[j]- 58) + k[l % strlen(k)]) % 26) + 'A');到 printf("%c",(((p[j]- 'A' -6) + k[l % strlen(k)]) % 26) + 'A'); -6 是因为这给了我正确的输出,这意味着有些东西仍然关闭我将在描述中指定输入和输出
  • 另外@RetiredNinja get_string 函数会提示用户输入一个字符串,我认为cs50在2018年新课程中用get_string()“替换”了GetString()。正如我所说,我现在在描述中指定了所有输出和输入

标签: c ascii cs50 vigenere


【解决方案1】:

所以代码的问题是密钥没有正确规范化。而不是字母“A”表示键中的值0,而是表示值97。使用您的示例,我们应该将“b”的键值应用于字母“M”以达到编码字母“N”。由于'b'不是1而是98,我们必须通过减去97来抵消它。但是由于我们在最后加上'A',我们也必须通过减去65来抵消它。复合减法是97 + 65 = 162 ,其模数是 162 mod 26 = 6。所以你可以减去 6 而不是减去 58。结果是一样的,因为 58 mod 26 也是 6,所以使用 58 而不是 6 可以获得相同的结果。

下一个案例处理小写字母,因此复合减法是 97 + 97 = 194,以及 194 mod 26 = 12。但 90 mod 26 = 12 也是如此,因此使用 90 而不是 12 可以获得所需的结果。

为避免键 (97) 所需的偏移量,您可以使用正确的值(字母“A”的值 0)构建键。但是您必须在构建密钥之前存储密钥长度,因为函数strlen 将在值 0(前一个字母“A”)处停止计数。之后,在对字母进行编码时,大小写(65 和 97)仍然存在偏移,但它们的值至少不那么令人困惑。

【讨论】:

  • 非常感谢我投了赞成票,但我的排名/级别还不够高,无法显示。非常感谢您帮助我了解哪里出了问题以及为什么:D
最近更新 更多