void是什么意思(void指针背后隐藏着什么?)
1个不可移动“地址”的空指针1.1空指针
Void *表示一个“未知类型”的指针,即从这个指针地址开始的一段数据有多少字节是未知的。和用int表示一个指针是一样的,但是更具体的是“指针”。
所以void *只能代表一个地址,不能用来& value,也不能++和-移动指针,所以不知道多少字节是一个数据单元。
(相关资料图)
int nums[] = {3,5,6,7,9}; void* ptr1 = nums; //int i = *ptr1; // 对于void指针没法直接取值 int*&红豆博客nbsp;ptr2 = (int*)nums; printf("%d,%d\n",ptr1,ptr2); int i = *ptr2; printf("%d\n",i);
从输出结果可以看出,无论是非类型化void指针还是int指针,指向的地址都是一样的:
Ps: void *是一个不可移动的“地址”,它必须在移动指针之前被转换成一个类型指针。
1.2 void指针的用途这里,我们来看看之前学过的memset函数。第一个参数是一个void指针,可以帮助我们屏蔽不同类型指针的差异。
如下面的代码所示,我们可以传入一个指向int类型数组的指针或一个指向char类型数组的指针:
int nums对于结构类型,我们也可以使用mymemset函数:; memset(nums,0,sizeof(nums)); char chs[2]; memset(chs,0,sizeof(chs));
那么,我们也可以尝试自己模拟这个memset函数,暂时命名为mymemset:
void mymemset(void *data,int num,int byteSize){ // char就是一个字节,而计算机中是以字节为单位存储的 char *ptr = (char*)data; int i; for(i=0;i
在这个mymemset函数中,我们用void指针接收不同类型的指针,用char类型(一个字节)逐个读取内存中的每个字节,最后依次填充指定的数字。
因为char类型是具体类型,所以可以使用++或-来移动指针。
[20]
typedef struct _Person{ char *name; int age;} Person;Person p1;mymemset(&p1,0,sizeof(Person));printf("p1.Age:%d\n",p1.age);
红豆博客最终运行结果如下图所示:
void *的用途:只知道内存,但不知道是什么类型的时候。
2函数指针2.1指向函数的指针我们可以很容易地在C中定义一个函数指针:
typedef void (*intFunc)(int i);
这里我们定义了一个函数指针intFunc,没有返回值,只有一个int类型的参数。
我们可以在主函数中使用这个函数指针指向一个特定的函数(这个特定的函数定义需要和函数指针的定义一致):
void test1(int age){ printf("test1:%d\n",age);}int main(void){ // 声明一个intFunc类型的函数指针 intFunc f1 = test1; // 执行f1函数指针所指向的代码区 f1(8); return 0;}
最终运行结果如下图所示,执行函数指针f1执行其指向的特定函数:
2.2函数指针的基本用法
这里我们通过一个小案例对函数指针的使用做一个基本的介绍。相信大部分C#或Java程序员对foreach都很熟悉,所以我们模拟foreach对int数组中的值进行不同的处理。for循环中体现的代码是重用的,但是如何处理数据是不确定的,所以处理数据的逻辑由函数指针指定。
void foreachNums(int *nums,int len,intFunc func){ int i; for(i=0;idata2,则返回正数void *getMax(void *data,int unitSize,int length,compareFunc func){ int i; char *ptr = (char*)data; char *max = ptr; for(i=1;i0) { max = item; } } return max;}
这里可以看到,在getMax中比较几个字节是由compareFunc指向的函数完成的,getMax根本不在乎。
(2)定义符合函数指针定义的不同类型的函数:
int intDataCompare(void *data1,void *data2){ int *ptr1 = (int*)data1; int *ptr2 = (int*)data2; int i1=*ptr1; int i2=*ptr2; return i1-i2;}typedef struct _Dog{ char *name; int age;} Dog;int dogDataCompare(void *data1,void *data2){ Dog *dog1 = (Dog*)data1; Dog *dog2 = (Dog*)data2; return (dog1->age)-(dog2->age);}
(3)在主函数中调用int类型和structure类型:
int main(int argc, char *argv[]){ // test1:int类型求最大值 int nums[] = { 3,5,8,7,6 }; int *pMax = (int *)getMax(nums,sizeof(int),sizeof(nums)/sizeof(int), intDataCompare); int max = *pMax; printf("%d\n",max); // test2:结构体类型求最大值 Dog dogs[] ={{"沙皮",3},{"腊肠",10},{"哈士奇",5}, {"京巴",8},{"大狗",2}}; Dog *pDog = (Dog *)getMax(dogs,sizeof(Dog), sizeof(dogs)/sizeof(Dog),dogDataCompare); printf("%s=%d",pDog->name,pDog->age); return 0;}
最终运行结果如下图所示:
3.2 C-自定义排序中包含的qsort功能
Qsort包含在头文件中。这个函数根据你给的比较条件快速排序,通过移动指针来排序。排序后的结果仍然放在原始数组中。
要使用qsort函数,必须自己写一个比较函数。我们可以看看qsort函数的原型:
void qsort ( void * base, size_t num, size_t size, int ( * comparator ) ( const void *, const void * ) ); int nums[] = { 3,5,8,7,6 }; qsort(nums,sizeof(nums)/sizeof(int),sizeof(int),intDataCompare); int i; for(i=0;i
那么,快速排序后有结果吗?答案是肯定的,我们可以引入各种比较方法,可以升序排序,也可以降序排序。
——结尾——