今天总结两个不借助第三个变量实现两个值的交换的方法:
int main()
{
int a = 10;
int b = 20;
printf("%d,%d\n",a,b);
a += b;//a=30,b=20
b = a-b;//a=30,b=10;
a = a-b;//a=20,b=10
printf("%d,%d\n",a,b);
return 0;
}
int main()
{
int a = 10;
int b = 20;
printf("%d,%d\n",a,b);
a ^= b;
b ^= a;
a ^= b;
printf("%d,%d\n",a,b);
return 0;
}
今天主要聊聊第一个方法,因为可读性较强,并且听一些老师说,这个方法也被很多互联网公司作为面试题,但其实这个方法是有bug的,隐藏的很深,我们来分析分析。
#include <stdio.h>
void Swap_1(int *a,int *b)//不借助第三个变量实现的交换函数
{
*a += *b;
*b = *a - *b;
*a = *a - *b;
}
void Show(int *arr,int len)//打印输出数组函数
{
for(int i = 0; i < len; i ++)
{
printf("%d ",*(arr+i));
}
printf("\n");
}
void Reverse(int *c,int len)//逆置数组函数
{
for(int i=0,j=len-1;i<=j;i++,j--)
{
Swap_1(&c[i],&c[j]);
}
}
int main()
{
int brr[] = {1,2,3,4,5,6,7,8,9,10,11};//定义并赋初值一个长度为奇数的数组
Show(brr,sizeof(brr)/sizeof(brr[0]));
Reverse(brr,sizeof(brr)/sizeof(brr[0]));
Show(brr,sizeof(brr)/sizeof(brr[0]));
return 0;
}
这个程序很简单,首先定义了一个长度为奇数的数组并赋予初值,接着调用逆置函数,将数组元素逆置,最后通过打印输出函数,将数组元素依次输出。我们来看看结果:
乍一看,结果好像是正确的,实际上仔细观察,会发现最中间的数6变为了0,这个bug隐藏的很深,我们很难发现,我们再来调试找找原因:
当逆置函数的循环体走到长度为奇数的数组最中间(对于长度为11的数组来说,最中间是6,对应为brr[5]),调用交换函数,此时交换函数的指针变量a和b同时指向了brr[5]的地址,接着解引用,两个值相加:
接着再相减:
此时对应brr[5]的值就被修改为了0。
综上:我们得出结论,不借用第三个变量达到交换的函数,如果是用先相加,在相减,再相减的方法时,存在一个不易被发现的bug:若整体数组长度为奇数,则交换函数交换到最中间的时候,会使中间值变为0。从而使得数据错误。