http://blog.csdn.net/norains/article/details/6746844
如何通過函數來改變傳入指針的指向?想必大家第一反應就是使用指向指針的指針作爲形參,也就是說會寫類似於Func_1的函數:
- void Func_1(DWORD **ppdw)
- {
- *ppdw = &g_dwVal;
- }
g_dwVal是一個全局變量,只要知道這個即可,其餘的暫時不用考慮。有了Func_1,那麼調用估計大家也會想到,無非是傳入一個指針,如:
- pBuf = NULL;
- Func_1(&pBuf);
如果你認爲這是C++通過函數改變指針指向的全部,那麼你就太小看它了。使用"DWORD **"能改變指針的指向,那是不是通過"DWORD *"就不行了呢?答案是否定的,形參爲"DWORD *"也可以改變指針指向!不過,這個函數的寫法就有所不同,如Func_2:
- void Func_2(DWORD *pdw)
- {
- *(reinterpret_cast<DWORD *>(pdw)) = reinterpret_cast<DWORD>(&g_dwVal);
- }
函數寫法不同,調用也要有所區別,如:
- pBuf = NULL;
- Func_2(reinterpret_cast<DWORD *>(&pBuf));
如果你測試過這段代碼,那麼會發現即使函數形參是"DWORD *",也可以改變指針的指向!
在這裏再稍微多說一點,Func_2的函數體,其實寫成這樣也是可以正常賦值的,如:
- void Func_2(DWORD *pdw)
- {
- *(reinterpret_cast<DWORD **>(pdw)) = &g_dwVal;
- }
我們再來看一個更加有趣的問題,如果指針的類型是BYTE,那麼是不是也能正常改變呢?所以,我們便有了一個Func_3函數:
- void Func_3(BYTE *pb)
- {
- *(reinterpret_cast<DWORD **>(pb)) = &g_dwVal;
- }
調用的時候,自然也是有所區別:
- pBuf = NULL;
- Func_3(reinterpret_cast<BYTE *>(&pBuf));
經過測試,這樣的方式也是能夠改變指針的指向的。估計看到這裏,應該不少朋友迷惑了,爲什麼呢?在回答這個問題之前,我們繼續再看另一個更有趣的問題,不通過指針,而是通過"DWORD"類型來改變指針的指向!於是,便有了函數Func_4:
- void Func_4(DWORD dwVal)
- {
- *(reinterpret_cast<DWORD *>(dwVal)) = reinterpret_cast<DWORD>(&g_dwVal);
- }
不用想,調用方式自然也是有區別,如:
- pBuf = NULL;
- Func_4(reinterpret_cast<DWORD>(&pBuf));
估計很多初學者看到這裏,應該已經兩眼發暈了吧?我們不妨看看爲何可以改變的真正原因。
要明白上述函數爲何能夠正常改變指向,那麼就必須明白指針的地址。對於指針的地址,它其實分爲兩部分,一部分是指針本身的地址,另一部分則是指針指向的地址。這樣說可能大家有點糊塗,不妨看如下的圖示:
如果是C++高手的話,那麼對於這張圖肯定是非常熟悉,但可能初學者就有點暈了。沒事,我們現在一起來看看。
假設有個指針,名爲pBuf。對於圖中的0x4000 0000來說,這是指針本身的地址,以代碼表示,便是&pBuf;而0x4000 0000這個內存地址存儲的0x8000 0000,便是指針指向的地址,代碼表示爲pBuf;至於0x1234 5678,不用說,就是0x8000 0000這個內存塊的數值了,代碼自然是*pBuf。根據這些內容,不難得出這個表:
地址/數值 |
代碼 |
0x4000 0000 |
&pBuf |
0x8000 0000 |
pBuf |
0x1234 5678 |
*pBuf |
還是以圖爲例子,如果要改變指針的指向的話,那麼只需要改變0x4000 0000這個內存裏面的數值即可。明白這點,對於之前的函數理解就沒什麼難度了。大家不妨回頭看看,其實在調用這些Func_x函數時,傳入的都是"&pBuf",也就是指針本身的地址。既然已經知道了指針本身的地址,那麼改變指針存儲的值還有什麼問題麼?函數所做的,只不過是一些轉換而已。
按理說,本文到此已經結束,但最後不妨再看一個初學者非常容易搞混的問題:空指針是否佔據內存空間?也就是說,下面這行代碼是否佔據內存空間:
- DWORD *pBuf = NULL;
答案是佔有空間!如果對此還有疑惑,那麼看了下面這張圖,相想必就非常明白了:
所謂的空指針,只不過是指向內存地址爲0x0000 0000的指針而已,和別的指針並沒有任何不同,所以肯定佔用空間。
這裏,應該還會有人迷惑,如果指向指針的指針爲空,那麼會不會佔用空間呢?也就是說下面這行代碼:
- DWORD **ppBuf = NULL;
答案還是佔用空間!指向指針的指針說白了,還是指針,既然是指針就有自己本身的地址,所以肯定佔用空間!所不同的是,指向指針的指針的存儲空間存儲的是所指向的指針的地址而已。如果以第一幅圖爲例子,稍微完善一下,那麼便有如下圖示:
最後,便是全部的代碼,以供大家參考:
- #include "windows.h"
- DWORD g_dwVal = 0x100;
- void Func_1(DWORD **ppdw)
- {
- *ppdw = &g_dwVal;
- }
- void Func_2(DWORD *pdw)
- {
- *(reinterpret_cast<DWORD **>(pdw)) = &g_dwVal;
- //*(reinterpret_cast<DWORD *>(pdw)) = reinterpret_cast<DWORD>(&g_dwVal);
- }
- void Func_3(BYTE *pb)
- {
- *(reinterpret_cast<DWORD **>(pb)) = &g_dwVal;
- }
- void Func_4(DWORD dwVal)
- {
- *(reinterpret_cast<DWORD *>(dwVal)) = reinterpret_cast<DWORD>(&g_dwVal);
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- DWORD *pBuf = NULL;
- pBuf = NULL;
- Func_1(&pBuf);
- pBuf = NULL;
- Func_2(reinterpret_cast<DWORD *>(&pBuf));
- pBuf = NULL;
- Func_3(reinterpret_cast<BYTE *>(&pBuf));
- pBuf = NULL;
- Func_4(reinterpret_cast<DWORD>(&pBuf));
- return 0;
- }