CS50 Pset2 Caesar:only_digits函数无法处理非数字密钥问题
修复CS50 Caesar作业中only_digits函数的问题
问题现象
完成CS50 Pset2 Caesar作业时,将only_digits的检查逻辑直接写在main函数里,能正常处理包含非数字的密钥;但调用only_digits函数时,执行./caesar 2x会出现程序超时退出的情况,且作业要求必须使用该函数。
错误分析
原only_digits函数存在三个关键问题:
- 返回值类型不匹配:函数声明为
bool类型,但最后返回argv(指针数组),遇到非数字时返回1(int类型),触发未定义行为导致逻辑混乱。 - 职责越界:函数内部直接打印错误信息并返回
1,但函数的核心职责应该仅为检查字符串是否全为数字,错误处理和程序终止逻辑应交给main函数。 - 效率低下:循环中每次调用
strlen(argv[1]),strlen会重复遍历字符串计算长度,增加不必要开销,是超时问题的诱因之一。
修复方案
- 调整函数参数:仅传入需要检查的目标字符串(即
argv[1]),无需传递整个argv数组。 - 优化长度计算:提前计算字符串长度并存储,避免循环内重复调用
strlen。 - 修正返回逻辑:函数仅返回
bool值——遇到非数字字符返回false,全部为数字则返回true,错误提示和程序终止逻辑移至main函数。 - 修正
isdigit判断:isdigit返回非零值表示是数字,应改为!isdigit(c)来判断非数字字符。
修复后的完整代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> bool only_digits(string s); int main(int argc, string argv[]) { if (argc == 2) { // 调用only_digits检查密钥是否全为数字 if (!only_digits(argv[1])) { printf("Usage: ./caesar key\n"); return 1; } // 将字符串密钥转换为整数 int k = atoi(argv[1]); // 获取明文 string plaintext = get_string("plaintext: "); printf("ciphertext: "); // 凯撒加密逻辑 for (int i = 0, n = strlen(plaintext); i < n; i++) { if (plaintext[i] >= 'a' && plaintext[i] <= 'z') { printf("%c", (((plaintext[i] - 'a') + k) % 26) + 'a'); } else if (plaintext[i] >= 'A' && plaintext[i] <= 'Z') { printf("%c", (((plaintext[i] - 'A') + k) % 26) + 'A'); } else { printf("%c", plaintext[i]); } } printf("\n"); return 0; } else { printf("Usage: ./caesar key\n"); return 1; } } bool only_digits(string s) { int len = strlen(s); for (int i = 0; i < len; i++) { // 判断当前字符是否不是数字 if (!isdigit(s[i])) { return false; } } return true; }
修复说明
only_digits函数现在专注于检查字符串是否全为数字,逻辑清晰且高效。main函数根据only_digits的返回值处理错误,符合单一职责原则。- 提前计算字符串长度避免了重复调用
strlen的性能损耗,解决了超时问题。
内容的提问来源于stack exchange,提问作者Meliodas
相关产品推荐
相关产品推荐

