C/C++:在不使用第三个变量的情况下实现两个变量的交换

这是HTC笔试中碰到的一个很基础的题,可是波儿大人竟然不会做,可见波儿大人是有多水!知耻后勇,好生搜罗学习了一番。

下面的三种实现方法均来自小兵同学的文章《C语言实现交换两个数》,另外分别附加了俺的一丁点儿讲解笔记。

和差差法

void exchange(int *a, int *b)
{
	*a = *a + *b;
	*b = *a - *b;
	*a = *a - *b;
}

最简单最易理解也最精妙!

异或位运算法

void exchange(int *a, int *b)
{
	*a ^= *b;
	*b ^= *a;
	*a ^= *b;
}

更简练地,可写成:

*a ^= *b^= *a ^= *b;

还不了解异或位运算的同学可看完下面这几段,跟俺一起脑补一下。大侠请绕过。
异或(exclusive OR)是数学上的一种逻辑运算,数学符号为“⊕”。缩写xor,也是计算机中常用的表示符号。但在C/C++语言中,用^表示异或位运算符。运算规则是:1^0=1, 1^1=0, 0^0=0。也就是半加运算,是相加不进位的二进制加法。所谓“异或”,就是位按逻辑或运算为真、且两数不相同时结果才为真。
异或算符最经典的用法是将一个数其中的几位按位取反,而其它位又保持不变。如将变量x的最后3位按位取反,而前面的位不变,则可用x=07^x。

回到正题。要理解上面的异或运算为什么能交换两个数,还须知道异或运算的如下四条性质 [1]
(1)任意一个变量X与其自身进行异或运算,结果为0,即X^X=0;
(2)任意一个变量X与0进行异或运算,结果不变,即X^0=X;
(3)异或运算具有可交换性,即a^b=b^a;
(4)异或运算具有可结合性,即a^b^c=(a^b)^c=a^(b^c);//可从0和1中任抽3个成不同组合穷举验证。

那么,上面的语句完整写出即是:

*a1 = *a^*b;

*b1 = *b^*a1 = *b^(*a^*b) = *a^(*b^*b) = *a^0 = *a;

*a2 = *a1^*b1 = (*a^*b)^*a = *b^(*a^*a) = *b^0 = *b;

本质跟“和差差”法一样,都是先把两变量的总体信息保留在其中一个变量中,然后用该总变量信息结合那个还存在的分变量信息分别解析出原来的两个分量并实现交换赋值。区别是“和差差法”是通过加减运算“融合”->“拆解”,而“异或位运算法”则是通过异或运算。


内联汇编法

For Microsoft

//Microsoft C++:
int x = 12, y= 19;
_asm
{
    push x; 
    push y; 
    pop x; 
    pop y; 
} 
printf("x is %d, y is %d /n", x,y);
内联汇编即是在C/C++代码中插入汇编语言的语法片段,片段通常由asm关键字后接一对括号语句段来插入。上面的 _asm [2]是该关键字的Microsoft C++版本,在Linux C++中或者说gcc/GNU中与它对应的则是 __asm__ 或者 asm。下面是俺尝试编写的交换两变量的相应Linux汇编版本:

For Linux

//Linux C++:
#include <stdio.h>
  
int main()
{
  int x = 12, y= 19; 
  asm(
  "push x\n\t"
  "push y\n\t"
  "pop x\n\t"
  "pop y\n\t"
  );  
  printf("x is %d, y is %d /n", x,y);
  return 0;
}
需要说明的是该Linux版目前暂未能通过gcc的编译。编译报错为:

$ gcc asm.C -o asm
/tmp/user/ccKNLY8z.o(.text+0x2c): In function `main':
: undefined reference to `x'
…
俺真心不会汇编,临时抱佛脚照猫画虎 [3]。大侠路过还盼指点!


参考资料

[0]  小兵, C语言实现交换两个数

[1]  jocks, 为什么异或运算可以实现两个整数的交换,而无需借助第3个临时变量

[2]  MS Developer Network, __asm

[3]  dolinux, c内联汇编


  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值