【问题标题】:String taking more input than it should take [duplicate]字符串接受的输入超出了应有的输入[重复]
【发布时间】:2021-07-06 15:15:10
【问题描述】:

我创建了这个简单的程序,它接受 3 名员工的意见。首先,它询问员工 id 的大小。然后它动态地将大小分配给字符数组。假设我给数组的大小为 4。在这里,我知道我们可以输入 3 个字符,因为最后一个字符是 '\0'。但是,在运行时,我可以输入比我最初假设的更多的字符。为什么会这样?预计会出错吗?

代码

#include <stdio.h>
#include <stdlib.h>

int main()
{
    int input;
    char *ptr;

    for (int i = 1; i <= 3; i++)
    {
        printf("\nEmployee %d\n", i);
        printf("    Enter the number of characters in your eID: ");
        scanf("%d", &input);

        ptr = (char *)malloc((input + 1) * sizeof(char));

        printf("    Enter your eID: ");
        scanf("%s", ptr);

        printf("    Employee eID entered: %s", ptr);

        free(ptr);
    }

    return 0;
}

输出

Employee 1
    Enter the number of characters in your eID: 4
    Enter your eID: 12345
    Employee eID entered: 12345
Employee 2
    Enter the number of characters in your eID: 3
    Enter your eID: 1234
    Employee eID entered: 1234
Employee 3
    Enter the number of characters in your eID: 2
    Enter your eID: 123
    Employee eID entered: 123

【问题讨论】:

  • 预计您不会收到错误消息。 预计会发生奇怪的事情——如果不是现在,那么最终。一个真实的事实是,向 malloc'ed 区域写入的内容超出指定的大小是错误的。如果您没有立即收到错误消息或失败,这并不意味着真实的事实在某种程度上不正确。
  • 超出缓冲区大小是 C 中调用 undefined behavior 的众多方法之一。该行为是未定义的,这意味着一切似乎都可以正常工作,它可能会出现在段错误中,它可能会在一段时间后表现出奇怪的行为,它现在可能对您有用,但不适用于另一台机器或使用不同的编译器标志。目的是编写定义明确的程序,而不是试图理解或解释 UB 在您的特定实例中的行为。
  • 仅供参考,这是在 C 中调用 UB 的全面(尽管可能并不详尽)列表...溢出内存缓冲区,正如您在 #14 处看到的那样:wikiod.com/w/C_Undefined_behavior跨度>

标签: c


【解决方案1】:

这样的问题经常被问到。我不确定,但我认为提出这个问题的动机是这样的。

  1. 听说如果你分配5个字节,写超过5个字节到那个内存是不对的。
  2. 但我试了一下,没有收到错误消息,也没有出错——它似乎有效。
  3. 所以当有人说我做不到时,我可能误解了。也许,当我写入超过 5 个字节时,它会以某种方式自动重新分配。

现在,事实是:

  1. #1 绝对正确。如果分配 5 个字节,那么向那个内存写入超过 5 个字节肯定是错误的。
  2. #2一直在发生。有时,如果你写的比你应该写的多,它似乎会奏效。
  3. #3 是一个完全错误的结论。毕竟,它似乎工作的事实确实意味着没关系。 (而且肯定不会在任何地方进行任何自动重新分配!)

多年来,我们使用了各种类比来试图解释这类事情。最古老的人之一,当时在 Usenet 新闻组 comp.lang.c 上被一个叫 Roger Miller 的人打趣说,仍然是mentioned in the C FAQ list,是,“有人告诉我,在篮球运动中你不能拿着球跑。我拿了一个篮球试了一下,效果很好。他显然不懂篮球。”

另一个流行的说法是“我听说你不应该在红灯[或当标志上写着不要走路]时通过十字路口。但我昨晚试过了,没有发生任何不好的事情。”

如果向数组(或 malloc 的区域)写入的内容比定义的要多,我使用的另一个类比是“我买了一块 40 x 40 英尺的土地。但后来我建了一个50 英尺长的房子,所以它在我的财产之外 10 英尺。天空中没有出现“超出财产线”的巨大错误消息,所以我想还好。” [1,2]

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-02-25
    • 1970-01-01
    • 1970-01-01
    • 2014-03-25
    • 2011-05-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多