基本解釋
通過上一篇的分析,我們已經很清楚地知道:指標不是一個簡單的類型,它是一個本身和所指向物相複合的類型。指標的算術運算(如步進)與指標所指向物的類型密切相關。
問題:指標步進 & 步進單位
下面的代碼中列印出的結果是幾?
int arContext[5] ={0,1,2,3,4}, i, *pAr; pAr = arContext; printf ("%d\n", *(pAr + 3 * sizeof (int))); |
答案與分析:
這段代碼沒有正確答案,因為這段代碼是錯的,printf將打出無法預測的記憶體區的值,其中的原因如下:
在C語言中,指標總是按照它所指向的對象的大小步進。在上面的例子中,pAr是指向整數類型變數的指標,一個整數是4個位元組(預設CPU字長是32位),pAr + 1就指向下一個整數,也就是指標後移4個位元組,而不是說將地址只移動一個位元組。
因為C語言編譯器知道每個指標的類型,因此對指標的運算是會自動把所指類型的Size考慮進去的。
pAr + 3 * sizeof (int) = pAr + 3 * 4 = pAr + 12 ,因此pAr指向了數組的第13個整數元素。而數組本身才5個元素,pAr早已經超出了界限,所指向的地方當然就是無人可知道的東西了,具體指向什麼東西,各種不同的編譯器互不相同。總之,肯定不能列印出我們想要的值就是了。
指標不是一個簡單的類型,它是一個和指標所指物的類型相複合的類型。因此,它的算術運算與指標所指物的類型密切相關,在C++語言中也是同樣。
再比如下面的例子:
int a[8]; int* p = a; int* q = p + 3; p++; |
指標的加減並不是指標本身的二進位表示加減,要記住,指標是一個元素的地址,它每加一次,就指向下一個元素。所以:
q指向從p開始的第三個整數。
p++;
p指向下一個整數。
問題:指標步進 & 步進單位轉換
我有一個char *類型的指標,恰好指向了一個int類型的值,我想讓這個指標跳過int指向下一個char,下面的代碼可以達到這個目的嗎?
答案與分析:
可以。
首先我們要清楚C語言中左值和右值的概念,C語言中左值是指可以放在“=”左側,即可以被賦值,右值是可以放在“=”的右邊,即可以賦給其它變數的值。++是單目操作符,它將一個變數的值加1然後再賦給這個變數,因此它需要的運算元應該既可以放在“=”號的左邊,也可以放在“=”的右邊。原則上講,類型強制轉換的結果是右值而不是左值。所以,(int *)p的結果在這個運算式中是++的右值,而++的左值依舊是p,而不是(int *)p。
這個問題的核心正是告訴我們類型強制轉換的結果是右值而不是左值。
另外,我們可以使用一個簡單的辦法達到相同的目的:
p是char *類型的指標,它的步進長度是1,加上一個整數所佔的長度,就是跳過了一個整數所佔的空間。
所以,有時候,ULONG *p; 想要增加8個位元組,可以作如下強制轉換:
問題:指標步進 & void 指標
為什麼我對void *類型的指標進行運算,編譯器會報告如下錯誤?
error C2036: 'void *' : unknown size |
答案與分析:
在C語言中,所有的指標遠算,例如+、—、*、/,都是將它所指向的對象的尺寸考慮進取的。例如‘char*’ 類型的指標加1,就是地址向後移動一個位元組;而‘int*’類型指標加1,就是移動4個位元組。但是,對於‘void*’型的指標呢?‘void *’指標在C標準中被規定可以強制轉換成任何類型的指標而不會遺失資料,它的大小具體的編譯器各不相同,也就是說,編譯器也不知道void到底有多大,因此,無法對‘void*’類型的指標進行算術運算。