C语言 - 野指针

C语言 - 野指针 首页 / C语言入门教程 / C语言 - 野指针

与指针和内存管理有关的最常见的错误是悬空指针/野生指针。有时,程序员无法使用有效地址初始化指针,则这种类型的初始化指针在C语言中称为"悬空指针"。

当在不破坏指针值的情况下从内存中删除或取消分配对象时,在对象销毁时会发生悬空指针。在这种情况下,指针指向已取消分配的内存。悬空指针可以指向内存,其中包含程序代码或操作系统代码。如果我们将值分配给该指针,则它将覆盖程序代码或操作系统指令的值;在这种情况下,程序将显示不良结果,甚至可能崩溃。如果将内存重新分配给其他某个进程,则我们取消引用悬空指针将导致分段错误。

让我们观察以下示例。

Dangling Pointers in C

在上图中,我们可以看到 Pointer 3 是一个悬空的指针。 Pointer1 Pointer2 是分别指向已分配对象(即对象1和对象2)的指针。 Pointer3 是一个悬空指针,因为它指向已取消分配的对象。

让我们通过一些C程序了解悬空指针。

free()函数取消分配内存

#include <stdio.h>
int main()
{
   int *ptr=(int *)malloc(sizeof(int));
   int a=560;
   ptr=&a;
   free(ptr);
   return 0;
}

在上面的代码中,我们创建了两个变量,即* ptr和a,其中'ptr'是指针,'a'是整数变量。 * ptr是一个指针变量,它是在 malloc()函数的帮助下创建的。我们知道malloc()函数返回void,因此我们使用int *将void指针转换为int指针。

语句 int * ptr =(int *)malloc(sizeof(int)); 将分配4个字节的内存,如下图所示:

Dangling Pointers in C

语句 free(ptr)取消分配内存,如下图所示,带有叉号,并且'ptr'指针悬空,因为它指向已取消分配的内存。

Dangling Pointers in C

如果我们将NULL值分配给'ptr',则'ptr'将不会指向已删除的内存。因此,我们可以说ptr不是悬空指针,如下图所示:

Dangling Pointers in C

变量超出范围

当变量超出范围时,指向该变量的指针将成为悬空指针。

#include<stdio.h>
int main()
{
    char *str;
    {
        char a = ?A?;
        str = &a;
    }
   //a 超出范围
   //str 现在是一个悬空指针
    printf("%s", *str);
}

在上面的代码中,我们执行了以下步骤:

  • 首先,我们声明名为'str'的指针变量。
  • 在内部范围内,我们声明一个字符变量。 str指针包含变量'a'的地址。
  • 当控件超出内部范围时," a"变量将不再可用,因此str指向已取消分配的内存。这意味着str指针变成了悬空指针。

函数调用

现在,我们将看到调用函数时指针如何悬空。

通过示例让我们理解。

#include <stdio.h>
int *fun(){
    int y=10;
    return &y;
}
int main()
{
  int *p=fun();
  printf("%d", *p);
  return 0;
}

在上面的代码中,我们执行了以下步骤:

  • 首先,我们创建 main()函数,在其中声明了'p'指针,该指针包含 fun()的返回值
  • 调用 fun()时,控件将移至 int * fun() fun()的上下文返回" y"变量的地址。
  • 当控件返回到 main()函数的上下文时,这意味着变量'y'不再可用。因此,我们可以说'p'指针是一个悬空指针,因为它指向已取消分配的内存。
Dangling Pointers in C

我们以图表的形式表示上述代码的工作情况。

Dangling Pointers in C

让我们考虑另一个悬空指针的例子。

#include <stdio.h>
int *fun()
{
    static int y=10;
    return &y;
}
int main()
{
   int *p=fun();
   printf("%d", *p);
    return 0;
}

上面的代码与上一个代码相似,但是唯一的区别是变量y是静态的。我们知道静态变量存储在全局内存中。

Dangling Pointers in C

现在,我们以图形方式表示上述代码的工作。

Dangling Pointers in C

上图显示了堆栈存储器。首先,调用 fun()函数,然后将控件移至 int * fun()的上下文。由于" y"是静态变量,因此它是存储在全局存储器中;它的范围在整个程序中都可用。返回地址值时,控件将返回到 main()的上下文。指针" p"包含地址" y",即100。当我们打印该值时'* p'的值,则打印出'y'的值,即10。因此,我们可以说指针'p'不是悬空指针,因为它包含存储在全局变量中的变量的地址记忆。

避免指针悬空错误

可以通过将指针初始化为 NULL 值来避免悬空的指针错误。如果将 NULL 值分配给指针,则指针将不会指向已取消分配的内存。将 NULL 值分配给指针意味着指针没有指向任何内存位置。

祝学习愉快!(内容编辑有误?请选中要编辑内容 -> 右键 -> 修改 -> 提交!)

技术教程推荐

从0开始学游戏开发 -〔蔡能〕

数据分析实战45讲 -〔陈旸〕

Java业务开发常见错误100例 -〔朱晔〕

零基础实战机器学习 -〔黄佳〕

超级访谈:对话张雪峰 -〔张雪峰〕

Web漏洞挖掘实战 -〔王昊天〕

深入浅出可观测性 -〔翁一磊〕

手把手教你落地DDD -〔钟敬〕

AI大模型系统实战 -〔Tyler〕

好记忆不如烂笔头。留下您的足迹吧 :)