You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

凯撒密码加密程序异常求助:明文第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数值(比如6597),改用'A''a'这类字符常量,代码可读性更强且跨平台兼容。
  • 动态分配内存后一定要检查是否分配成功,使用完毕后记得释放内存,避免内存泄漏问题。

内容的提问来源于stack exchange,提问作者Ebuka

火山引擎 最新活动