野指针与结构体成员指针,动态分配存储空间

1、野指针举例

例1:明显的野指针,直接赋值

#include <stdio.h>
int main()
{
    int a;
    int *p;
    *p=10;//错误来源与此处
    printf("%d %d\n",a,*p);
    return 0;
}

*p没有被初始化,而直接赋值为10,相当于把某一内存中直接存入“10”;

未初始化的*p指向一个随机的内存单元0x2,该内存单元(0x2)中的值(未知)由计算机内存管理的规则决定,不能随意被程序更改。

指针变量*p初始化的意义:定义*p的指向!而不是初始化前的随机指向!!!

例1修改后如下,可以正常运行:

#include <stdio.h>
int main()
{
    int a=2;
    int *p=&a;//必须初始化
    *p=10;
    printf("%d %d\n",a,*p);
    return 0;
}

例2:未分配内存的野指针

#include <stdio.h>
#include<string.h>

struct test
{
    int x;
    char *str;
};

int main()
{
    struct test a;
    a.x=100;
    char s[]="hello";
    strcpy(a.str,s);//复制字符串s到结构体变量a的数据项str
    printf("%d %s\n",a.x,a.str);
    return 0;
}

其中,strcpy(a.str,s)的作用是把数组s[ ]的首地址赋值给a.str

但是a.str在未初始化前,指向的是一个内存中的随机地址,不能随便被更改;

未分配a.str的具体指向时(未初始化),a.str就是一种野指针!

#include <stdio.h>
#include<string.h>
#include<malloc.h>

struct test
{
    int x;
    char *str;
};

int main()
{
    struct test a;
    a.x=100;
    char s[]="hello";
    a.str=(char*)malloc(strlen(s)+1);//!!!通过malloc给a.str分配了一端长度为(s+1)的内存空间
    strcpy(a.str,s);//复制字符串s到结构体变量a的数据项str
    printf("%d %s\n",a.x,a.str);
    return 0;
}

malloc 函数其实就是在内存中:找一片指定大小的空间,然后将这个空间的首地址给一个指针变量,这里的指针变量可以是一个单独的指针,也可以是一个数组的首地址, 这要看malloc函数中参数size的具体内容。我们这里malloc分配的内存空间在逻辑上是连续的,而在物理上可以不连续。我们作为程序员,关注的 是逻辑上的连续,其它的,操作系统会帮着我们处理的。

分配空间口的a.str就不再是随意指向的野指针了,就可以用strcpy进行赋值了,程序就不会报错。

 

例3:不易被发现的野指针

struct test
{
    int x;
    char *str;
};

int main()
{
    struct test a;
    a.x=100;
    char s[]="hello";
    a.str=s;//指针的赋值,数组首元素的地址赋值给a.str
    printf("%d %s\n",a.x,a.str);
    return 0;
}

该程序编译完成没有bug,并且正常运行!

但是,详细分析:当s[ ]不是一个固定的数组,而是由其它机制带来的数组,例如该数组在被a.str使用时已经被释放掉了;

则a.str指向的是一个程序不具备访问权限的内存单元,a.str就会变成“野指针”!!!如下程序所示:

#include <stdio.h>
#include<string.h>
#include<malloc.h>

struct test
{
    int x;
    char *str;
};

int main()
{
    struct test a;
    a.x=100;
    char *s=(char*)malloc(10);//第一步,给s分配长度为10的内存地址
    strcpy(s,"hello");//第二步,在该地址中存放hell\0
    a.str=s;//第三步,将s的地址赋值给a.str
    free(s);//第四步,释放掉s的内存空间
    printf("%d %s\n",a.x,a.str);//第五步,a.str输出的值是已经被释放掉的内存中的随机值
    return 0;
}

程序运行结果:

a.str的输出结果是:?n

实际上对该程序而言,每一次运行输出的a.str的值都不同,因为a.str通过s赋值,但是s的内存又被释放掉了,因此a.str指向的值为内存的随机内容。

如果注释掉free(s),可以尝试一下。

备注:一定要动态分配存储空间!否则一定会有机会错!

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章