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

CS50第二周替换密码:为何要在ciphertext数组中存储'\0'?

CS50替换密码:字符串结束符'\0'的作用问题

我在CS50第二周的替换密码问题中,使用以下代码实现功能:

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

bool check_char(string key);
void cipher_function(string plaintext, string argv);

int main(int argc, string argv[])
{
    if (argc != 2)
    {
        printf("Usage: ./substitution key\n");
        return 1;
    }
    if (!check_char(argv[1]))
    {
        printf("Key must contain 26 unique characters.\n");
        return 1;
    }

    // Get plaintext from user
    string plaintext = get_string("plaintext: ");

    // Function to generate and print ciphertext based on plaintext and key
    cipher_function(plaintext, argv[1]);


}

bool check_char(string key)
{
    int length;
    length = strlen(key);

    if (length != 26)
    {
        return false;
    }
    for (int i = 0; i < length; i++)
    {
        key[i] = toupper(key[i]);
    }
    for (int i = 0; i < length; i++)
    {
        if (!isalpha(key[i]))
        {
            return false;
        }
        for (int j = i + 1; j < length; j++)
        {
            if (key[i] == key[j])
            {
                return false;
            }
        }
    }
    return true;
}

void cipher_function(string plaintext, string argv)
{
    int length = strlen(plaintext);
    int index;
    char ciphertext[length + 1];

    for (int i = 0; i < length; i++)
    {
        if (islower(plaintext[i])) // If plaintext character is lowercase
        {
            index = plaintext[i] - 97;
            ciphertext[i] = argv[index];
            if (isupper(ciphertext[i])) // If the ciphertext char for corresponding plaintext is upper, then convert to lower
            {
                ciphertext[i] += 32;
            }
        }
        else if (isupper(plaintext[i])) // If plaintext character is uppercase
        {
            index = plaintext[i] - 65;
            ciphertext[i] = argv[index];
            if (islower(ciphertext[i]))
            {
                ciphertext[i] -= 32;   // If the ciphertext char for corresponding plaintext is lower, then convert to upper
            }
        }
        else
        {
            ciphertext[i] = plaintext[i]; // To print out non-alpha characters in the plaintext like spaces, numbers etc.
        }
    }
    ciphertext[length] = '\0';
    printf("ciphertext: %s\n", ciphertext);
}

当我移除第92行的ciphertext[length] = '\0';,并将第65行的ciphertext数组长度设为与明文数组长度相同时,部分输入的输出末尾会出现带问号的奇怪符号。我了解到'\0'用于标记字符串结束,但不清楚这一规则如何作用于数组,特此问询原因。


问题解释

C语言中字符串的本质

C语言里没有原生的"字符串"类型,我们说的字符串其实是以'\0'(ASCII值为0的空字符)结尾的字符数组。所有处理字符串的标准函数(比如printf("%s")、strlen)都依赖这个结束符来判断字符串的边界:它们会从数组的起始地址开始逐个读取字符,直到碰到'\0'才停止。

代码出问题的具体原因

  1. 当你把ciphertext的长度设为和明文长度length一致时,数组的所有位置(下标0到length-1)都被明文转换后的字符填满了,没有多余空间存放'\0'。
  2. 如果你不手动添加'\0',数组末尾之后的内存区域是未初始化的垃圾数据——里面可能是任意随机值,几乎不可能刚好是'\0'。
  3. 当printf打印这个数组时,它会越过数组边界继续读取内存中的垃圾数据,直到某个位置碰巧出现'\0'才停下。那些末尾的问号或乱码,就是这些未定义的垃圾数据被解析成字符后的结果。

原代码正常的原因

原代码定义char ciphertext[length + 1];,多出来的1个元素位置就是专门留给'\0'的。手动添加ciphertext[length] = '\0';后,printf读到这个位置就会停止,不会越界读取垃圾数据。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.17 09:58:09