內存地址
如果您在計算機硬件的層面上理解了內存地址的原理,前面的討論就會變得更加清晰了。您若還沒有閱讀過位和字節,那么現在應該去讀一遍這篇文章,它會幫您弄清位、字節和字的概念。
所有計算機都配有內存,也稱RAM(隨機存取存儲器)。比如您的計算機現在可能配有16、32或64兆字節的RAM。RAM用于存儲計算機正在執行的程序以及程序使用的數據(即程序的變量和數據結構)。內存可以看作是一個簡單的字節數組。在這個數組中,每個內存單元都有自己的地址:第一個字節的地址是0,后面依次是1、2、3,等等。內存地址相當于普通數組的下標。計算機可以隨時訪問內存的任何位置(所以稱為“隨機存取存儲器”)。根據需要,多個字節可以組合起來構成較大的變量、數組和結構體。例如,一個浮點型變量占用4個連續字節的內存空間。您可以像下面這樣在程序中聲明一個全局變量:
float f;
上面這條語句的意思是說:“聲明一個名為f的可以保存一個浮點值的內存位置。”程序執行的時候,計算機就會在內存中某個位置為變量f預留空間。這個位置在內存空間中有確定的地址,如下圖所示:
?

變量f在內存某處占用四個字節的空間。此位置有確定的地址,本例中是248,440。
您認為的變量f在計算機看來就是一個具體的內存地址(如248,440)。因此,當您寫下這樣的語句時:
f=3.14;
?
編譯器可能把它翻譯成:“將數值3.14裝入到內存地址是248,440的位置。”計算機總是通過操作地址和操作地址的值來使用內存的。
另外,計算機的這種使用內存的方式還會帶來一些“副作用”。例如,您的程序包含了下面的代碼:
int i, s[4], t[4], u=0; for (i=0; i<=4; i++) {s[i] = i;t[i] =i;} printf("s:tn"); for (i=0; i<=4; i++) printf("%d:%dn", s[i], t[i]); printf("u=%dn", u);
?
您很可能會看到這樣的程序輸出:
s:t 1:5 2:2 3:3 4:4 5:5 u=5
?
t[0]和u的值為什么不對?仔細觀察代碼就會發現,兩個for循環在訪問數組時都越界了一個元素。在內存中,兩個數組是相鄰存儲的,如下圖所示:
?
![]() |
?
因此,當向s[4]這個并不存在的數組元素寫數據時,實際上覆蓋了t[0],因為它正處于s[4]的位置上。當向t[4]寫數據時,實際上就覆蓋了u。對于計算機來說,s[4]只是一個可以寫數據的內存位置而已。您會發現盡管計算機執行了程序,但程序卻是不正確或不正常的。這個程序在運行時損壞了t 數組。執行下面的語句將會產生更加嚴重的后果:
s[1000000]=5;
?
s[1000000] 這個位置很可能在程序的內存空間之外。也就是說,您向不屬于您程序的內存空間寫入數據。在具備存儲空間保護的系統上(如UNIX和Windows 98/NT),這樣的語句會使系統終止程序的執行。而在其他系統(如Windows 3.1和早期的Mac)會聽任程序為所欲為。結果是另一個程序的代碼或變量被破壞了。這種侵犯的后果小到不產生任何影響,大到導致徹底的系統崩潰。在內存中,變量i、s、t、u具有前后相鄰的確定地址。因此,如果您對一個變量越界寫入,計算機會照您說的做,但將破壞另一處內存位置的數據。
因為C和C++在訪問數組元素時不做任何形式的邊界檢查,所以您作為一名程序員自己一定要嚴加注意數組邊界,不要超越。對超越數組邊界內容的無意讀寫總是會導致程序出現問題。
下面的代碼是另一個例子:
#includeint main() {int i,j;int *p; /* 指向整數的指針 */ printf("%d %d n", p, &i);p = &i;printf("%d %d n", p, &i);return 0;}
?
這段代碼告訴編譯器打印p保存的地址和i占用的地址。變量p一開始是一個隨意的數值或0。i的地址一般是一個很大的數字。例如,運行這段代碼后得到的輸出是:
0 2147478276 2147478276 2147478276
?
可知i的地址是2147478276。p=&i;這條語句執行之后,就保存了i的地址。再試試下面的代碼:
#includevoid main() {int *p; /* 指向整數的指針 */ printf("%d n",*p);}
?
這段代碼告訴編譯器打印p指向的值。然而p尚未初始化,它保存的地址是0或一個隨機地址。多數情況下這將引發一個段錯誤(或某些其他運行時錯誤),表明您使用了一個指向無效內存空間的指針。段錯誤幾乎總是由未初始化的指針或錯誤的內存地址導致的。
通過以上的介紹,現在我們可以從新的角度來理解指針了。請看下面的例子:
#include
int main()
{int i;int *p; /*
p = &i;*p=5;printf("%d %d
?
程序的運行過程是這樣的:
?
-變量i占4字節的內存。指針p也占4字節(在當今使用的多數計算機上,一個指針占4字節內存。現在大部分CPU的內存地址都是32位的,盡管64位尋址已漸成趨勢)。i所代表的內存位置有一個確定的地址,本例中是248,440。執行過p=&i;后,指針p也將保存同樣的地址。因此變量*p和i是等價的。
指針p原樣保存著i的地址。當執行如下的語句時:
printf("%d", p);
?
?
程序就會打印變量i的實際內存地址。
電子發燒友App














評論