當以指標作為引數,在函式中分配記憶體的時候,其操作要格外小心。
#include
#include
#include
#include
void fun(int *p)
執行結果如下:
main 1:
0x00032fa0
1fun 1:
0x00032fa0
1fun 2:
0x00032fd8
2main 2:
0x00032fd82
void getmemory(char *p)
void test(void)
請問執行test函式會有什麼樣的結果?
答:記憶體錯誤,getmemory並沒有給str分配記憶體空間,p是str的複製,p和str指向同一塊記憶體區域
上面的程式p複製了str成為null指標,然後p分配到了記憶體空間,而str仍然為null,所以出錯
修改為引用傳遞就可以了。或者改用指標的指標。
void getmemory(char *&p)
char *getmemory(void)
void test(void)
請問執行test函式會有什麼樣的結果?答:
str指向一塊已經釋放掉的記憶體,結果錯誤。指標p指向的「hello world」記憶體由於在棧中分配,在函式結束後釋放
乙個由c/c++編譯的程式占用的記憶體分為以下幾個部分
1、棧區(stack)—由編譯器自動分配釋放,存放函式的引數值,區域性變數的值等。其操作方式類似於
資料結構中的棧。
2、堆區(heap)—一般由程式設計師分配釋放,若程式設計師不釋放,程式結束時可能由os**。注意它與資料
結構中的堆是兩回事,分配方式倒是類似於鍊錶。
3、全域性區(靜態區)(static)—全域性變數和靜態變數的儲存是放在一塊的,初始化的全域性變數和靜態
變數在一塊區域,未初始化的全域性變數和未初始化的靜態變數在相鄰的另一塊區域。程式結束後由系統
釋放。4、文字常量區—常量字串就是放在這裡的。程式結束後由系統釋放。
5、程式**區
這是乙個例子
//main.cpp
int a=0; //全域性初始化區
char *p1; //全域性未初始化區
main()
該**段的意圖是通過乙個函式建立乙個二叉樹的節點,然而在,呼叫該函式後,試圖訪問該節點結構體的成員時候,卻發生了記憶體訪問錯誤,到底問題出在哪兒呢?
一直不明白指標作為函式引數傳值的機制,翻開林銳的《高質量c/c++程式設計指南》,找到了答案。
[如果函式的引數是乙個指標,不要指望用該指標去申請動態記憶體]
原來問題出在c編譯器原理上:編譯器總是要為函式的每個引數製作臨時副本,指標引數tree的副本是 _tree,編譯器使 _tree = tree。如果函式體內的程式修改了_tree的內容,就導致引數tree的內容作相應的修改。這就是指標可以用作輸出引數的原因。
即上面的函式**經過編譯後成為:
createnode(binnode *tree,char *p)
如果沒有
_tree = (binnode *) malloc(sizeof(binnode));
這個語句,在函式體內修改了_tree的內容,將會導致引數tree的內容作相應的修改,因為它們指向相同的記憶體位址。而
_tree = (binnode *) malloc(sizeof(binnode));
這個句,系統重新分配記憶體給_tree指標,_tree指標指向了系統分配的新位址,函式體內修改的只是_tree的內容,對原tree所指的位址的內容沒有任何影響。因此,函式的引數是乙個指標時,不要在函式體內部改變指標所指的位址,那樣毫無作用,需要修改的只能是指標所指向的內容。即應當把指標當作常量。
如果非要使用函式指標來申請記憶體空間,那麼需要使用指向指標的指標
createnode(binnode **tree,char *p)
上面的是林銳的說法,目前來說不知道怎麼去理解,不過可以有另外的方案,通過函式返回值傳遞動態記憶體:
binnode *createnode()
這個倒還說得過去,因為函式返回的是乙個位址的值,該位址就是申請的記憶體塊首位址。但是,這個容易和另外的乙個忠告相混繞
[不要用return語句返回指向「棧記憶體」的指標,因為該內存在函式結束時自動消亡]
這裡區分一下靜態記憶體,棧記憶體和動態分配的記憶體(堆記憶體)的區別:
(1) 從靜態儲存區域分配。內存在程式編譯的時候就已經分配好,這塊內存在程式的整個執行期間都存在。例如全域性變數,static變數。
(2) 在棧上建立。在執行函式時,函式內區域性變數的儲存單元都可以在棧上建立,函式執行結束時這些儲存單元自動被釋放。棧記憶體分配運算內置於處理器的指令集中,效率很高,但是分配的記憶體容量有限。
(3) 從堆上分配,亦稱動態記憶體分配。程式在執行的時候用malloc或new申請任意多少的記憶體,程式設計師自己負責在何時用free或delete釋放記憶體。動態記憶體的生存期由我們決定,使用非常靈活,但問題也最多。
因此,試圖返回乙個棧上分配的記憶體將會引發未知錯誤
char *getstring(void)
p是在棧上分配的記憶體,函式結束後將會自動釋放,p指向的記憶體區域內容不是"hello world",而是未知的內容。
如果是返回靜態儲存的記憶體呢:
char *getstring(void)
這裡「hello world」是常量字串,位於靜態儲存區,它在程式生命期內恆定不變。無論什麼時候呼叫getstring,它返回的始終是同乙個「唯讀」的記憶體塊。
c指標點滴三(指標運算)
1 include 2 include 3 4void main3 512 13 void main4 14 24 system pause 25 26 27void main5 28 30int p5 a 2 31 printf d a 2 32 p5 p5 2 相當於在陣列內部向後移動兩個元素的...
C 0428 指標和空間分配
檔案 開啟檔案 ifstream 是用於讀取檔案的istream流,ofstream是用於寫檔案的ostream流,ost檢測檔案是否成功開啟。i o錯誤處理 good 操作成功 eof 到達輸入尾部 fail 發生某些意外情況 例如,我們要讀入乙個數字,卻讀入了字元 x bad 發生嚴重的意外 如...
C 學習歷程6 指標
int main 指標變數和普通變數的區別 int main 總結 所有指標型別在32位作業系統下是4個位元組 用途 初始化指標變數 切記不可訪問 int p null 訪問空指標報錯 記憶體編號0 255為系統占用記憶體,不允許使用者訪問 cout p endl 指標變數指向非法的記憶體空間 in...