交換兩個變量的值,最多見的寫法是html
int i , j ; int temp ; temp = i ; i = j ; j = temp ;
這種寫法相信任何學過程序設計語言的都知道。java
然而有些着三不着兩的極品面試官卻喜歡追問,不用中間變量應該怎麼寫?這一追問沒關係,追出了不少邪門歪道,例如面試
int i , j ; i = i + j; j = i - j ; i = i - j ;
這樣的寫法,很是晦澀,但擋不住這樣寫的人爲少定義了一個變量而洋洋得意。然而這樣寫真的行得通嗎?運行一下下面的代碼就明白了。 算法
#include <stdio.h> #include <limits.h> int main( void ) { int i , j ; int temp ; i = INT_MAX ; j = INT_MAX - 1; puts("交換前:"); printf("i = %d , j = %d \n" , i , j ); temp = i ; i = j ; j = temp ; puts("交換後:"); printf("i = %d , j = %d \n" , i , j ); i = INT_MAX ; j = INT_MAX - 1; puts("交換前:"); printf("i = %d , j = %d \n" , i , j ); i = i + j ; j = i - j ; i = i - j ; puts("交換後:"); printf("i = %d , j = %d \n" , i , j ); return 0; }
運行結果一般都是荒誕不經的。緣由很簡單, 計算 i + j 時發生溢出,而溢出在C語言中是一種未定義行爲,因此獲得什麼樣的荒誕結果都不奇怪。函數
更極品的回答是用乘除法。 post
i = i * j; j = i / j; i = i / j;
這不明擺着更容易溢出嗎?甚至會發生除以0的錯誤。可竟然還有人認爲「其實否則」,「不會溢出」。嚴重懷疑這是三鹿奶粉喝多了的後遺症。url
有的面試官可能自覺得本身還沒愚蠢到這種程度,由於他心目中的「標準答案」是經過異或運算。spa
i ^= j; j ^= i; i ^= j;
這種寫法雖然不會產生溢出,但使用條件受限,由於只能用於整數類型,浮點類型、結構體類型等徹底不適用。並且除了少用了一個臨時變量,沒有其餘任何好處。設計
有些人天真地覺得這種寫法對於整數類型變量來講會更快,其實這種猜想毫無根據。很難說異或運算就比賦值快,據一份公開發表的數據,在某環境下,異或用時爲0.050μs,而賦值運算只用0.036μs。指針
就可讀性而言,異或寫法顯然如同蝌蚪文天書。
更有極品將異或寫法發揮到了極限:
i ^= j ^= i ^= j;
對於C語言來講,這種寫法大錯特錯。由於C語言規定在兩個序點之間同一個數據對象最多隻能改變一次,不然就是未定義行爲。(參見 「牙里長嘴」和「a+=a-=a*a」 )這種代碼壓根就不能夠寫。若是運行結果碰巧正確,那麼只是瞎貓碰上死耗子而已。何況已有報告稱在某些環境下這種寫法的運行結果是錯誤的。
異或寫法還有一個潛在的問題,好比
#include <stdio.h> void swap( int * , int * ); int main( void ) { int i = 5 , j = 10 ; puts("交換前:"); printf("i = %d , j = %d \n" , i , j ); swap( & i , & j); puts("交換後:"); printf("i = %d , j = %d \n" , i , j ); //本身和本身交換 puts("交換前:"); printf("i = %d\n" , i ); swap( & i , & i); puts("交換後:"); printf("i = %d\n" , i ); return 0; } void swap( int * p , int * q ) { * p ^= * q ; * q ^= * p ; * p ^= * q ; }
這段代碼運行的結果是:
交換前:
i = 5 , j = 10
交換後:
i = 10 , j = 5
交換前:
i = 10
交換後:
i = 0
不難發現,若是swap()函數的兩個實參爲指向同一數據對象的指針時,結果是錯誤的。
固然,你可能認爲本身和本身交換有些無聊。但咱們不能排除有些算法可能存在這種交換的可能性。
除了這種可能性,還有另一種可能性,那就是你把代碼寫錯了,多寫了一次沒必要要的變量本身和本身的交換。若是你用的是使用中間變量的算法,那麼除了代碼有瑕疵,運行結果的正確性仍是有保證的。但若是你用的是異或的辦法,軟件災難則是召之即來——保準比打車來的還快。
因此結論就是,不要用異或的辦法交換變量值。
寫到這裏,本應打住。不過偶然興起,心血來潮,隨手一搜,竟發現還有更多的奇葩寫法。
某java-er居然一本正經地提出下面兩種方法:
a = a + b - (b = a);
b = a + (a = b)*0;
我不清楚在java裏這是否成立,但在C語言中,這都屬於未定義行爲。使人拍案的是,該java-er居然洋洋得意地寫到:
"這是java語言寫的,可是語言不分種類,任何方法都是通用的,推薦使用a=b+(b=a)*0和a^b的方法,有些環境也許會不經過,可是方法和思想不會錯得"
SHIT!