第四讲
继续看swap函数:
void swap (void *vp1, void *vp2) {
void temp = *vp1;
*vp1 = *vp2;
*vp2 = temp;
}
当然没有void类型变量,因为void类型的话,机器不知道要分配多大的内存给它,所以temp对*vp1的解引是有问题的
void swap (void *vp1, void *vp2, int size) {
char buffer[size];
memcpy(buffer, vp1, size);
memcpy(vp1, vp2, size);
memcpy(vp2, buffer, size);
}
上面这段代码实现了一般类型的swap函数,char buffer[size]是为了进行位模式的拷贝,一般的ansi c编译器不允许将一个非常数值size传进函数,
这里的buffer[size]是一个temp,存储在堆中,函数结束后也会将其释放,是一个动态申请和释放的临时存储区。
int x = 17, y = 37;
swap(&x, &y, sizeof(int));
double d = 3.1415926, e = 2.71828;
swap(&d, &e, sizeof(double));
cout << "x:" << x << ", y:" << y << endl;
cout << "d:" << d << ", e:" << e << endl;
运行结果:
这两个调用在编译过程中生成的汇编代码是一样的,再根据扩展确定是int还是double的swap。
int i = 44;
short s = 5;
swap(&i, &s, sizeof(short));
cout << "i:" << i << ", s:" << s << endl;
这里,结合之前的知识,应该知道是怎么进行交换的,在大端机器中肯定会出问题,在小端机器可能会完成功能,但是仍然有bug的,如果int数值存储区需要2字节以上,那么高地址的就会无法交换,产生bug。
运行结果:
char *husband = strdup("Fred");
char *wife = strdup("Wilma");
swap(&husband, &wife, sizeof(char*));
cout << "husband:" << husband << ", wife:" << wife << endl;
这里其实交换的是husband和wife两个char*指针所指向的内存区,并不是交换内存区中存储的数据。
最终是husband指向了Wilma的堆区,wife指向Fred的堆区。
运行结果:
比较下面这段代码:
char *husband = strdup("Fred");
char *wife = strdup("Wilma");
swap(husband, wife, sizeof(char*));
cout << "husband:" << husband << ", wife:" << wife << endl;
其中swap传入的husband和wife并不是地址,那么char*是4byte,机器就会执行对这两个字符串的4byte数据交换,
结果就是:
两个字符串只交换了4byte的数据。
sizeof(char****)这种也是可以的,因为指针类型大小都是4byte。
查找
下面是一个简单的线性查找算法:
int lsearch(int key, int array[], int size) {
for (int i = 0; i < size; i++) {
if (array[i] == key) {
return i;
}
}
return -1;
}
这里array[i] == key,实际上是比较两者所在内存的位层次上的4byte布局是否一致
那么根据这个思想,如何把它变为通用类型的线性查找呢?
根据之前学习的通用swap算法,可以写出如下函数体:
void* lsearch2(void *key, void *base, int n, int elemSize) {
for (int i = 0; i < n; i++ ) {
}
}
传入void* key指针,从base地址开始搜索,然后n次的搜索长度,每次搜索的比较字节大小为elemSize
void* elemAddr = base + i * elemSize;
这样子定义逻辑上没什么问题,但是在编译器中被当作是指针运算,而一般编译器中不允许对void*类型指针进行上述寻址操作,并不是我们所想的那样进行比较
有下面这种技巧:
void* elemAddr = (char*)base + i * elemSize;
把void*强制转换成char*类型,便于编译器为我们进行工作,char大小是1byte,可以完美实现位模式的比较。
完整函数就如下:
void *lsearch2(void *key, void *base, int n, int elemSize) {
for (int i = 0; i < n; i++ ) {
void *elemAddr = (char*)base + i * elemSize;
if (memcmp(key, elemAddr, elemSize) == 0) {
return elemAddr;
}
}
return NULL;
}
对于一般的int,long,float之类的都通用的线性搜索函数就完成,但是对结构体和指针等不支持的。