与指针和内存管理相关的最常见的错误是悬空指针。有时程序员未能用有效的地址初始化指针,此类未初始化的指针在 C 语言中称为悬空指针。

悬空指针在对象销毁时出现,当对象被删除或从内存中释放时,未修改指针的值。在这种情况下,指针指向已被释放的内存。悬空指针可能指向包含程序代码或操作系统代码的内存。如果我们给这个指针赋值,它将覆盖程序代码或操作系统指令的值;在这种情况下,程序将显示不希望的结果,甚至可能崩溃。如果内存被重新分配给其他进程,那么解引用悬空指针将导致分段错误。

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

使用 free() 函数释放内存。

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

在上面的代码中,我们创建了两个变量,即 *ptra,其中 ptr 是一个指针,a 是一个整数变量。*ptr 是一个指针变量,它使用 malloc() 函数创建。由于我们知道 malloc() 函数返回 void,所以我们使用 int *void 指针转换为 int 指针。

语句 int *ptr = (int *)malloc(sizeof(int)); 将分配 4 个字节的内存,语句 free(ptr) 释放了内存,如下图所示,带有一个交叉符号,ptr 指针变为悬空指针,因为它指向已释放的内存。如果我们将 NULL 值赋给 ptr,那么 ptr 将不再指向已删除的内存。因此,我们可以说 ptr 不是悬空指针。

变量超出作用域

当变量超出作用域时,指向该变量的指针变成悬空指针。

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

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

  • 首先,我们声明了指针变量 str
  • 在内部作用域中,我们声明了一个字符变量。str 指针包含变量 a 的地址。
  • 当控制流离开内部作用域时,变量 a 将不再可用,因此 str 指向已释放的内存。这意味着 str 指针变成了悬空指针。

函数调用

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

让我们通过一个示例来理解。

cCopy code
#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 指针是一个悬空指针,因为它指向已释放的内存。

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

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

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

首先,调用 fun() 函数,然后控制流移动到 int *fun() 的上下文中。由于 y 是一个静态变量,所以它存储在全局内存中;它的作用域在整个程序中可用。当地址值被返回时,控制流回到 main() 的上下文中。指针 p 包含了变量 y 的地址,即 100。当我们打印 *p 的值时,它打印出变量 y 的值,即 10。因此,我们可以说指针 p 不是悬空指针,因为它包含了存储在全局内存中的变量的地址。

避免悬空指针错误

可以通过将指针初始化为 NULL 值来避免悬空指针错误。如果将 NULL 值赋给指针,那么指针将不指向已释放的内存。将 NULL 值赋给指针意味着指针不指向任何内存位置。

标签: c语言, c语言教程, c语言技术, c语言学习, c语言学习教程, c语言下载, c语言开发, c语言入门教程, c语言进阶教程, c语言高级教程, c语言面试题, c语言笔试题, c语言编程思想