最近對C/C++指針特別感冒,就詳細的研究了下
看下面的定義:
char a[] = "Hello World";
char *p = "Hello World";
1.什麼是地址
地址本身就是一種基本數據類型,它跟整數,浮點數,字符等基本類型是一樣的。指針不是類型,真正的類型是地址,指針只不過是存儲地址這種數據類型的變量。
打個比方,對於
int i=10;
10是整數,而i是存儲整數的變量,指針就好比這個i,地址就好比那個10。指針能夠進行加減法,原因並不是因為它是指針,加減法則不是屬於指針這種變量的,而是地址這種數據類型的本能,正是因為地址具有加減的能力,所以才使指針作為存放地址的變量能夠進行加減運算。這跟整數變量因為整數能夠進行加減乘除因而它也能進行加減乘除一個道理。
2.什麼是指針
指針本身就是一個變量,它跟其他的變量是一樣的。指針本身是一個符號。
比如 int *p,我們定義了一個指針p,編譯器就會在內存分配一個2(32位系統是4個字節)字節的存儲空間。我們在使用p的時候,p的值就是剛剛所分配的存儲空間中所存的內容。再來看看變量,我們定義int a = 10,a是一個變量名。我們在使用a的時候,用的是a所對應的存儲空間的內容。a本身可以理解為就是一個符號,它跟某個存儲空間相對應。&a就是取a所對應的存儲空間的地址。這樣,指針也是變量,本身也是一個符號,在使用p的時候,我們使用的是p這個變量所對應的存儲空間的內容,而這個存儲空間的內容有些特別,它不是整數,也不是浮點數,而是一個地址類型的數據。那麼&p是什麼意義呢,&p就是指p所對應的存儲空間的地址(這個地址可不是p所對應的存儲空間的內容哦)。那麼*p怎麼理解呢?記住在使用時,p的值是所對應的存儲空間的內容,那麼*p自然就是取出那個地址所對應的存儲空間的內容了。
3.什麼是數組名
數組名:就是一個數,這個數和整數,浮點數類似,是一個地址類型的數據。就像int a = 10;這裡的10就是一個整數,它跟地址類型數據屬於一個層次。也就是說數組名跟整數10是相似的,而跟a差距大多了,根本不是一個概念.應該說數組名與&a是一樣的,都是一個地址數據,同時數組名還是一個常量常量,地址常量。
用來存放數組的區域是一塊在棧中靜態分配的內存(非static),而數組名是這塊內存的代表,它被定義為這塊內存的首地址。這就說明了數組名是一個地址,而且,還是一個不可修改的常量,完整地說,就是一個地址常量。數組名跟枚舉常量類似,都屬於符號常量。數組名這個符號,就代表了那塊內存的首地址。注意了!不是數組名這個符號的值是那塊內存的首地址,而是數組名這個符號本身就代表了首地址這個地址值,它就是這個地址,這就是數組名屬於符號常量的意義所在。由於數組名是一種符號常量,因此它是一個右值,而指針,作為變量,卻是一個左值,一個右值永遠都不會是左值,那麼,數組名永遠都不會是指針!
4.再來討論開頭我們所定義的字符數組和字符串指針的區別
我們假定這兩個定義是在同一個函數中的(如main)。
繼續:*(a+1) =u;
*(p+1) = u
這裡第一個操作會通過,而第二個操作則會出現段錯誤。這是什麼原因呢?那麼我們需要了解下,程序空間分配中存儲區問題。C/C++程序所對應的存儲區,分位三類
1.靜態存儲區:內存在程序編譯的時候就已經分配好,這塊內存在程序的整個運行期間 都存在。它主要存放靜態數據、全局數據和常量。
2.棧區:在執行函數時,函數內局部變量的存儲單元都可以在棧上創建,函數執行結束 時這些存儲單元自動被釋放。棧內存分配運算內置於處理器的指令集中,效率很高,但是分配的內存容量有限。
3.堆區:亦稱動態內存分配。程序在運行的時候用malloc或new申請任意大小的內存,程序員自己負責在適當的時候用free或delete釋放內存。
這裡char a[] = "Hello World",其空間是分配在棧中的,所以你可以對其中的內容進行修改。而char *p = “Hello World”,其空間是分配在靜態存儲區的。且Hello world為字符串常量,是不允許修改的。