c语言中*
表示变量为指针类型如int* p, double* q
。虽然他们指向数据类型不同但是他们在内存中所占的大小是一致的,根据机器的字节码确定。sizeof(p) == sizeof(q)
。但是对于他们的加减法运算有差异。p+1
指针移动4个内存地址。q+1
移动8个内存地址。
viod* p
是一个指向类型不明确的指针,也就是说p+1
不明确移动多少个内存地址。但是我们可以灵活地将其进行类型转换使其转换为需要的数据类型。这样的好处是可以实现灵活的泛型编程。比如排序算法我们不知道需要排序的数据类型,在c++中可以使用模板进行实现。但是在c语言中需要使用函数指针或者void*
实现。定义排序接口:
void InsertSort(void* arr, int n, int elem_size, int(*cmp)(void*, void*));
这里由于数组的数据类型未定所以传入void*
,同时传入数据量n
,数据类型大小elem_size
。对于不同数据类型的比较函数指针。
函数指针
函数指针指指向函数的指针,定义方式为ret (*p)(arg,...)
p是一个指向形参列表为arg,...
,返回值为ret
类型的函数指针。函数指针可以当做形参进行传递。int (*p)(int ,int)
p是一个指向返回值为int
,形参为(int,int)
的函数指针。定义方式如下:
typedef int(*Fp)(int,int);//定义函数指针类型名字
bool max(int a, int b){
return a>b?true:false;
}
int main(){
bool (*p)(int,int);
p = max;
p(1,2);//调用
p(2,3);
(*p)(1,3);
//另一种定义方式
Fp q;
q = max;
}
进一步来看void
的排序函数。首先对于不同数据类型定义比较函数:
int compare_int(void *elem1, void *elem2)
{
return (*(int *)elem1 - *(int *)elem2);
}
int compare_double(void *elem1, void *elem2)
{
return (*(double *)elem1 > *(double *)elem2) ? 1 : 0;
}
排序函数:
void InsertSort(void* arr, int n, int elem_size, int(*cmp)(void*, void*)) {
int i, j;
char* elem_addr1, *elem_addr2;
char* key_addr;
char* tmp = (char*)malloc(elem_size);
for (i = 1; i < n; i++) {
key_addr = (char*)arr + i * elem_size;
memcpy(tmp, key_addr, elem_size);
j = i - 1;
elem_addr1 = (char*)arr + j * elem_size;
while (j >= 0 && cmp(elem_addr1, tmp) > 0){
elem_addr1 = (char*)arr + j * elem_size;
elem_addr2 = (char*)arr + (j + 1) * elem_size;
memcpy(elem_addr2, elem_addr1, elem_size);
j--;
}
elem_addr2 = (char*)arr + (j + 1) * elem_size;
memcpy(elem_addr2, tmp,elem_size);
}
free(tmp);
}
测试函数:
int main(){
int num_int[8] = { 8,7,6,5,4,3,2,1 };
InsertSort(num_int, 8, sizeof(int), compare_int);
return 0;
}