2

I typed these code. However, the output is beyond my expectations.

#define SWAP(x,y) {x=x^y;y=x^y;x=x^y;}
#define SWAP2(x,y) {x=x+y;y=x-y;x=x-y;}
int main()
{
    int ia[] = { 1, 10, 1 };
    SWAP(ia[0], ia[0]);   // the resutl is ia[0] = 0
    SWAP(ia[1], ia[2]);   // work fine
    SWAP2(ia[1], ia[1])   // the result is ia[0] = 0    
}

Anyone can help me? Any help will be appreciated.

Violet Giraffe
  • 32,368
  • 48
  • 194
  • 335
Graywd
  • 31
  • 3
  • 2
    Why are you swapping an array item with itself? – Violet Giraffe Sep 18 '16 at 05:27
  • 2
    Why would use use a macro for this? – shuttle87 Sep 18 '16 at 05:28
  • 2
    Why write confusing code? Macros are hard to debug. Best to avoid. Anyway C++ has `std::swap` – Ed Heal Sep 18 '16 at 05:34
  • 1
    @VioletGiraffe Presumably to test the swap implementation, or in a context that doesn't know they're the same. – Kyle Strand Sep 18 '16 at 05:39
  • @shuttle87 The xor trick is a classic in-place swap algorithm that doesn't require a third memory space. It's confusing to read, though, so it should be hidden somehow, and a function would need to be inlined (which is never guaranteed) in order to preserve that feature. – Kyle Strand Sep 18 '16 at 05:42
  • @EdHeal C++11/14/1z do, yes, but not all projects have up-to-date compilers or enable modern settings. – Kyle Strand Sep 18 '16 at 05:43
  • @KyleStrand - If not available - quite easy to write. – Ed Heal Sep 18 '16 at 05:48
  • Read the [Wikipedia page](https://en.wikipedia.org/wiki/XOR_swap_algorithm). It explains why you can't use XOR to swap a variable with itself. – Barmar Sep 18 '16 at 05:58
  • 1
    @EdHeal Well, obviously not, or OP presumably would have gotten it right! – Kyle Strand Sep 18 '16 at 06:05
  • 1
    @Graywd - You might also want to read [Swapping two variable values without using 3rd variable](http://stackoverflow.com/questions/1826159/swapping-two-variable-value-without-using-3rd-variable) to see that your code not only fails sometimes, but also runs a lot slower than code using a temp variable. – Bo Persson Sep 18 '16 at 11:28

3 Answers3

4

Your problem is that your swap algorithms require the two arguments to be separate pieces of memory.

As noted by LYF_HKN, the first step in each algorithm causes x to become 0 when x=y. If the two are merely equal but are still separate pieces of memory, this is fine, because the second step will leave y unchanged (because x is 0), and the third step will restore the original value of x if y is now equal to that original value.

However, when x and y are actually the same object in memory, then the first operation in each algorithm, in setting x to 0, also sets y to 0, since y is x. Thus the rest of each algorithm merely preserves the value 0 in this memory space.

Kyle Strand
  • 15,941
  • 8
  • 72
  • 167
3

The first SWAP:

ia[0] = ia[0] ^ ia[0];
ia[0] = ia[0] ^ ia[0];
ia[0] = ia[0] ^ ia[0];

Well, any value XOR'd with itself gives zero. That's why the first SWAP result in ia[0] becoming zero. The second one is fine, so I will skip it and jump into the third one.

ia[1] = ia[1] + ia[1];
ia[1] = ia[1] - ia[1];
ia[1] = ia[1] - ia[1];

What is the result of ia[1] - ia[1]? Always zero regardless of the value of ia[1].

DDMC
  • 396
  • 2
  • 11
  • 1
    Yes, any value xor'd with itself is 0, but that's not where the algorithm ends. Same for the second algorithm. And algorithmically, there's no distinction here between using a macro and using a function. – Kyle Strand Sep 18 '16 at 05:45
  • Yes, my mistake, sorry. It still refers to the same variable and leads to the same result. – DDMC Sep 18 '16 at 05:50
2

The first SWAP is called XOR swap, it can swap two different variables without a temp variable. However, the two variables must have different addresses. That's the reason SWAP(ia[0], ia[0]); fails, but SWAP(ia[1], ia[2]); works fine.

The second SWAP2 is dangerous, since x+y might overflow. And you should not use that one.

To make the XOR swap work, you need to some modification:

void swap(int &x, int &y) {
    if (&x != &y) {
        x ^= y;
        y ^= x;
        x ^= y;
    }
}
for_stack
  • 21,012
  • 4
  • 35
  • 48
  • Call your `swap` like this: `int a = 42, b = 42; swap(a, b);` and observe. – Daniel Jour Sep 18 '16 at 05:58
  • If you are going to write a function, why not just do it properly without the rigmarole of XOR? – Ed Heal Sep 18 '16 at 06:19
  • 1
    @EdHeal Whether it's a function or macro is not OP's question. Whether `std::swap` is better than XOR swap is not OP's question either. I'm just trying to explain why he didn't get what's he expected, and how to fix it. – for_stack Sep 18 '16 at 06:31