CS50 Caesar程序问题:大写字母加密后出现不可见字符
CS50 Caesar项目:大写字母加密后出现不可见字符导致Check50失败
我为CS50的Caesar项目写了代码,本地自测符合需求,但用Check50检测时,所有包含大写字母的测试用例全失败。检测显示大写字母间有额外不可见字符,本地运行没这问题。
Check50报错:
:( encrypts "BARFOO" as "EDUIRR" using 3 as key expected "ciphertext: ED...", not "ciphertext: E\..." :( encrypts "BaRFoo" as "FeVJss" using 4 as key expected "ciphertext: Fe...", not "ciphertext: F\..."
我的代码:
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> bool only_digits(string s); char rotate(int, int); int main(int argc, string argv[]) { // 确保密钥输入正确 if (argc != 2) { printf("Usage: ./caesar key\n"); return 1; } else { int cont = only_digits(argv[1]); if (cont != 1) { return 1; } else { // 将密钥从字符串转为整数 int key = atoi(argv[1]); string plain = get_string("plain text: \n"); // 使用密钥旋转字母 printf("ciphertext: "); for (int i = 0, len = strlen(plain); i < len; i++) { rotate(plain[i], key); } printf("\n"); } } } // 使用密钥旋转字母 char rotate(int p, int i) { // 处理大写字母 if (isupper(p)) { p = p - 65; char c = (p + i) % 26; c += 65; printf("%c", c); } // 处理小写字母 if (islower(p)) { p = p - 97; char c = (p + i) % 26; c += 97; printf("%c", c); } // 非字母字符保持不变 else { printf("%c", p); } return 0; } // 确保输入的密钥仅包含数字 bool only_digits(string s) { for (int i = 0, len = strlen(s); i < len; i++) { if (!isdigit(s[i])) { printf("Usage: ./caesar key\n"); return 0; } } return 1; }
问题分析
问题出在rotate函数的逻辑上:
- 分支结构错误:第二个
if(islower(p))是独立判断,不是else if,导致else分支只和第二个if绑定。当处理大写字母时,第一个if执行完后,第二个if不成立,会直接进入else分支重复打印内容。 - 修改了原变量值:在处理大写字母时,你修改了
p的值(p = p - 65),导致后续判断islower(p)时,p已经变成0-25的数字,必然不满足小写条件,进而执行else分支打印这个数字对应的不可见ASCII字符(比如ASCII 1是控制字符),这就是Check50检测到的额外不可见字符。
修复代码
把第二个if改成else if,并且使用临时变量保存计算值,不修改原p:
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> bool only_digits(string s); char rotate(int, int); int main(int argc, string argv[]) { if (argc != 2) { printf("Usage: ./caesar key\n"); return 1; } if (!only_digits(argv[1])) { return 1; } int key = atoi(argv[1]); string plain = get_string("plain text: "); printf("ciphertext: "); for (int i = 0, len = strlen(plain); i < len; i++) { rotate(plain[i], key); } printf("\n"); return 0; } char rotate(int p, int key) { if (isupper(p)) { // 用临时变量计算,不修改原p int temp = p - 'A'; char c = (temp + key) % 26 + 'A'; printf("%c", c); } else if (islower(p)) { int temp = p - 'a'; char c = (temp + key) % 26 + 'a'; printf("%c", c); } else { printf("%c", p); } return 0; } bool only_digits(string s) { for (int i = 0, len = strlen(s); i < len; i++) { if (!isdigit(s[i])) { printf("Usage: ./caesar key\n"); return false; } } return true; }
另外,代码里多余的大括号也可以去掉,让结构更清晰。修复后,大写字母只会被处理一次,不会再输出额外的不可见字符,Check50就能通过测试了。
内容的提问来源于stack exchange,提问作者lozlf
相关产品推荐
相关产品推荐

