为何加密第二个单词后代码插入3个空格?附代码求排查
问题分析与修复方案
嘿,我帮你定位到问题根源了——你的代码里嵌套循环的逻辑完全违背了Vigenère密码的设计思路,这直接导致了空格重复输出、加密偏移混乱的问题。咱们一步步拆解问题,再给出修复方案:
你的代码核心问题
- 双重循环导致非字母字符重复输出:你用外层循环遍历明文,内层循环遍历密钥。这意味着每个非字母字符(比如空格)会被输出密钥长度次——比如你的密钥是
abcde(长度5),空格就会被打印5次,这就是你看到多个空格的原因。 - 明文索引被随意修改:在内层循环里你手动执行
k++,这会让外层的for循环索引彻底混乱,导致明文被跳着处理,加密结果完全错误。 - 密钥循环逻辑搞反:Vigenère密码需要循环用密钥的每个字母对应明文的每个字母(非字母不消耗密钥位),但你的代码是把整个密钥套用到每个明文字符上,完全搞反了对应关系。
修复后的完整代码
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> int main(int argc, string argv[]) { // 先校验命令行参数合法性 if (argc != 2) { printf("You didn't submit a valid encryption key.\n"); printf("Please check your input and re-run the program.\n"); printf("We require a keyword (letters only) as encryption key.\n"); return 1; } string keyword = argv[1]; // 额外检查密钥是否全为字母(Vigenère密码的密钥应为纯字母) for (int i = 0; i < strlen(keyword); i++) { if (!isalpha(keyword[i])) { printf("Keyword must contain only letters!\n"); return 1; } } string plain = get_string("plaintext: "); printf("ciphertext: "); int key_len = strlen(keyword); int key_idx = 0; // 跟踪当前使用的密钥位置 for (int k = 0; k < strlen(plain); k++) { char c = plain[k]; if (isalpha(c)) { // 计算密钥偏移:统一转小写后得到0-25的偏移值 int shift = tolower(keyword[key_idx]) - 'a'; key_idx = (key_idx + 1) % key_len; // 密钥索引循环复用 if (isupper(c)) { printf("%c", ((c - 'A' + shift) % 26) + 'A'); } else { printf("%c", ((c - 'a' + shift) % 26) + 'a'); } } else { // 非字母直接输出,不消耗密钥位 printf("%c", c); } } printf("\n"); // 最后加换行,输出更规范 return 0; }
修复细节说明
- 移除错误的嵌套循环:改用单个循环遍历明文,用
key_idx变量跟踪当前使用的密钥位置,逻辑更清晰。 - 正确实现密钥循环:只有处理明文的字母字符时,才移动
key_idx,通过(key_idx + 1) % key_len实现密钥的循环复用,完全符合你预期的偏移逻辑。 - 修正参数与合法性检查:
- 把
main函数的参数修正为标准的string argv[](你原来的argv[1]写法不标准)。 - 增加了密钥纯字母的检查(Vigenère密码的密钥应为字母,而非整数,你原来的提示文本也有误,已修正)。
- 把
- 优化代码可读性:用
'A'和'a'代替硬编码的ASCII值65、97,去掉了冗余的do-while循环(参数检查不需要循环,不符合直接退出即可)。
现在测试你给出的例子:
- 明文:
Meet me at the Park - 密钥:
abcde
每个字母会对应正确的偏移量,空格只会输出一次,完全符合你预期的逻辑。
内容的提问来源于stack exchange,提问作者jstrnbrg
相关产品推荐
相关产品推荐

