Generic Pointer : void * 并不是说没有类型,而是指向没有任何类型信息的某个东西。
变量的类型 int
隐式地指明了变量在内存空间中占用的大小。
/* 轮转换位 */
void swap(int *ap, int *bp)
{
int temp = *ap;
*ap = *bp;
*bp = temp;
}
只能使用这个函数进行int类型的交换。
如何实现一种函数可以实现两个相同内存大小的变量进行内存交换的操作?
/* Generic pointer */
void swap(void* vp1, void* vp2, int elemSize)
{
char buffer[size] = {0}; // gcc 支持
// void *temp = malloc(elemSize);
memcpy(buffer, vp1, elemSize);
memcpy(vp1, vp2, elemSize);
memcpy(vp2, buffer, elemSize);
// free(temp);
}
void* vp1
, void* vp2
没有体现任何的类型信息。int x = 17;
int y = 37;
swap(&x, &y, sizeof(int));
double d = 3.1415;
double e = 2.732;
swap(&d, &e, sizeof(int));
// problem 编译器可检查不出来void* 的错误
int i = 44;
short s = 5;
swap(&i, &s, sizeof(short));
char *husband = strdup("Fred");
char *wife = strdup("Wilma");
// correct 交换两个char* 变量中的内容
swap(&husband, &wife, sizeof(char*));
// wrong, but won't crash, macOS is 64 bits -> 8 bytes swaped
swap(husband, wife, sizeof(char*));
// wrong,
swap(husband, &wife, sizeof(char*));
当我们通常写代码将类型弄混时,编译器总是会提示我们可能存在问题。除非在使用void* 类型时。编译器无法知道类型是什么,这样也就没法进行类型检查。
void* 失去了与类型相关联的隐式指针算术运算, 编译器也不知道如何比较它们指向的内容。
int lsearch(int key,
int array[],
int size)
{
for(int i = 0; i < size; ++i)
{
if(array[i] == key) // 指针算术运算 -> *(array + i) 编译器会自动乘上sizeof(int)
{
return i;
}
}
return -1;
}
1.function poniters -> call back/ hook function .
memcpy 对于内置类型有效,但是如果是字符串数组呢? 我们如果想要比较数组中的元素指向的字符串是否相等呢?这就是cmpfn的作用,判断相等的规则由调用者来指定。
2.calculate the address manually. 难点在于保证指针运算都正确
void *lsearch(void* key,
void* base,
int n,
int elemSize,
int(*cmpfn)(void*vp1, void* vp2))
{
void* elemAddr = NULL;
for(int i = 0; i < n; ++i)
{
elemAddr =
(char*)base + i*elemSize; //语法上想要实现的话要使用char* 步长为sizeof(char) = 1
if(cmpfn(elemAddr, key) == 0)
{
return elemAddr;
}
}
return NULL;
}
/* int type */
int array[] = {4,2,3,7,11,6};
int size = 6;
int number = 7;
int intCmp(void*vp1, void* vp2)
{
/* 调用者提供的函数,它知道void* 应该被解释成int* 类型 */
return *((int*)vp1) - *((int*)vp2);
}
int * found = lsearch(&number, array, 6, sizeof(int), intCmp);
if(found == NULL)
{
;
}
else
{
;
}
{
}
要比较的是字符串是否一致。
请注意vp1, vp2 被解释成了什么类型,为什么?
对称性。
/* char* type */
char * notes[] = {"Ab", "F#", "B", "Gb", "D"};
int stringCmp(void*, void*);
char * favoritenote = "Eb";
char **found = lsearch(&favoritenote, notes, 5, sizeof(char*), stringCmp);
int stringCmp(void *vp1, void *vp2)
{
char *s1 = *(char**)vp1;
char *s2 = *(char**)vp2;
return strcmp(s1, s2);
}
void *bsearch(void *key, void* base, int n, int elemsize, int(*cmpfn)(void*, void*));
int (cmpfn)(void*, void*);
// 现代语法分析器和语义分析器能够正确识别这是个函数指针,以前是必须加上*才能被正确识别。
void* 可以传入任何类型指针,只要cmpfn知道该如何正确解释这个地址,并提供相应的比较机制。
通用数据结构