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

为何CS50替换密码实现中密文长度超出预期?

CS50替换密码问题:为何必须手动添加'\0'才能正常输出?

问题描述

我正在解决CS50的替换密码问题,代码可运行但未优化。问题在于必须在末尾添加代码行cipher_text[strlen(plain_text)] = '\0';才能正常工作,否则密文长度会超出预期。请告诉我原因是什么?

以下是编写的代码:

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

int main(int argc, string argv[])
{
    // check if there's 1 argument, if there are > 1 or < 0 print error message and return 1
    if (argc != 2)
    {
        printf("Error, type 1 command\n");
        return 1;
    }

    string key = argv[1];
    long lenght = strlen(key);

    // check if the key is valid (26 characters) or not, if not return 1 and print error
    if (lenght != 26)
    {
        printf("Key must contain 26 characters.\n");
        return 1;
    }

    // iterate throughout the key, element after element whith the 1st for loop
        //check if contains letters or something else in the 1st if
        //make the key all lower in order to compare letter repetition in the else if
        //check for double letters (compare every letter (key[i]) with all the other letters) in the second for loop
    for (int i = 0 ; i < lenght ; i++)
    {
        if (isalpha(key[i]) == 0) //(key[i] < 65 || key[i] > 90) && (key[i] < 97 || key[i] > 122))
        {
            printf("Key must contain only letters\n");
            return 1;
        }
        else if (isupper(key[i]))
        {
            key[i] = tolower(key[i]);
        }
        for (int j = 0 ; j < lenght ; j++)
        {
            if (j != i && key[j] == key[i])
            {
                printf("You can't repeat letters in key (you've repeated the letter %c)\n", key[j]);
                return 1;
            }
        }
    }

    //ask user for the text to cipher
    string plain_text = get_string("plaintext:  ");

    char alphabet[] = "abcdefghijklmnopqrstuvwxyz";
    char ALPHABET[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";

    char cipher_text[strlen(plain_text)];

    // iterate through every index in plain_text
        //if it is not alphabetical, add it to cipher text
        //otherwise, check if it is lower or upper, and add to cipher_text
        //
    for (int j = 0; j < strlen(plain_text) ; j++)
    {
        if (isalpha(plain_text[j]) == 0)
        {
            cipher_text[j] = plain_text[j];
        }

        for (int x = 0 ; x < lenght ; x++)
        {
            if(islower(plain_text[j]))
            {
                if (plain_text[j] == alphabet[x])
                {
                cipher_text[j] = key[x];
                }
            }
            else if (isupper(plain_text[j]))
            {
                if (plain_text[j] == ALPHABET[x])
                {
                cipher_text[j] = toupper(key[x]);
                }
            }

        }


    }

    cipher_text[strlen(plain_text)] = '\0';

    printf("ciphertext: %s\n", cipher_text);

    return 0;

}

原因解析

C语言中的字符串本质是字符数组,但必须以**空字符'\0'**作为结束标记——所有标准字符串处理函数(比如printf("%s")、strlen)都会从数组起始地址开始读取数据,直到碰到'\0'才停止。

你的代码中存在两个关键点:

  1. char cipher_text[strlen(plain_text)]; 只分配了与明文字符数相等的内存空间,这个空间不会自动填充'\0'。
  2. 如果不手动添加cipher_text[strlen(plain_text)] = '\0';,printf输出密文时会持续读取内存中的数据,直到随机遇到某个'\0',最终导致输出内容长度超出预期(甚至出现乱码)。

额外注意:数组越界隐患

你当前的数组定义存在未定义行为风险:数组大小为strlen(plain_text),有效索引范围是0到strlen(plain_text)-1,但你赋值'\0'的位置是strlen(plain_text),属于越界访问内存。这次能运行只是环境巧合,正确的写法应该是给数组多分配一个字节来存放终止符:

char cipher_text[strlen(plain_text) + 1];

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 05:20:22