關於這一點本來是不想寫的,一直覺的是些旁枝末葉的東西,很容易就能掌握,或者說不會犯錯的地方,但這兩天敲代碼的時候就遇到了這樣的問題,或者說不容易犯錯的地方才最容易犯錯吧!下面切入正題:
何為野指針,對一個指向空地址的指針我們將其稱為野指針,即所指向的地址不能進行操作的指針;(這兩天寫C++的時候就遇到了這個問題,我把指針重新指向了未分配的空間並對其進行了操作!剛開始硬是不知道自己錯在哪!來來回回的看來好幾遍才想到這一點);
下面先來看一段代碼;
1 #define _CRT_SECURE_NO_WARNINGS 2 #include <stdio.h> 3 #include <string.h> 4 #include <stdlib.h> 5 6 void distribution(char **str)//分配空間 7 { 8 char *tmp = NULL;//輔助指針變量 9 10 if(str == NULL)//如果傳遞過來的地址為空,則不執行以下操作 11 { 12 printf("error\n"); 13 return ; 14 } 15 16 tmp = (char *)malloc(sizeof(char)* 5); 17 if(tmp == NULL) 18 { 19 printf("error"); 20 return; 21 } 22 strcpy(tmp,"aaa");//將aaa字符串copy到分配的內存空間中 23 *str = tmp;//可以通過二級指針來操作一級指針的指向//即間接賦值是指針存在的最大意義 24 25 /********************************/ 26 //然后我們將透tmp所指向的內存空間釋放掉 27 free(tmp); 28 /********************************/ 29 } 30 31 void main() 32 { 33 char *point; 34 distribution(NULL);//如果我們傳遞一個空地址過去,而且沒有合理的處理,編譯器會直接報錯 35 36 distribution(&point);//因為是同二級指針所以我們要將一級指針的地址傳遞過去 37 if(point != NULL)//如果point不是指向NULL我們就打印字符串 38 { 39 printf("%s\n",point);//結果打印出來的是一堆亂碼 40 41 } 42 43 if(point != NULL) 44 { 45 free(point);//當編譯器執行到這一步的時候會停止調試 46 } 47 48 49 system("pause"); 50 return; 51 }
在這里我們可以看到,在distribution()函數中雖然我們已經在棧區分配了內存,並將指針指向了它,但是當我們將其釋放掉之后,並不能判斷出它已經是空指針了,而且會打印出一堆亂碼,並且再次對這塊內存進行釋放的時候 free(point) 我們會發現編譯器會直接報錯(老版本的編譯器搞不好會直接當機);
那么問題就出來了,明明已經將內存釋放掉了,為什么,編譯器認為它指向一個空間:即if(point != NULL)並不能判斷出它所指向的地址已經是空地址了:
所謂的地址就是內存編號,而這個內存編號也就是我們所說的物理地址,我們所能析構的和操作的內存空間,也就是我們對其進行了類型(int ,char等)聲明的內存空間,不然是無法對其訪問的,所以也就是說釋放的內存空間就是將我們所聲明的地址類型給抹除了,它就變為了沒有類型,沒有類型不是void類型,但是物理地址是無法被釋放的,不然我們要到哪里去操作內存空間呢?所以即使釋放掉了內存空間,地址仍然存在,所以身為一個負責任的人我們應該在釋放完內存之后,將其指向NULL(這也是為什么很多資料上在要求定義變量的時候就初始化的原因吧!);
**str = &point;// * 就像一把鑰匙,通過*str可以達到改變point指向的效果,**str可以達到改變*point(改變具體值)的效果;
free(tmp); tmp = NULL;通過free(tmp),直接釋放掉了在在堆區所分配的內存,但是指向這個內存塊的的地址符是不會改變的,即在tmp在沒有指向NULL的時候*str所指向的地址符和tmp時一樣的,所以釋放的tmp所指向的內存塊,即釋放了*str所指向的內存塊,但是*str的內存快並沒有改變,所以此時應該在加上*str = NULL,這樣point也會指向null,而不會指向一個只有地址符的內存塊(即野指針);
在進行內存分配的時候我們也要知道我們是不是用NULL指向了一個地址,即
distribution(NULL);//如果我們傳遞一個空地址過去,而且沒有合理的處理,編譯器會直接報錯
如果不對其判斷直接執行
//if(str == NULL)//如果傳遞過來的地址為空,則不執行以下操作
*str = tmp;//可以通過二級指針來操作一級指針的指向//即間接賦值是指針存在的最大意義
編譯器會直接報錯,因為無法使用NULL指向一個地址;