void指针为何能幻化有数据类型?
一.测试环境
qt5.12
二.void指针
1.void指针
void *表示一个“不知道类型”的指针,也就不知道从这个指针地址开始多少字节为一个数据。和用int表示指针异曲同工,只是更明确是“指针”。
因此void *只能表示一个地址,不能用来&取值,也不能++和--移动指针,因此不知道多少字节是一个数据单位。
示例:
int nums[] = {3,5,6,7,9};
void* ptr1 = nums;
//int i = *ptr1; // 对于void指针没法直接取值
int* ptr2 = (int*)nums;
qDebug()<<ptr1<<ptr2;
int i = *ptr2;
qDebug()<<i;
从输出结果上,无论是无类型的void指针还是int类型指针,指向的地址都是一样的:
说明:void *就是一个不能动的“地址”,在进行&、移动指针之前必须转型为类型指针。
2.void指针的用途
(1)memset 函数是 C 语言标准库中的一个函数,常用于将一段内存区域设置为指定的值。
#include <string.h>
函数原型:void *memset(void *s, int c, size_t n);
代码示例:
#include <stdio.h>
#include <string.h>
int main() {
int str[10];
// 使用 memset 将 str 数组全部置位0
memset(str, 0, sizeof(str));
qDebug()<<"len=" << sizeof(str);
for (int i = 0; i < 10; i++) {
qDebug()<<str[i];
}
return 0;
}
输出结果:
说明:
void *的用途:在只知道内存,但是不知道是什么类型的时候。
三.函数指针
1.指向函数的指针
我们可以在C中定义一个函数指针:
typedef void (*intFunc)(int i);
这里我们定义了一个无返回值的,只有一个int类型参数的函数指针intFunc。
我们可以在main函数中使用这个函数指针来指向一个具体的函数(这个具体的函数定义需要和函数指针的定义一致):
代码示例:
typedef void (*intFunc)(int i);
void test1(int age){
qDebug()<<"test1:%d\n",age);
}
int main(void){
// 声明一个intFunc类型的函数指针
intFunc f1 = test1;
// 执行f1函数指针所指向的代码区
f1(8);
return 0;
}
最终运行结果为:8,执行函数指针f1即执行了其所指向的具体的函数。
2.函数指针的基本使用
这里我们通过一个小案例来对函数指针做一个基本的使用介绍。相信大部分的C#或Java程序员都很熟悉foreach,那么我们就来模拟foreach对int数组中的值进行不同的处理。
具体体现为for循环的代码是复用的,但是怎么处理这些数据不确定,因此把处理数据的逻辑由函数指针指定。
void foreachNums(int *nums,int len,intFunc func)
{
int i;
for(i=0;i<len;i++)
{
int num = nums[i];
func(num);
}
}
void printNum(int num)
{
qDebug()<<num;
}
在foreachNums函数中,我们定义了一个intFunc函数指针,printNum函数是满足intFunc定义的一个具体的函数。
下面我们在main函数中将printNum函数作为函数指针传递给foreachNums函数。
int nums[] = { 1,5,666,23423,223 };
foreachNums(nums,sizeof(nums)/sizeof(int),printNum);
最终运行的结果如下图所示:
通过函数指针,我们可以屏蔽各种具体处理方法的不同,也就是将不确定的因素都依赖于抽象,这也是面向抽象或面向接口编程的精髓。