字符串中的大写字符不能转换为小写,减去它们的 ASCII 值不会使它们在字母索引中
Posted
技术标签:
【中文标题】字符串中的大写字符不能转换为小写,减去它们的 ASCII 值不会使它们在字母索引中【英文标题】:Uppercase characters in a string cannot be converted to lowercase and subtracting their ASCII value doesnt make them in alphabetical index 【发布时间】:2018-08-25 17:59:44 【问题描述】:我是一名尝试学习编码的初学者。 目前我正在上CS50课程。我遇到了 Vigenere 密码问题;请在下面的 github 链接上查看我的代码。
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define ASCII_VALUE_LOWER 97
#define ASCII_VALUE_UPPER 65
#define NR_OF_LETTERS 26
int main(int argc, string argv[])
char key[strlen(argv[1]) + 1];
strcpy(key, argv[1]);
int keyLen = strlen(key);
for (int k = 0; k < keyLen; k++)
if (!isalpha(key[k]))
printf("ERROR: Secret key has to be alphabetical string, program will be terminated now!\n");
return 1; // main should return 1 (signify an error)
//converting key letters to respective values
if (isupper(key[k]))
key[k] -= ASCII_VALUE_UPPER;
key[k] -= ASCII_VALUE_LOWER;
//if program is executed without an argument, or with more than one arguments
if (argc != 2)
printf("ERROR: You need to give a secret key as an argument, program will be terminated now!\n");
return 1; // main should return 1 (signify an error)
else
string plaintext = get_string("plaintext: "); //get a plaintext from a user using cs50 custom function from their library
int stringLen = strlen(plaintext);
int keyIndex = 0;
for (int j = 0; j < keyLen; j++)
//for each character in the plaintext string
for (int i = 0; i < stringLen; i++)
//check if is alphabetic (tolower, toupper)
if (isalpha(plaintext[i]))
//cypher_character = (plain_character + key_character)% 26
if (islower(plaintext[i]))
keyIndex %= keyLen;
plaintext[i] = ((plaintext[i] - ASCII_VALUE_LOWER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_LOWER;
else
plaintext[i] = ((plaintext[i] - ASCII_VALUE_UPPER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_UPPER;
keyIndex++;
//else leave as is
//print ciphertext in a format "ciphertext: " + ciper
printf("ciphertext: %s\n", plaintext);
return 0;
问题如下:
如果您在键中以大写字母形式传递参数,则值很奇怪并且转换不起作用。这个想法是在字符串键中获取每个字符,如果大写则减去 65,如果小写则减去 97,因此它们的 ASCII 值将变为 0 - 25。然后我可以在 Vigenere 密码公式中使用它们:cipher[i_index] = (plaintext[i_index] + key[j_index]) % 26
不处理缺少argv[1]
,即使有一个IF条件(!argc == 2)
,所以如果你什么都不通过,它不应该通过。
"failed to execute program due to segmentation fault".
我已经尽我所能尝试了一切,我很累,也许明天解决方案会立即弹出。 求你给我一些提示,可能不会透露全部,但可能会指导我,让我从中学习。
【问题讨论】:
你为什么不把所有的东西都改成大写然后减去65? 你试过调试你的程序吗? ...然后减去'A'
就是@RobertHarvey 的意思。
您的第二个问题出现是因为当您检查是否argc != 2
时,您已经访问了argv[1]
,因此假设argc >= 2
。如果调用者没有提供参数,则argv[1]
超出了数组的末尾,并且评估该表达式会导致未定义的行为。
@Joe Farrell,感谢您的提醒,这解决了问题!
【参考方案1】:
if (isupper(key[k]))
key[k] -= ASCII_VALUE_UPPER;
key[k] -= ASCII_VALUE_LOWER;
如果字符为大写,则减去ASCII_VALUE_UPPER
。然后,无论如何,它都会减去ASCII_VALUE_LOWER
。从周围的代码中,我假设您的意思是:
if (isupper(key[k]))
key[k] -= ASCII_VALUE_UPPER;
else
key[k] -= ASCII_VALUE_LOWER;
【讨论】:
谢谢!过去几个小时我一直在盯着它,试图找出问题出在哪里……遗憾的是,我对调试器的效率不是很高,所以我无法确定问题的根源。这使得程序功能更好,但仍然存在一些错误。例如,在单词 BaRFoo 上给出键 BaZ 会给出 CaQFon,但它应该是 CaQGon。如果我将 FFFfff 放在同一个键(BaZ)上,它会正常工作,给 GFEgfe。 使用printf()
,而不是与调试器斗争(这是一项重要的技能,但我们暂时把它放在一边)。在此过程中的每一步,打印出当前值是什么,并确保它们是您想要的。
好的,所以我按照你的建议做了,最后我找到了罪魁祸首。它在 if 条件内而不是在它之外放置的变量操作很糟糕。再次感谢您的帮助!【参考方案2】:
正如其他人所建议的那样,一切都已解决,如果有人好奇到底哪里出错了:
1.] @Rob Napier 指出的错误
for (int i = 0; i < stringLen; i++)
//check if is alphabetic (tolower, toupper)
if (isalpha(plaintext[i]))
keyIndex %= keyLen; // makes sure that keyIndex doesnt exceeds actual string length
//cypher_character = (plain_character + key_character)% 26
if (islower(plaintext[i]))
plaintext[i] = ((plaintext[i] - ASCII_VALUE_LOWER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_LOWER;
else
plaintext[i] = ((plaintext[i] - ASCII_VALUE_UPPER + key[keyIndex]) % NR_OF_LETTERS) + ASCII_VALUE_UPPER;
keyIndex++;
//else leave as is
keyIndex %= keyLen;被放置在它下方的 if 条件内,因此它不会在 FOR 循环的每次迭代中执行。
2.] @Joe Farrel 回答: 因为当我检查是否 argc != 2 时,我已经访问了 argv[1],因此假设 argc >= 2。如果调用者没有提供参数,那么 argv[1] 已经过了数组并评估该表达式会导致未定义的行为。 - 所以我首先将 if 条件移到 main 中。
【讨论】:
以上是关于字符串中的大写字符不能转换为小写,减去它们的 ASCII 值不会使它们在字母索引中的主要内容,如果未能解决你的问题,请参考以下文章