c语言范式编程之swap
引言
C语言是一门古老的语言,没有C++语言的诸如模版、应用、面向对象的高级特性。对于数据的交换,只能使用指针来实现。在C语言中,一般使用如下的方法来实现两个整数的交换:
1: void swap(int *ap, int *bp)
2: {
3: int tmp = *ap;
4: int *ap = *bp;
5: *bp = tmp;
6: }
然后,使用如下方法来实现数据交换:
1: int x = 10;
2: int y = 15;
3:
4: swap(&x,&y);
至此,便完成了数据的交换。现假如有多个不同的类型的数据需要实现交换,在C++语言中使用模版简洁的实现了需要的功能。在C语言中,我们没有模版,可能只能为每个不同类型的数据写一个swap函数。但是当我们了解数据在内存中的表示时,我们很容易想到不同类型的数据交换的本质是相同的。
数据交换的本质简单介绍
一个简单的例子:
- 1: #include <stdio.h>
2: #include <stdlib.h>
3:
4: void swap(int *ap, int *bp)
5: {
6: int tmp = *ap;
7: *ap = *bp;
8: *bp = tmp;
9: }
10:
11: int main()
12: {
13: float fa = 10.0;
14: float fb = 20.0;
15: printf("fa = %f,fb = %f\n",fa,fb);
16: swap(&fa,&fb);
17: printf("after swap,fa = %f, fb = %f",fa,fb);
18: return 0;
19: }
由于sizeof(int)和sizeof(float)的结果是相同的,因此得到了正确地结果:
这似乎是投机取巧的,但是当了解数据在内存的表示时,可以发现其实不同类型的数据底层的操作是一样的,都是位模式(所谓的bit pattern)的交换。
实现
void 指针可以指向任意类型的数据(也可以指向void 指针),亦即可用任意数据类型的指针对void指针赋值。值得注意的是,并不能对void指针解引用,因为编译器不知道void指针指向的数据类型,也就没办法为其生成相应的代码(不同类型的数据的大小可能不同,可执行的操作也可能不同)。
1: #include <stdio.h>
2: #include <stdlib.h>
3: #include <string.h>
4:
5: void swap(void *vp1, void *vp2,int size)
6: {
7: char buf[size];
8: memcpy(buf,vp1,size);
9: memcpy(vp1,vp2,size);
10: memcpy(vp2,buf,size);
11: }
12:
13: int main()
14: {
15: float fa = 10.0;
16: float fb = 20.0;
17: printf("fa = %f,fb = %f\n",fa,fb);
18: swap(&fa,&fb,sizeof(float));
19: printf("after swap,fa = %f, fb = %f",fa,fb);
20: return 0;
21: }
结果:
可以看到,实现了范类型数据的交换。这样写乍看很丑,当理解了内存的位模式时,可以发现其实这段代码是十分优雅的。如果用C++的模版来实现,C++会为不同类型的数据生成对应的代码,当我们有很多不同类型的数据需要swap时,代码膨胀会非常的明显。而调用这个函数只生成一份代码,所有不同数据类型的swap都是调用同一份代码。当然,调用这个函数必须十分小心,因为void指针式通用类型的指针,这意味着,当在这个函数传入不同类型的数据时,编译器并不会报错,这个错误只能在运行时才能发现。
转载请注明出处,查看原文:http://wavelee.info/2013/05/02/c-language-programming-paradigm-swap/