cs107 编程范式(三)

437 阅读2分钟

int型整数交换

void swap(int *ap, int *bp) 
{
    int temp = *ap;
    *ap = *bp;
    *bp = temp;
}

因为参数声明的是int*类型,所以只会操作4字节的内存空间,这只适用于int类型,不具备通用性。

通用类型交换

void swap(void *vp1, void *vp2, int size)
{
    char buffer[size];
    memcpy(buffer, vp1, size);
    memcpy(vp1, vp2, size);
    memcpy(vp2, buffer, size);
}

这里我们使用void*类型(任何类型指针都可以转为void*),但是void*会造成信息损失,编译器无法确定以vp1为首地址的变量该取多少个字节。因此,不能使用取值操作*vp1,而直接使用memcpy进行字节层面的拷贝。

int x = 17, q = 37;
swap(&x, &q, sizeof(int));

double d = 3.14, e = 2.78;
swap(&d, &e, sizeof(double));

运行结果x:37, q:17, d:2.78, e: 3.14

但是,如果两个变量是不同的类型则会产生一定的问题,如下:

int i = 44;
short s = 5;
swap(&i, &s, sizeof(short));

即0x2c 00 00 00与0x05 00 00 00按2字节进行交换

输出 i: 5, s: 44

如果想传递不同类型的变量,则需要要为函数提供更多的类型信息。

字符串交换

char *hushand = strdup("Fred");
char *wife = strdup("Wilma");
swap(&hushand, &wife, sizeof(char*));

这里交换的是char*指针,并不是内存中存储的数据。

捕获4.PNG

char *husband = strdup("Fred");
char *wife = strdup("Wilma");
swap(husband, wife, sizeof(char*));

这里传入的是char*指针,同时sizeof(char*)为4字节,编译器会执行4字节交换

输出结果就是husband: Wilm, wife: Freda

查找

int lsearch(int key, int array[], int size) {
    for(int i = 0; i < size; i++) {
        if(array[i] == key) {
            return i;
        };
    }
    return -1;
}

因为array实际上是数组首地址,在传递的过程中我们损失了数组长度的信息,因此在函数参数中我们需要进行补充。

通用版本

void* lsearch(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;
}

在通用版本中,我们通过void*来进行传递,但是这种方式会进一步损失元素字节大小的信息,因此在函数参数中我们需要进行补充。

一般情况下,我们采用如下方式进行处理

void *elemAddr = base + i * elemSize;

但是void*中不包含元素字节大小的信息,因此一般编译器中不允许如上操作,最常见的方式就是将void*类型强制转为char*类型来进行操作。

下节课,我们会将比较函数也进行传递,来实现在标准库中我们所见到的一般形式,如下所示:

void *lsearch(void *key, void *base, int n, int elemSize, int (*cmpfn)(void*, void*));