CS50替换密码问题:tolower未将第二个A转换为小写
CS50替换密码:小写字母未正确转换的问题修复
问题现象
- 密钥:
NQXPOMAFTRHLZGECYJIUWSKDVB - 输入明文:
Armando - 实际输出密文:
NjzNgpe - 期望输出密文:
Njzngpe
问题出在第四个小写字母a被转换为大写N,未按要求转为小写n。
代码中的核心问题
空数组的未定义行为
- 你定义的
cypher[] = {}和new[] = {}是空数组,长度为0。后续对cypher[i]和new[i]的赋值都是越界内存访问,会导致数据混乱、内存错误,这是出现异常的根本原因之一。 cypher应该是长度26的字符数组(对应26个字母的密钥),new需要足够容纳输入的明文。
- 你定义的
字符匹配逻辑错误
scramble函数的内层循环中,无论是否匹配到目标字符,position都会被递增多次。比如处理第一个字符A时,匹配成功后position++,但内层循环会继续执行,position会被持续递增到26,后续字符的匹配逻辑完全错乱。- 没必要循环遍历
alpha数组找位置,直接通过字符ASCII值计算位置更高效且准确。
变量类型错误
cypher被定义为int类型数组,但存储的是字符,应该改为char类型。
修复后的代码
#include <cs50.h> #include <stdio.h> #include <string.h> #include <ctype.h> // 定义26个大写字母的数组 char alpha[] = {'A','B','C','D','E','F','G','H','I','J','K','L','M', 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z'}; // 密钥数组,固定长度26 char cypher[26]; // 密文数组,定义足够大的空间(可根据实际需求调整) char new[100]; void cypher_s(string k); void scramble(string s); int main(int argc, string argv[]) { if (argc == 2 && strlen(argv[1]) == 26) { string key = argv[1]; cypher_s(key); string text = get_string("plaintext: "); scramble(text); } else { printf("错误:请输入一个长度为26的密钥作为命令行参数\n"); return 1; } } void cypher_s(string k) { // 将密钥字符复制到cypher数组 for (int i = 0; i < 26; i++) { // 统一转为大写存储,避免密钥大小写干扰 cypher[i] = toupper(k[i]); } } void scramble(string s) { int len = strlen(s); for (int i = 0; i < len; i++) { if (isupper(s[i])) { // 计算大写字母在字母表中的位置 int pos = s[i] - 'A'; new[i] = cypher[pos]; } else if (islower(s[i])) { // 计算小写字母在字母表中的位置 int pos = s[i] - 'a'; // 将密钥对应字符转为小写 new[i] = tolower(cypher[pos]); } else { // 非字母字符直接保留 new[i] = s[i]; } } // 添加字符串结束符 new[len] = '\0'; printf("ciphertext: %s\n", new); }
修复说明
- 修正了数组初始化问题,为
cypher和new分配了足够的内存空间。 - 移除了低效且易出错的内层匹配循环,改用ASCII值直接计算字符位置,逻辑更清晰。
- 增加了密钥长度检查(必须26位),避免非法输入。
- 统一将密钥转为大写存储,确保大小写输入的密钥都能正常工作。
- 处理非字母字符时直接保留,增强鲁棒性。
内容的提问来源于stack exchange,提问作者Mamushi
相关产品推荐
相关产品推荐

