【问题标题】:Why does this work? Character pointer in C [duplicate]为什么这行得通? C中的字符指针[重复]
【发布时间】:2014-02-16 13:40:45
【问题描述】:
#include <stdio.h>
#include <stdlib.h>
#include <iostream>

int main()
{
    char* s = (char*)malloc(sizeof(char) * 3); //I allocate memory for 3 chars
    s[0] = 'a';
    s[1] = 'b';
    s[2] = '\0';
    s[3] = 'd'; //This shouldn't work

    std::cout << s[3] << std::endl; //It prints out d, why?

    free(s);        
    return 0;
}

为什么允许我写 s[3]?

【问题讨论】:

  • 关于这个确切主题的另一个问题:stackoverflow.com/questions/21563565/this-malloc-shouldnt-work/…
  • 为什么人们更喜欢 C/C++ 代码的混合体?
  • 因为,在大多数 C 执行环境中,没有什么可以阻止您使用您不“拥有”的存储空间。 (而且因为“数组”在 C 中并不真正存在。在运行时没有任何东西可以识别数组的大小或其他分配。)
  • @devnull 一位朋友让我展示 C++ 的基础知识,我想向他展示 C 中的 char* 和 C++ 中的字符串。这出现了,我无法回答。
  • 那是因为在 c 和 c++ 中,没有错误检查。因此,c 和 c++ 代码更快,但容易出错。编码器负责计算边界

标签: c++ c pointers memory-management undefined-behavior


【解决方案1】:

这称为未定义的行为

编译器不会阻止你做非法的事情;但是,编译后的代码可能无法达到您的预期。

【讨论】:

    【解决方案2】:

    通常函数 malloc 分配一些最小字节数,例如 16,即使您将请求仅分配一个(或在您的示例中为 3 个)字节。

    但是,您不应依赖该功能的此类特性。它是实现定义 malloc 如何分配内存。所以你的代码有未定义的行为。

    【讨论】:

      【解决方案3】:

      进程甚至可能允许在 s[100] 上写入,但在大多数情况下它会破坏进程地址空间并产生难以调试的问题。如果写入的地址不在进程地址空间中,有时写入这样的位置会导致分段错误,但我们不会总是遇到访问冲突,因为地址可能非常落在进程的地址空间中。

      基本上,在 C/C++ 中,这些是人们应该非常小心的一些问题。因为内存的损坏会在其他一些地方表现出来,从而导致奇怪的行为,我们需要花费数小时在大海捞针中寻找答案。电子围栏、Valgrind、cppcheck 等工具有助于隔离此类错误,但即使它们也可能无法检测到内存损坏的原因。特别是电子围栏只适用于小程序,cppcheck 只能做静态检查,而 valgrind 会大大减慢这个过程。

      【讨论】:

        【解决方案4】:

        你正在写在你不拥有的内存中。您可以这样做,但它会侵犯您的地址空间,可能会导致分段错误。

        在这种情况下,它正在工作并打印d,但不能保证它会发生在其他机器上,甚至不能保证发生在您自己机器上其他编译器编译的代码中。这称为未定义行为。

        【讨论】:

          【解决方案5】:

          为什么允许我写 s[3]?

          因为你没有被禁止这样做。

          这将导致未定义的行为,因为您尝试访问未分配给您的内存。

          【讨论】:

            【解决方案6】:

            s[3] = 'd'; 它可以调用未定义的行为。它不会阻止您写入相邻的内存位置,但当您访问它时会表现不同,因为它不是由您分配的。

            【讨论】:

              【解决方案7】:

              您正在写入一个未分配的内存位置。如果此位置属于另一个程序,那么您的程序可能会出现错误的行为。如果它属于操作系统保留的内存,那么您可能会遇到分段错误或程序崩溃。这是未定义的行为。

              【讨论】:

                【解决方案8】:

                啊,这样的问题每周都会出现……

                在每个 C 教程中都必须说明一件事:C 库的环境和运行时不保证任何误用、错误类型的访问或其他未明确定义的操作都会被捕获并正确报告。这样做的重点是效率。您遵守规则(并负责实现它们),运行时围绕它们构建,有效地将编程环境模型代理到硬件和内核。

                注意为什么会发生这种情况。您在 C 中看到的环境及其运行时库比实际完成这项工作的底层机制要简单得多。在这种情况下,您会看到malloc 从系统获得了一大块内存到进程的动态数据部分,并返回了较小子块的地址,并记住它在它自己的结构中使用。您的代码试图执行的操作称为缓冲区溢出。它真正的作用是:破坏 malloc 的内部结构,或写入另一个分配的块(导致严重的延迟问题),或写入未分配的部分(导致当前进程的未来绝对没有问题)。

                【讨论】:

                  猜你喜欢
                  • 1970-01-01
                  • 2011-06-15
                  • 1970-01-01
                  • 1970-01-01
                  • 2021-12-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2016-11-20
                  • 2021-08-12
                  相关资源
                  最近更新 更多