1. 程式人生 > >用異或進行兩個數交換的陷阱

用異或進行兩個數交換的陷阱

我們都知道可用通過異或運算交換兩個數,而不需要任何的中間變數。 如下面:

  1. void exchange(int &a, int &b)
  2. {
  3.     a ^= b;
  4.     b ^= a;
  5.     a ^= b;
  6. }

然而,這裡面卻存在著一個非常隱蔽的陷阱。

通常我們在對陣列進行操作的時候,會交換陣列中的兩個元素,如exchang(&a[i], &b[j]), 這兒如果i==j了(這種情況是很可能發生的),得到的結果就並非我們所期望的。

  1. void main() 
  2. {
  3.    int a[2] = {1, 2};
  4.    exchange(a[0], a[1]); //交換a[0]和a[1]的值

  5.    printf("1---a[0]=%d a[1]=%d\n", a[0], a[1]);
  6.    exchange(a[0], a[0]); //將a[0]與自己進行交換
  7.    printf("2---a[0]=%d a[1]=%d\n", a[0], a[1]);
  8. }
 上面那段測試程式碼的輸出是:
  1. 1---a[0]=2 a[1]=1
  2. 2---a[0]=0 a[1]=1
很意外吧,第一次的交換正確的執行了,但是第二次呼叫exchange的時候卻將a[0]置為了0. 仔細分析,不難發現,這正是我們在exchange裡面用異或實現交換所造成的。如果輸入a和b是同一個數,exchange裡面程式碼相當於:

  1. a ^=
     a;
  2. a ^= a;
  3. a ^= a;
成了a做了3次於自己的異或,其結果當然是0了。

既然這樣,我們就不能夠在任何使用交換的地方採用異或了,即使要用,也一定要在交換之前判斷兩個數是否已經相等了,如下:

  1.     void exchange(int &a, int &b)
  2.     {
  3.         if(== b) return; //防止&a,&b指向同一個地址;那樣結果會錯誤。
  4.         a ^= b;
  5.         b ^= a;
  6.         a ^= b;
  7.     }