CS50凯撒密码程序Bug:单个字母加密结果错误
Caesar密码程序错误分析与修复
问题描述
执行命令./caesar 65,输入plaintext: barfoo后,字母"f"被错误转换为"Y",预期结果应为"s"。
问题代码
#include <cs50.h> #include <stdio.h> #include <ctype.h> #include <string.h> #include <stdlib.h> int main(int argc, string argv[]) //argc(参数数量) 记录命令行输入的参数个数,argv (参数向量) 存储命令行输入的参数数组 { if (argv[1] == NULL) { printf("Usage: ./caesar key"); return 1; } if (argc != 2) { printf("Usage: ./caesar key"); return 1; } //处理密钥输入 int key; for (int i = 0; i < strlen(argv[1]); i++) { if (isdigit(argv[1][i])) //检查每个字符是否为数字 { key = strtol(argv[1], NULL, 10);//将字符串转换为整数密钥 } else { printf("Usage: ./caesar key"); return 1; } } string input = get_string("plaintext: "); printf("ciphertext: "); if (key > 26) { key = key % 26; } int new_pos; for (int i = 0; i < strlen(input); i++) { int i_int = (int)input[i]; //将字符转为ASCII值 if (i_int >= 65 && i_int <= 90)// 大写字母处理 { if ((key + i_int) > 90) { key = key - 26; new_pos = i_int + key; } else { new_pos = i_int + key; } char letter = (char)new_pos; //转回字符 printf("%c", letter); } else if (i_int >= 97 && i_int <= 122) //小写字母处理 { if ((key + i_int) > 122) { key = key - 26; new_pos = i_int + key; } else { new_pos = i_int + key; } char letter = (char)new_pos; //转回字符 printf("%c", letter); } else //非字母字符直接输出 { printf("%c", i_int); } } printf("\n"); }
错误原因
核心问题是在字符处理循环中修改了原始的key值。以输入barfoo为例:
- 初始
key经65%26计算后为13; - 处理第三个字符"r"(ASCII 114)时,114+13=127>122,执行
key = 13-26 = -13,key被永久修改为-13; - 后续处理"f"(ASCII 102)时,102 + (-13)=89,对应字符"Y",导致错误结果。
修复方案
不要修改原始key,改用模运算实现循环移位,这种方式无需判断范围,逻辑更简洁可靠:
修复后的完整代码
#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: ./caesar key\n"); return 1; } int key; for (int i = 0; i < strlen(argv[1]); i++) { if (!isdigit(argv[1][i])) { printf("Usage: ./caesar key\n"); return 1; } } key = strtol(argv[1], NULL, 10); key = key % 26; // 提前将密钥归约到0-25范围 if (key < 0) { key += 26; // 处理负数密钥(若允许) } string input = get_string("plaintext: "); printf("ciphertext: "); for (int i = 0; i < strlen(input); i++) { char c = input[i]; if (isupper(c)) { printf("%c", ((c - 'A') + key) % 26 + 'A'); } else if (islower(c)) { printf("%c", ((c - 'a') + key) % 26 + 'a'); } else { printf("%c", c); } } printf("\n"); return 0; }
验证结果
执行./caesar 65并输入barfoo,65%26=13,转换结果为onesbb,其中"f"正确转换为"s",符合预期。
内容的提问来源于stack exchange,提问作者sam
相关产品推荐
相关产品推荐

