实现两个值的交换(不借助第三个变量)

今天总结两个不借助第三个变量实现两个值的交换的方法:

  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。从而使得数据错误。

猜你喜欢

转载自blog.csdn.net/m0_46308273/article/details/104999739