C语言实现CS50x凯撒密码时部分小写字母回绕功能失效问题
问题根因
回绕逻辑失效的核心原因是有符号char类型溢出:
- 绝大多数C编译环境下,普通
char默认是带符号类型,可存储的值范围为-128 ~ 127 - 小写字母
z的ASCII值为122,当处理t(ASCII值116)及之后的小写字母时,只要密钥值≥12,text[i] + key的计算结果就会超过127的存储上限,触发有符号整数溢出,实际存入变量的值会变成负数 - 此时你写的判断条件
while (b > 122)永远为假——负数不可能大于122,回绕逻辑直接被跳过,自然输出错误字符 - 大写字母
Z的ASCII值仅为90,90 + key要超过127需要密钥≥38,你测试时用的密钥没达到这个阈值,所以大写逻辑看起来运行完全正常 - 你额外定义
char类型变量b的操作没有改变变量的存储类型,和原变量a的运算逻辑完全一致,自然排查不出问题。
修复方法
- 不要用
char类型存储偏移后的字符值,改用int或者unsigned char存储计算结果,从根源避免值溢出 - 弃用硬编码ASCII数值、while循环逐次减26的写法,改用字母序号偏移+取模的方式实现回绕,逻辑更简洁,也不会受密钥大小影响
- 调用
isupper/islower这类字符判断函数时,将参数强转为unsigned char,避免传入负数值触发未定义行为
修复后的参考代码:
// 循环外提前计算一次字符串长度,避免每次循环重复调用strlen产生不必要的性能损耗 int text_len = strlen(text); for (int i = 0; i < text_len; i++) { unsigned char cur = text[i]; if (isupper(cur)) { int offset = (cur - 'A' + key) % 26; // 如果密钥可能传入负数,加这行修正负偏移 if (offset < 0) offset += 26; printf("%c", 'A' + offset); } else if (islower(cur)) { int offset = (cur - 'a' + key) % 26; if (offset < 0) offset += 26; printf("%c", 'a' + offset); } else { printf("%c", cur); } }
内容的提问来源于stack exchange,提问作者Fiveishere
相关产品推荐
相关产品推荐

