野指針與結構體成員指針,動態分配存儲空間

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),可以嘗試一下。

備註:一定要動態分配存儲空間!否則一定會有機會錯!

 

 

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