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

CS50凯撒密码C程序运行正常但无法通过check50校验问题

凯撒加密程序问题排查与修复

程序设计目标

实现根据用户传入密钥对明文字符串执行凯撒加密的功能,预设校验逻辑:

  • 若命令行参数argc个数不为2,或argv[1]传入的密钥不是合法正整数,打印使用提示Usage: ./caesar key并返回1
  • 参数校验通过后,执行完整加密流程输出密文

初始问题代码

#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>

int main(int argc, string argv[])
{
    //Get the key
    if (argc != 2)
    {
        printf("Usage: ./caesar key\n");
        return 1;
    }

    for (int key = 0; key < strlen(argv[1]); key++)
    {
        if(isalpha(argv[1][key]))
        {
            printf("Usage: ./caesar key\n");
            return 1;
        }
    }

    //Convert string to int
    int key = atoi(argv[1]);

    //Get the plaintext
    string plaintext = get_string("Plaintext:  ");

    //Output the ciphertext
    printf("ciphertext: ");

for (int i = 0, length = strlen(plaintext); i < length; i++)
{
    if(!isalpha(plaintext[i]))
    {
        printf("%c", plaintext[i]);
        continue;
    }

    int offset = isupper(plaintext[i]);

    for (int j = 0; plaintext[i] != '\0'; i++)
    {
        if (isalpha(plaintext[i]) != 0)
        {
            if (isupper(plaintext[i]) != 0)
            {
                printf("%c", ((plaintext[i] - 65 + key) % 26) + 65);
            }
            else
            {
                printf("%c", ((plaintext[i] - 97 + key) % 26) + 97);
            }
        }
        else
        {
            printf("%c", plaintext[i]);
        }
    }

    int p = plaintext[i] - offset;
    int c = (p + key) % 26;
    printf("%c", c + offset);
}

    printf("\n");
    return 0;
}

自动化校验报错现象

运行CS50的check50自动化校验得到如下结果:

  • 基础校验通过:caesar.c文件存在、可正常编译;缺少argv[1]、密钥为非数字、参数过多三类异常场景校验逻辑符合要求
  • 所有加密测试用例未通过:
    • 使用密钥3加密"BARFOO"、密钥4加密"BaRFoo"的场景,提示输出非有效ASCII文本
    • 其余加密场景提示预期输出与实际输出前缀一致但校验不通过,报错信息中展示的预期输出与实际输出可见文本完全一致,肉眼无法直接定位差异

问题排查与修复步骤

  1. 硬编码ASCII值修复
    将代码中硬编码的ASCII值65、97替换为字符常量'A'、'a',解决硬编码带来的兼容性问题。
  2. 删除冗余死循环
    删除冗余的内层for (int j = 0; plaintext[i] != '\0'; i++)循环:该循环未使用循环变量j,进入后会持续递增外层遍历的索引i直到访问到字符串结束符,甚至越界访问栈内存的未知数据,这是输出非法ASCII字符的核心原因。
  3. 修正偏移量计算逻辑
    原代码int offset = isupper(plaintext[i]);逻辑错误:isupper()函数仅返回0(非大写)或非0值(大写),并非大写/小写字符的ASCII基准值。修正逻辑为:判断当前字符为大写时offset = 'A',为小写时offset = 'a',保证偏移计算基准正确。
  4. 删除重复加密输出逻辑
    内层循环删除后,原代码中int p = plaintext[i] - offset;开始的二次加密计算属于冗余逻辑,会对同一个字符重复输出一次密文,导致输出长度是预期的2倍——这就是肉眼可见文本一致但校验不通过的根本原因:输出前缀和预期完全匹配,但末尾多了重复计算的冗余字符,导致整体哈希校验不通过。

修复后核心加密逻辑参考

for (int i = 0, length = strlen(plaintext); i < length; i++)
{
    if(!isalpha(plaintext[i]))
    {
        printf("%c", plaintext[i]);
        continue;
    }
    char offset = isupper(plaintext[i]) ? 'A' : 'a';
    printf("%c", ((plaintext[i] - offset + key) % 26) + offset);
}

替换原外层循环内的冗余逻辑后,即可通过全部check50测试用例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.31 00:36:26