野指针概述

野指针通常指的是指针变量中保存的值不会死一个合法的内存地址,但又对其访问。需要注意的是野指针不是空指针,而是指向内存不可用的指针。
C语言中对于空指针(NULL)是可以判断出来的,但是野指针是无法判断一个非空指针是否为野指针。
 
野指针一般的来源如下:

局部指针变量没有初始化

#include <string.h>
int main()
{
    char *p;
    strcpy(p,"haha"); // 野指针
    return 0;
}

使用已释放的指针

int main()
{
    int *p = (int *)malloc(sizeof(int)*5);
 
    free(p);
 
    *p = 1; // 野指针
 
    return 0;
}

指针所指向的内存空间在使用前被销毁

#include<stdio.h>
char *fun()
{
    char p[] = "haha";
 
    return p;
}
 
int main()
{
    char *p = fun();
 
    printf("%s\n",p); // 野指针
 
    return 0;
}

指针经典错误

①被指向的变量没有初始化
②没有为指针指向的内存分配足够的内存

struct Demo
{
    int *p;
}
 
int main()
{
    struct Demo d1,d2;
 
    int i;
 
    for(i = 0; i < 10; i++){
        d1.p[i] = i; // 未初始化
    }
 
    d2.p = (int *)calloc(5,sizeof(int));
    for(i = 0; i < 10; i++){
        d2.p[i] = i; // 越界,没有分配足够的空间
    }
 
    free(d2.p);
 
    return 0;
}

内存分配成功但没有初始化

#include<stdio.h>
#include<malloc.h>
int main()
{
    char *s = (char *)malloc(10);
    printf("%s\n",s); // 字符串以 '\0' 为结束符,如不初始化,则未知 '\0'在哪。
    free(s);
 
    return 0;
}

数组越界

#include<stdio.h>
 
void fun(int a[10])
{
    int i;
 
    for(i = 0; i < 10 ;i++){
        a[i] = i; // 越界
        printf("%d\n",a[i]);
    }
}
 
int main()
{
    int a[5];
 
    fun(a);
 
    return 0;
}

内存泄漏

void fun(unsigned int size)
{
    int *p = malloc(sizeof(int) * size);
    int i;
 
    if(size % 2 != 0){
        return ; // 未释放已申请的内存
    }
 
    for(i = 0; i < size ;i++){
        p[i] = i;
        printf("%d\n",p[i]);
 
    }
 
    free(p);
}

此处可表明,函数设计时最好是单入口单出口。


多次对指针进行内存释放

void fun(int *p,int size)
{
    int i;
 
    for(i = 0; i< size; i++){
        p[i] = i;
        printf("%d\n",p[i]);
    }
 
    free(p);
}
 
int main()
{
    int *p = (int *)malloc(5 * sizeof(int));
    fun(p,5);
 
    free(p); // 多次释放
 
    return 0;
}

此处可以表明在进行内存操作时,其原则是“谁申请,谁释放”,并且在释放后对指针置空。


使用已释放的指针

void fun(int *p,int size)
{
    int i;
 
    for(i = 0; i < size ;i++){
        printf("%d\n",p[i]);
    }
 
    free(p);
}
 
int main()
{
    int *p = malloc(5 * sizeof(int));
    int i = 0;
 
    fun(p,5);
 
    for(i = 0;i < 5 ; i++){
        p[i] = i; // 内存空间已释放
    }
 
    return 0;
}

内存使用一般规则

① 使用malloc等申请内存后,必须立即检查返回值是否为NULL;
② 牢记数组长度,防止越界操作,可考虑使用柔性数组;
③ 内存申请和释放操作必须匹配,防止内存泄漏也可防止多次释放;
④ 如必须在某个函数中释放一个内存,则建议添加一个参数选项,来显式提醒调用者是否释放内存;
⑤ free后立即将其赋值为NULL,因为free的参数为空时是合法参数;

email: MingruiZhou@outlook.com


MingruiZhou
13 声望2 粉丝

linux内核从业者,略懂内存管理、进程调度以及驱动框架。