CS50替换密码作业:密钥重复字符检测超时问题修复咨询
CS50 Problem Set 2 Substitution密码:密钥重复字符检测超时问题修复
原代码在检测密钥重复字符时无法通过测试,报错信息为:
:( Handles duplicate characters in Key - timed out while waiting for program to exit
问题根源分析
- 非法修改只读内存:原代码中
string k = argv[1];直接指向命令行参数的只读内存区域,后续执行k[i] = tolower(k[i]);属于未定义行为,可能导致程序崩溃或进入死循环,最终引发超时。 - 重复检测逻辑漏洞:仅将
k[i]转为小写,但未处理k[j]的大小写,导致大小写不同的重复字符(如'a'和'A')无法被检测到。
修复后的代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> int main(int argc, string argv[]) { // 检查命令行参数数量是否正确 if (argc != 2) { printf("Usage: ./substitution key\n"); printf("(请仅输入2个命令行参数)\n"); return 1; } int key_len = strlen(argv[1]); // 创建可修改的密钥副本,避免操作只读内存 char key[27]; strcpy(key, argv[1]); // 检查密钥长度是否为26位 if (key_len != 26) { printf("Usage: ./substitution key\n"); printf("密钥必须是26个字符\n"); return 1; } // 校验密钥是否全为字母,并统一转为小写 for (int i = 0; i < 26; i++) { if (!isalpha(key[i])) { printf("Usage: ./substitution key\n"); printf("密钥必须全为字母\n"); return 1; } key[i] = tolower(key[i]); } // 检测密钥中的重复字符 for (int i = 0; i < 26; i++) { for (int j = i + 1; j < 26; j++) { if (key[i] == key[j]) { printf("Usage: ./substitution key\n"); printf("密钥不能包含重复字符\n"); return 1; } } } // 获取明文并执行加密 string plaintext = get_string("Plaintext: "); int text_len = strlen(plaintext); printf("ciphertext: "); for (int i = 0; i < text_len; i++) { if (isalpha(plaintext[i])) { if (isupper(plaintext[i])) { int idx = plaintext[i] - 'A'; printf("%c", toupper(key[idx])); } else { int idx = plaintext[i] - 'a'; printf("%c", key[idx]); } } else { printf("%c", plaintext[i]); } } printf("\n"); return 0; }
关键修改点
- 创建密钥副本:使用
char key[27];创建可修改的本地数组存储密钥,避免直接操作只读的命令行参数内存。 - 统一大小写处理:先将整个密钥转为小写,确保重复检测不受字符大小写影响。
- 优化重复检测逻辑:基于统一大小写后的密钥进行检测,确保所有重复字符(包括大小写形式不同的)都能被识别。
- 冗余代码清理:删除了未实际使用的
malloc申请的ciphertext变量,简化代码逻辑。
内容的提问来源于stack exchange,提问作者Potential_Lettuce
相关产品推荐
相关产品推荐

