指針加減法運算的“定義域”


  指針變量加(減)一個整數。

  例如:p++,p--,p+i,p-i,p+=i,p-=i等均是指針變量加(減)一個整數。

  將該指針變量的原值(是一個地址)和它指向的變量所占用的存儲單元的字節數相加(減)。

    ————譚浩強 ,《C程序設計》(第四版),清華大學出版社,2010年6月,p290

  在C語言中,任何運算都有前提條件。脫離了前提談運算是荒謬的。 

  比如,一元“*”運算,其運算對象必須是非void *類型的指針。如果對一個int類型的數據或unsigned類型的數據做一元“*”運算,連編譯都無法通過(這也間接說明了指針並非是一個32位無符號整數。參見§246)。 

  再比如,兩個int類型數據相加,其前提條件是結果必須在int類型可以表示的范圍之內,否則就成了一種未定義行為(undefined behavior)。 

  指針運算也是如此。並非所有的指針類型數據都有加(減)法運算。C語言並沒有定義void *類型指針或指向函數的指針的加減法運算。換言之,指針的加減法運算只對那些指向數據對象(Object)類型的指針才可能有意義。比如:int *類型的指針可以做加減法運算。

  指向數據對象類型的指針的加減法運算並沒有限制運算對象是左值(lvalue)或可修改的左值(modifiable lvalue),用一句通俗的話來說,就是任何指向數據對象類型的指針類型的表達式都可能可以與一個整數做加減法運算。比如,對於代碼片段

int i=2;
printf("%p\n",&i +1);

 來說,其中的 &i 就不是指針變量,但&i+1這個運算完全合法,因為&i是一個int *類型的表達式,它在一定條件下可以與一個int類型的數據做加法運算。

  但是,即使是指向數據對象類型的指針,也不是無條件地可以進行加減法運算。譬如,前面代碼片段中的&i,就不可以做減法運算,也不可以與0或1以外的其他非負整數做減法運算。否則,沒有人能保證會得到什么樣的結果,因為這是一種未定義行為(undefined  behavior)。

  指針與一個整數類型數據做加減法運算,除了要求必須是指向數據對象的指針之外,還要求這個指針必須是指向某個數組元素的指針(單個的數據對象可以視為具有一個元素的數組,如前面的i),或指向這個數組最后一個元素之后第一個元素的指針。這話說起來有點繞,下面用一個具體的例子來說明。對於

double a[5];

來說,只有當指針的值為a、a+1、a+2、a+3、a+4、a+5時,指針與一個整數的加減法才可能有意義。其中的a+5就是指向a數組最后一個元素之后第一個元素的指針。

  不僅如此,對與指針進行加減法運算的整數也有確定且苛刻的要求。這個要求就是,這些整數必須能保證運算的結果依然指向這個數組中的各個元素或者指向這個數組最后一個元素之后的第一個元素。

  可以指向數組元素,可以指向數組最后一個元素之后第一個元素,但絕對不可以指向數組之前的元素(即a-1是不可以的),這個性質被有些人形象地稱為“左閉右開”。

  同樣,兩個指針的減法也是有前提條件。這個前提條件就是要求兩個指針必須是指向同一數組元素或者指向數組元素最后一個元素之后的第一個元素,只有在這種情況下,兩個指針的減法運算才有意義。據此,不難看出下面陳述中的錯誤之所在。

  兩個指針變量可以相減。

  如果兩個指針變量都指向同一數組元素,則兩個指針變量值之差是兩個指針之間的元素個數。

————譚浩強 ,《C程序設計》(第四版),清華大學出版社,2010年6月,p290

  這段陳述有兩個主要錯誤。首先它把指針與指針變量混為一談,事實上並非兩個指針變量才可以相減;其次它把可以進行相減運算的指針的范圍縮小了。如果一個指針指向某數組之后的第一個元素,它同樣也可以進行指針減法運算。 

  特別值得指出的是,兩個指針相減得到的值可能並非是int類型。C標准規定,兩個指針相減的類型是ptrdiff_t類型,這個類型在stddef.h中定義,在許多編譯器上,這個類型是long int類型。 

  那么,不了解指針加減法運算有什么危害嗎? 

  答案是顯然的。忽視指針加減法運算的前提寫出的表達中很可能是錯誤的表達式,這種錯誤往往無法依靠編譯器的語法檢查檢測出來,因為這種錯誤屬於C語言的未定義行為,編譯器有時無法檢測出這種錯誤。這個道理就如同編譯器無法檢測出代碼中存在數組越界一樣。更為嚴重的是,這種錯誤可能並不會立刻表現出來,在程序運行時經常“顯得”很正常。程序員們都知道,這種不定時發作的錯誤才是最可怕的,因為它能讓你防不勝防,而且這種錯誤很難查找。 

  所以,在寫有關指針加減法的代碼時,一定特別要注意運算的前提條件,切忌想當然。而作為教材,也應該交代清楚這些運算的前提條件。 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM