You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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为例:

  1. 初始key经65%26计算后为13;
  2. 处理第三个字符"r"(ASCII 114)时,114+13=127>122,执行key = 13-26 = -13,key被永久修改为-13;
  3. 后续处理"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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 02:20:35