凯撒密码(Caesar cypher)调试:输出末尾出现问号与随机字符
凯撒密码代码乱码问题解决
问题现象
编写的C语言凯撒密码代码运行时,密文末尾会出现问号和随机字符,仅当输入为5个字符时功能正常。调整数组长度(将char cyphertext[x + 1];改为char cyphertext[x];)无法解决问题。
问题代码
#include <cs50.h> #include <stdio.h> #include <stdlib.h> #include <string.h> bool only_digits(string s); char rotate(char c, int n); int main(int argc, string argv[]) { if (argc < 2 || only_digits(argv[1]) == false || argc > 2) // 检查输入合法性 { printf("usage: ./caesasr key\n"); } else { int key = atoi(argv[1]); string plaintext = get_string("plaintext: "); int x = strlen(plaintext); char cyphertext[x + 1]; for (int i = 0; i < x; i++) { cyphertext[i] = rotate(plaintext[i], key); } printf("cyphertext: %s\n", cyphertext); } } // 检查输入是否为0-9的单个数字 bool only_digits(string s) { if (s[0] > 47 && s[0] < 58 && strlen(s) == 1) { return true; } else { return false; } } // 将字符c按凯撒密码规则偏移n位 // 大写字母公式:(cin -65 + n)%26 +65 // 小写字母公式:(cin -97 + n)%26 +97 // 非字母字符直接返回 char rotate(char c, int n) { if (c > 64 && c < 91) { c = ((c - 65 + n) % 26 + 65); } if (c > 96 && c < 123) { c = ((c - 97 + n) % 26 + 97); } else { return c; } return c; }
问题原因
C语言中,字符串必须以**空字符'\0'**作为结束标记。printf("%s", ...)会从起始地址开始读取字符,直到遇到'\0'才停止输出。当前代码中,cyphertext数组虽然分配了x+1的空间(足够容纳x个字符加结束符),但循环只填充了前x个字符,没有手动添加'\0',导致printf继续读取数组后面的随机内存数据,从而出现问号、乱码等异常字符。
输入恰好为5个字符时正常是偶然情况——此时数组后面的内存恰好存在一个'\0',属于未定义行为的巧合结果。
解决方法
在循环结束后,给cyphertext的第x个位置赋值为'\0',明确标记字符串结束:
for (int i = 0; i < x; i++) { cyphertext[i] = rotate(plaintext[i], key); } // 添加结束符 cyphertext[x] = '\0'; printf("cyphertext: %s\n", cyphertext);
额外优化建议
only_digits函数逻辑优化:当前仅允许单个数字作为密钥,实际凯撒密码的密钥可以是任意正整数,修改函数支持多位数输入:
bool only_digits(string s) { for (int i = 0; s[i] != '\0'; i++) { if (!(s[i] >= '0' && s[i] <= '9')) { return false; } } return true; }
rotate函数逻辑优化:将双if改为else if让逻辑更严谨,同时用字符常量替代ASCII数值提升可读性:
char rotate(char c, int n) { if (c >= 'A' && c <= 'Z') { c = ((c - 'A' + n) % 26 + 'A'); } else if (c >= 'a' && c <= 'z') { c = ((c - 'a' + n) % 26 + 'a'); } // 非字母直接返回原字符 return c; }
内容的提问来源于stack exchange,提问作者Butterworth Filter
相关产品推荐
相关产品推荐

