【C语言进阶深度学习记录】三十七 C/C++中造成程序内存错误的原因(野指针)

版权声明:本文为博主原创文章,未经博主允许不得转载,转载请加博主qq:1126137994或者微信:liu1126137994 https://blog.csdn.net/qq_37375427/article/details/88108124

什么是野指针? 指针变量存的地址是一块非法内存地址。进而形成野指针。但是需要注意一点,野指针不是NULL指针。

1 野指针的概念

  • 野指针变量中的值是非法内存地址,进而形成野指针
  • 野指针不是NULL指针,是指向不可用内存的地址的指针
  • NULL指针并无危害,很好判断,也很好调试
  • C语言的语言层面无法判断一个指针所保存的地址是否是合法的。

那么野指针是如何产生的呢?

以下在代码中的编程不规范会导致野指针的产生:

  1. 局部指针变量没有被初始化(我们知道局部变量不初始化就是随机值,所以如果局部指针被赋为随机值,那么这个随机值所代表的地址很有可能是不能访问的,是非法的地址。那么它就是野指针)
  2. 指针所指向的变量在指针被使用之前被销毁。比如在函数的返回值是指针。在函数返回后,函数的调用栈就被销毁了,接着使用被返回的指针时,这个指针所指向的内存已经被销毁,所以形成野指针
  3. free指针后,还依然使用指针,这也是野指针
  4. 进行了错误的指针运算和错误的强制类型转换(后面代码案例会分析)

1.1 野指针代码案例初探

  • 代码41-1.c
#include <stdio.h>
#include <malloc.h>


int main()
{
    int* p1 = (int*)malloc(40);
    int* p2 = (int*)1234567;
    int i = 0;
    
    for(i=0; i<40; i++)
    {
        *(p1 + i) = 40 - i;
    }

    free(p1); 
    
    for(i=0; i<40; i++)
    {
        p1[i] = p2[i];
    }
    
    return 0;
}
  • 使用gcc4.4.5编译器编译上述代码:上述代码编译没有问题,运行会出现段错误。如果使用较新版本的编译器,可能编译都会直接报错。
  • 分析错误原因:

段错误一般就是野指针问题:

  1. 首先第8行将1234567强制转换为int*指针变量并赋值给p2。然后在第29行使用p2。1234567这个地址,肯定是不能访问的。所以p2就是野指针。所以运行时访问p2指针指向的内存就会产生段错误
  2. 16行已经将指针p1的内存释放。但是在20行又使用p1.这也是野指针,会造成段错误
  3. 第13行中,因为p1在第7行只申请了40字节也就是10个int的内存。所以13行使用p1加了40次,肯定会越界访问了本不是p1申请的内存。这也会造成段错误

2 如何避免野指针

遵循以下几条规则,避免野指针的产生

  1. 绝不在函数中返回局部指针变量或者局部数组
  2. 任何变量在定义后,必须先初始化
  3. 字符数组必须确认最后一个元素是‘\0’结束符才能将该数组当成是字符串,否则不能将其当成字符串。因为字符串的所有操作都是基于最后的’\0’结束符,如果没有这个结束符,很有可能在操作字符串的时候产生内存越界
  4. 任何使用与内存操作相关的函数必须指定长度信息。在C语言中,长度信息很重要,它往往是变量类型的一部分。如数组。如下图:

在这里插入图片描述

2.1 野指针代码案例分析进阶

  • 代码41-2.c
#include <stdio.h>
#include <string.h>
#include <malloc.h>

struct Student
{
    char* name;   //这里有指针,很容易忘记初始化
    int number;
};

char* func()
{
    char p[] = "D.T.Software";
    
    return p;   //返回局部数组/指针,gcc4.4.5编译器会编译警告
}

void del(char* p)
{
    printf("%s\n", p);
    
    free(p);  //free之后要将p置NULL
}

int main()
{
    struct Student s;  //s中有指针变量,这里没有初始化,容易产生野指针
    char* p = func();   // 返回的指针指向的内存已经被销毁
    
    strcpy(s.name, p);   //p指向的内存已经被销毁不能使用,且s中的name指针没有初始化也会产生野指针
    
    s.number = 99;
    
    p = (char*)malloc(5);
    
    strcpy(p, "D.T.Software");   //内存越界
    
    del(p);
    
    return 0;
}
  • 上述代码编译就会产生警告。警告第15行返回局部指针。程序运行产生段错误
  • 其他的会产生野指针的地方在代码中已经详细的说明。自己分析即可。

3 总结

  • 知道野指针的由来以及如何避免产生野指针。这是非常重要的!!!

猜你喜欢

转载自blog.csdn.net/qq_37375427/article/details/88108124
今日推荐