CS50 Caesar程序处理非数字密钥超时问题修复求助
修复Caesar密码程序的非数字密钥超时问题
我是CS50新手,正在完成Caesar密码作业。当前程序测试反馈如下:
- ✅ caesar.c exists.
- ✅ caesar.c compiles.
- ✅ encrypts "a" as "b" using 1 as key
- ✅ encrypts "barfoo" as "yxocll" using 23 as key
- ✅ encrypts "BARFOO" as "EDUIRR" using 3 as key
- ✅ encrypts "BaRFoo" as "FeVJss" using 4 as key
- ✅ encrypts "barfoo" as "onesbb" using 65 as key
- ✅ encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
- ✅ handles lack of argv[1]
- ❌ handles non-numeric key(timed out while waiting for program to exit)
- ✅ handles too many arguments
仅「处理非数字密钥」测试失败,提示等待程序退出时超时。我的代码如下:
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> int main(int argc, string argv[]) { if (argc != 2) { printf("Usage: ./ceasar key\n"); return 1; } if (atoi(argv[1]) == 0) { printf("Usage: ./ceasar key\n"); return 1; } int k = atoi(argv[1]); k = k % 26; string plaintext = get_string("plaintext: "); string ciphertext = plaintext; int n = strlen(plaintext); for (int i = 0; i < n; i++) { if ('a' <= plaintext[i] && plaintext[i] <= 'z') { if ((plaintext[i] + k) > 'z') { ciphertext[i] = ((plaintext[i] + k) - 26); } else { ciphertext[i] = (plaintext[i] + k); } } else if ('A' <= plaintext[i] && plaintext[i] <= 'Z') { if ((plaintext[i] + k) > 'Z') { ciphertext[i] = ((plaintext[i] + k) - 26); } else { ciphertext[i] = (plaintext[i] + k); } } } printf("ciphertext: %s\n", ciphertext); return 0; }
问题根源
超时的核心原因是密钥合法性判断逻辑错误:
- 用
atoi(argv[1]) == 0判断非数字密钥不可靠:- 合法密钥"0"会被错误判定为非法,直接退出;
- 输入混合数字与非数字的字符串(比如"12a")时,
atoi会返回前半部分有效数字,程序不会触发错误提示,反而继续执行到get_string等待用户输入明文,导致测试用例超时。
正确的做法是遍历密钥的每个字符,确保所有字符都是数字,而非依赖atoi的返回值。
修复后的代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> int main(int argc, string argv[]) { if (argc != 2) { printf("Usage: ./ceasar key\n"); return 1; } // 遍历密钥字符,检查是否全为数字 for (int i = 0; argv[1][i] != '\0'; i++) { if (!isdigit(argv[1][i])) { printf("Usage: ./ceasar key\n"); return 1; } } int k = atoi(argv[1]); k = k % 26; // 处理负密钥,转换为等效正偏移 if (k < 0) { k += 26; } string plaintext = get_string("plaintext: "); string ciphertext = plaintext; int n = strlen(plaintext); for (int i = 0; i < n; i++) { if ('a' <= plaintext[i] && plaintext[i] <= 'z') { ciphertext[i] = (plaintext[i] - 'a' + k) % 26 + 'a'; } else if ('A' <= plaintext[i] && plaintext[i] <= 'Z') { ciphertext[i] = (plaintext[i] - 'A' + k) % 26 + 'A'; } // 非字母字符保持不变,无需额外处理 } printf("ciphertext: %s\n", ciphertext); return 0; }
额外优化说明
- 替换了原有的字母偏移边界判断,用
(字符 - 基准字母 + 偏移) %26 + 基准字母的方式,逻辑更简洁且避免边界错误; - 增加了负密钥处理,确保输入负数时也能得到正确的加密结果;
- 移除冗余的分支判断,代码可读性更强。
内容的提问来源于stack exchange,提问作者zisegneD
相关产品推荐
相关产品推荐

