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

C语言实现Vigenere密码加密结果不符合预期(CS50习题)

CS50维吉尼亚(Vigenere)密码实现问题排查

加密规则说明

  • 偏移映射规则:密钥为纯字母组成,A/a对应偏移值0,B/b对应偏移值1,以此类推Z/z对应偏移值25;密文字符计算公式为 ci = (pi + kj) % 26,其中pi为明文字母对应0-25的序号,kj为当前密钥字符对应偏移值
  • 密钥复用规则:密钥逐字符循环取用,若密钥长度小于明文长度,循环重复密钥字符直至所有明文加密完成;非字母类明文字符直接输出,不消耗密钥字符

规则示例:使用密钥ABC加密明文HELLO时,H取密钥A(0)偏移、E取B(1)偏移、第一个L取C(2)偏移,密钥用尽后循环回到A偏移第二个L、B偏移O,最终得到密文HFNLP,计算过程如下:

内容类型字符序列
明文H E L L O
密钥A B C A B
偏移值0 1 2 0 1
密文H F N L P
  • 官方运行参考:
$ ./vigenere bacon
plaintext:  Meet me at the park at eleven am
ciphertext: Negh zf av huf pcfx bt gzrwep oz

异常复现

  • 测试入参:密钥baz,明文barfoo
  • 预期输出密文:caqgon
  • 程序实际输出:caqfgv,加密结果不符合规则

问题原代码

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

// Functions:
bool check_arguments(int argc);
bool is_key_alpha(string key);
int shift(char c);

int main(int argc, string argv[])
{

    if (check_arguments(argc) == false)
    {
        return 1;
    }

    // Declaring key string variable:
    string key = argv[1];

    // Check containing any character that is not an alphabetic character
    if (is_key_alpha(key) == false)
    {
        return 1;
    }

    // Prompting user for plaintext:
    string plaintext = get_string("plaintext: ");
    
    // Ecipher:
    printf("ciphertext: ");
    for (int i = 0; i < strlen(plaintext); i++)
    {
        if (islower(plaintext[i]))
        {
            printf("%c", ((plaintext[i]) - 97 + shift(key[i])) % 26 + 97);
        }
        else if (isupper(plaintext[i]))
        {
            printf("%c", ((plaintext[i]) - 65 + shift(key[i])) % 26 + 65);
        }
        else
        {
            printf("%c", plaintext[i]);
        }
    }
    printf("\n");

    return 0;
}

// FUNCTIONS :

// Checking if there's more than one command-line argument
// Checking if the command-line argument exists:
bool check_arguments(int argc)
{
    // Checking if there's more than one command-line argument
    if (argc > 2)
    {
        printf("Usage: ./vigenere keyword\n\n");
        return false;
    }
    // Checking if the command-line argument exists:
    else if (argc < 2)
    {
        printf("Usage: ./vigenere keyword\n");
        return false;
    }
    // If okey:
    else
    {
        return true;
    }
}

// containing any character that is not an alphabetic character
bool is_key_alpha(string key)
{
    for (int i = 0; i < strlen(key); i++)
    {
        if (isalpha(key[i]) == false)
        {
            printf("Key contains non-alphabetical chars");
            return false;
        }
    }
    return true;
}

// convert character into the correct shift value
int shift(char c)
{ // for ex. char = a == 97 ascii
    if (isalpha(c))
    {
        if (isupper(c))
        // The ASCII value of A is 65
        {
            c = c - 65;
        }
        else if (islower(c))
        // The ASCII value of a is 97
        {
            c = c - 97;
        }
    }
    else
    {
        return c;
    }
    return c;
}

错误原因

加密循环中直接用明文遍历索引i访问密钥字符,存在两个问题:

  1. 没有单独维护密钥的遍历索引,也没有对密钥长度取模实现循环复用。当明文长度超过密钥长度时,key[i]会访问密钥字符串结束符之后的越界内存,读到随机值,偏移计算完全错误。
  2. 遇到非字母明文字符时没有跳过密钥计数,不符合“非字母字符不消耗密钥位”的规则。

修复方案

  1. 加密循环前单独定义密钥索引变量key_idx,初始值为0,提前计算密钥长度key_len避免循环内重复计算。
  2. 仅当当前处理的字符为字母时,通过key[key_idx % key_len]取对应密钥字符计算偏移,计算完成后key_idx自增1;非字母字符直接输出,不改动key_idx。
    修复后的加密核心代码段:
int key_len = strlen(key);
int key_idx = 0;
printf("ciphertext: ");
for (int i = 0; i < strlen(plaintext); i++)
{
    if (islower(plaintext[i]))
    {
        int offset = shift(key[key_idx % key_len]);
        printf("%c", (plaintext[i] - 'a' + offset) % 26 + 'a');
        key_idx++;
    }
    else if (isupper(plaintext[i]))
    {
        int offset = shift(key[key_idx % key_len]);
        printf("%c", (plaintext[i] - 'A' + offset) % 26 + 'A');
        key_idx++;
    }
    else
    {
        printf("%c", plaintext[i]);
    }
}

修复后用测试用例验证:密钥baz对应偏移序列为1、0、25,循环使用后加密barfoo得到的结果为caqgon,与预期一致,官方示例运行结果也符合要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 16:09:21