凯撒密码加密程序异常求助:明文第8位后加密错误
问题定位与修复
你的凯撒密码程序出现第8位及之后字符加密异常的核心原因是固定大小的cyphertext数组内存不足,导致字符串拼接时发生内存越界。
具体分析
你定义的char cyphertext[] = "ciphertext: ";是一个固定长度的字符数组,它的大小仅够存储初始字符串(包括末尾的\0)。初始字符串"ciphertext: "的长度是12个字符(加上结束符\0共13字节),当你用strncat不断追加加密后的字符时,前7次追加刚好填满剩余空间,第8次追加就会超出数组的内存边界,覆盖程序其他区域的内存数据,破坏运行状态,最终导致后续字符的加密结果异常。
修复方案
我们需要为cyphertext分配足够的内存空间,确保能容纳初始前缀加上所有明文转换后的字符。这里提供两种实用方案:
方案1:动态分配内存(更灵活通用)
先计算明文的长度,再为cyphertext分配「前缀长度 + 明文长度 + 1(存储\0)」的内存:
#include <stdio.h> #include <cs50.h> #include <ctype.h> #include <string.h> #include <stdlib.h> char upperciphertext(char text); char lowerciphertext(char text); int key; int main(int argc, string argv[]) { // 简化命令行参数检查 if (argc != 2) { printf("Usage: ./caesar key\n"); return 1; } // 验证参数是否为纯数字 for (int i = 0; argv[1][i] != '\0'; i++) { if (!isdigit(argv[1][i])) { printf("Usage: ./caesar key\n"); return 1; } } key = atoi(argv[1]); char *plaintext = get_string("plaintext: \n"); // 计算所需总内存:前缀长度 + 明文长度 + 1(结束符) const char *prefix = "ciphertext: "; int total_len = strlen(prefix) + strlen(plaintext) + 1; char *cyphertext = malloc(total_len * sizeof(char)); if (cyphertext == NULL) { printf("Memory allocation failed\n"); return 1; } // 初始化前缀 strcpy(cyphertext, prefix); // 遍历处理每个明文字符 for (int i = 0; plaintext[i] != '\0'; i++) { if (isalpha(plaintext[i]) && isupper(plaintext[i])) { char cytext = upperciphertext(plaintext[i]); strncat(cyphertext, &cytext, 1); } else if (isalpha(plaintext[i]) && islower(plaintext[i])) { char lowcytext = lowerciphertext(plaintext[i]); strncat(cyphertext, &lowcytext, 1); } else { strncat(cyphertext, &plaintext[i], 1); } } printf("%s\n", cyphertext); // 释放动态分配的内存,避免泄漏 free(cyphertext); return 0; } // 大写字符加密函数(用字符常量替代硬编码ASCII值,可读性更强) char upperciphertext(char text) { int alphaindex = text - 'A'; int cipher = (alphaindex + key) % 26; return cipher + 'A'; } // 小写字符加密函数 char lowerciphertext(char text) { int alphaindex = text - 'a'; int cipher = (alphaindex + key) % 26; return cipher + 'a'; }
方案2:使用足够大的静态数组(简单场景适用)
如果能确定明文的最大长度限制,可以直接定义一个足够大的静态数组:
// 假设明文最多不超过1000个字符,预留足够空间 char cyphertext[1024] = "ciphertext: ";
这种方式实现简单,但灵活性较差,适合固定场景使用。
额外优化小建议
- 避免硬编码ASCII数值(比如
65、97),改用'A'、'a'这类字符常量,代码可读性更强且跨平台兼容。 - 动态分配内存后一定要检查是否分配成功,使用完毕后记得释放内存,避免内存泄漏问题。
内容的提问来源于stack exchange,提问作者Ebuka




