C 程式設計點滴6 指標引數和記憶體分配

2021-04-26 10:05:13 字數 2728 閱讀 8718

當以指標作為引數,在函式中分配記憶體的時候,其操作要格外小心。

#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...