最近在学习数据结构和算法,发现使用到swap()函数,于是重新看了一下swap函数的各种实现,发现我对函数实参和形参理解不够透彻,现在分享我对swap的一些见解。
void swap(int *a,int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}
而以下两种是不能实现交换的:
void swap1(int a,int b)
{
int temp;
temp=a;
a=b;
b=temp;
}
void swap2(int *a,int *b)
{
int *temp;
temp=a;
a=b;
b=temp;
}
对于swap1,不能实现交换的理由是,C语言中函数的传的是形参,也就是一个副本,虽然在函数内体内交换了,但对真实的数据没影响。就如以下代码:
{
int a=1,b=2;
int ta=a,tb=b;
int temp;
temp=ta;
ta=tb;
tb=temp;
}
a和b并没有因此交换,交换的只是编译器自动生成的临时变量ta(形参)和tb!
而对于swap2,执行过程如下代码:
{
int a=1,b=2;
int *ta=&a,*tb=&b;
int *temp;
temp=ta;
ta=tb;
tb=temp;
}
printf(“a=%d,b=%d”,a,b);
pirintf(“a’=%d,b’=%d\n”,*ta,*tb);可以看到交换了由副本指向的内容,但a,b内容不会变,即原本是ta指向a(ta = &a),tb指向b(tb = &b),交换后,变为ta指向b(ta = &b),tb指向a(tb = &a),相当于换一个指针变量指向a、b的地址,对a和b的值并无影响。
而
void swap3(char **a,char**b)
{
char *temp;
temp=*b;
*b=*a;
*a=temp;
}
//使用如下方式调用:
char *pa=&a,*pb=&b;
swap1(&pa,&pb);
调用前和调用后分别打印printf(“a=%d,b=%d,a’=%x,b’=%x\n”,a,b,&a,&b);可以看到:并没有交换a和b由编译器分配的地址,交换的是指针pa和pb的值,所以a和b的值还是没变。其实跟上面的swap2()函数很类似,不同的是swap2()交换的是由编译器为实现函数形参功能而隐式生成的临时指针变量ta和tb,swap3函数则是交换调用swap3前显式定义好的指针变量pa和pb。
最后关于C语言的泛型编程,上面的swap()只能处理整型变量,但我们需要同时可以处理char、double、long型的变量,我们可以使用void*和size_t这些类型来达到。如下
void swap(void *a,void *b,size_t size)
{
char *p1=(char *)a;
char *p2=(char *)b;
char temp;
while(size--)
{
temp=*p1;
*p1=*p2;
*p2=temp;
p1++;
p2++;
}
}
使用这样的形式调用:
int c = 1000;
int d = -18;
swap(&c,&d,sizeof(int));
或
float a = -4.6;
float b = -2.1;
swap(&a,&b,sizeof(float));
等
但要注意的是彼此之间应该是同种类型,否则会出现错误的结果或内存越界。
void swap(int &a, int &b)
{
//方法一:
int tmp = 0;
tmp = b;
b = a;
a = tmp;
//方法二:
//a = a+b;
//b = a-b;
//a = a -b;
//方法三:
//a ^= b ^= a ^= b;
//方法四:
//a = a+b-(b=a);
}
int main(void) //下面这一部分是swap的实现,上面几种方法是对swap的定义
{
int a = 3;
int b = 4;
printf("before swap: a = %d, b = %d\n", a, b);
swap(a, b);
printf("after swap: a = %d, b = %d\n", a, b);
return 0;
}
结果
before swap: a = 3, b = 4
after swap: a = 4, b = 3