【问题标题】:Error (Segmentation Fault) while reusing a dangling or null pointer重用悬空指针或空指针时出错(分段错误)
【发布时间】:2021-04-09 11:08:16
【问题描述】:
#include<stdlib.h>
#include<string.h>
int main ( void )
{
  char *title=NULL;
  title = (char *) malloc(15);
  strcpy(title, "C Programming");
  printf("String = %c", *title);
  free(title); 
//   title=NULL;    //or title = 0;
  strcpy(title, "C++");
  printf(" %s", title);
  return 0;
}

当我取消注释“title=NULL”行时,程序因分段错误而崩溃;有人可以解释一下这种行为吗

否则打印“String = C C++”

【问题讨论】:

  • title=NULL; 是为了避免您刚刚面临的行为,您为什么要在不应该​​的情况下尝试使某些东西起作用,您需要再次 malloc 使其起作用,因为您free'd 以前的记忆
  • free(title); // title=NULL; //or title = 0; strcpy(title, "C++"); 您正在使用您释放的内存。因此,您遇到了分段错误 - 这是您在使用不属于您的内存时遇到的错误。
  • @IrAM 告诉程序的输出是一个 MCQ 问题,我只是想知道将字符串复制到该指针时出了什么问题。
  • strcpy(title, "C++"); 导致未定义的行为,当 title 已被释放且未设置为 NULL 时(未定义的行为包括“显然工作正常”)。 strcpy(NULL, "C++"); 虽然是未定义的行为,但在几乎任何现代系统上都会出现段错误。
  • 输出为:未定义

标签: c null-pointer dangling-pointer


【解决方案1】:

如果您的代码取消引用悬空或空指针,则行为为undefined - 任何事情都可能发生。这两种可能的行为(“它按预期工作”和“它崩溃”)实际上是未定义行为的最常见表现。

有时,您可以合理化未定义的行为 - 就像在这种情况下一样。但你不能总是指望它是可以理解的。

  • 如果您的代码尝试将内容写入空地址,它会崩溃,因为操作系统可以检测到这一点。它非常简单(空指针指向一个不可读和不可写的内存页面)并且很有用(一个好的调试器会直接停在有问题的代码行)。
  • 如果您的代码尝试重用一个悬空指针,它指向的地址通常仍然是可写的 - free 不会告诉操作系统它现在是悬空的。 free 只会编辑一些簿记数据结构,因此释放的地址将可用于将来的分配。访问悬空指针不容易导致崩溃,因为操作系统只能在页面粒度上管理内存访问,可以是4 KiB 或类似的东西。

【讨论】:

    【解决方案2】:

    这是未定义的行为。您通过执行free(title) 告诉操作系统您的程序不再需要内存,但这并不意味着内存会立即从您的进程中取出。取而代之的是title 仍然拥有(现在已释放但未考虑)内存的地址,随后的strcpy()(取决于操作系统及其内存使用策略)可能能够写入该内存,printf() 将获得地址(再次释放并且下落不明)并将打印字符,直到到达第一个由strcpy() 放置的\0

    当您在释放 title 后将其正确设置为 NULL 时,期望指向已分配内存的指针的其他函数(此处为 strcpy())将获得无效输入并失败(出现分段错误)。

    【讨论】:

      【解决方案3】:

      90% 的问题是red herring。整个问题可以用一行重述:

      当我这样做时: 标题=空; strcpy(标题,“C++”); 我的程序崩溃了。为什么?

      上面的代码尝试将字节写入由空指针引用的内存地址。根据定义,这是未定义的行为。未定义的行为意味着任何事情都可能发生,例如一碗矮牵牛花和抹香鲸可能会从天上掉下来,但是在绝大多数执行环境中,当然在您的执行环境中,空指针引用的内存地址不是可写,因此这将始终导致您遇到的确切行为:分段错误。

      此外,为了解决问题的其余部分,当将指针设置为 NULL 的行被注释掉时,您正在写入已释放的内存位置。由于它已被释放,因此不应再次访问它,并且再次访问它是未定义的行为,只有在这种情况下,没有检测到滥用的机制,所以它只是巧合。尝试在不同的环境中运行相同的程序,就会有成盆的矮牵牛和抹香鲸从天而降。

      【讨论】:

        猜你喜欢
        • 2018-07-20
        • 1970-01-01
        • 2013-04-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多