void类型指针和函数指针

void类型的指针

1. void就是空的意思, void类型的指针。

2. void*point; 这样就定义了一个void类型的指针。  

3. 不能只用*来直接访问void类型的指针, *point; // 会报错 

    不能对指针进行++,point++;// 会报错, 是因为void类型指针,对指针进行++,不知道要增加多少个 

    字节。  

4. void类型指针可以隐式转换为任何类型的指针。 

    int nub = 10;  int *a = &nub;  void* b = a; // a为int类型的指针在赋值给void类型的指针b时自动转换成了void类型。 

5. void类型在使用的时候,必须强制转换成相应的类型才可以使用。 

 int c = *((int*) b);  // b为void类型指针,强制转换为int类型的指针,这样就可以访问和运算了。

那为什么要使用void类型的指针呢? 看后面。 

函数指针 

函数指针: 顾名思义就是指向函数的指针。 

所以,函数也是有地址的,函数的名称在编译之后就转化为函数的入口地址了,系统通过这个地址找到函数的位置,然后按顺序执行函数中的指令。 

int compare_int(const void* a, const void* b)
{
	//printf("成功调用函数");
	int *a1 = (int*)a;
	int *b1 = (int*)b;

	return *a1 - *b1; // *b1 - *a1 反过来了,从大到小排列
}


int main(void)
{
	int a = 0;
	int b = 10;
    /*既然函数也有地址,那我们可以定义一个指针指向函数*/
	int (*fun_point)(const void*, const void*); // 定义了一个可以指向函数的指针

	fun_point = &compare_int;

	// 第一种
	(*fun_point)(&a, &b); // 含义: *fun_point去访问这个函数,但是函数调用需要传参数,所以应该传 
    相应的参数
	
	// 第二种
	compare_int(&a, &b); // 不用*可以直接调用。



	system("pause");

	return 0;
}

上面的代码定义了一个函数指针, 和数组指针的原理是类似的。 

 int (*fun_point)(const void*, const void*); 定义了一个指针,指向参数为(const void*, const void*)返回值为 int 的函数。

而我们可以创建这样的一个函数,  compare_int;  // 可以使用这个指针指向这个函数

fun_point = compare_int;  

注意: 使用函数指针指向的函数,必须和函数指针指向的函数类型(返回类型和参数)一致才行,(也就是定义函数指针时,其指向的函数类型),否则是不对的。 

 指针已经指向了函数,我们可以使用它访问这个函数, 因为访问的是函数,所以我们应该传入相应的参数(代码中有两种访问方式,主要是历史上有的人使用第一种,有的人使用第二种,所以两种都是可以的)。

 (*fun_point)(&a, &b); 对于这段代码,其实和compare_int(&a,&b)是一致的。因为compare_int就是函数的入口地址,执行函数调用,就是跳转到函数的位置,然后将实参赋值给函数形参,然后执行函数中的指令。

那么为什么要使用函数指针呢?  

使用函数指针和void类型的指针 

我们以c库函数中的一个快速排序的函数,qsort(). 

这个函数接收4个数据: 1. 需要排序数的地址  

                                     2. 传入数据的占用的内存 

                                     3.  传入数据类型的大小 

                                     4. 传入一个函数,指明排序规则 

上面的第一个参数: 它使用的就是一个void*类型的指针, 因为任何指针都可以隐式转换成void类型,所以这可以使qsort()接收任何类型的数据,也就可以实现任何类型值得排序。(void类型指针在此处得作用)。如果qsort接收得参数是int 类型得指针,那么就只能传入int得值,只能实现int类型指针得排序 。

第四个参数: 很明显是需要传入一个函数得,那怎么将函数作为参数传入呢,我们可以定义一个函数指针指向对应函数,然后将这个函数指针传入qsort,这样它就可以使用传入得函数指针调用函数(这个中指明了排序的规则排序的类型)。 (函数指针在此处得使用)

 

#include 
#include 

int compare_int(const void* a, const void* b)
{
	//printf("成功调用函数");
	int *a1 = (int*)a;  // 函数指明排序的类型为int 则将传入的void*转为int*
	int *b1 = (int*)b;

	// 从大到小排
	return *a1 - *b1; // *b1 - *a1 反过来了,从大到小排列
}

int compare_char(const void* a, const void* b)
{
	char a1 = *(char*)a;  // 函数指明排序的类型为char,则将传入的void*转换为char*
	char b1 = *(char*)b;

	//不区分大小写,那就先将其都转换成小写,换成大写也一样
	if (a1 >= 'A' && a1 <= 'Z')
	{
		a1 = a1 + 32; // 转化成小写
	}

	if (b1 >= 'A' && b1 <= 'Z')
	{
		b1 = b1 + 32; // 转化成小写
	}

	// 从大到小排  b1-a1是从大到小排
	return a1 - b1;
}

int main(void)
{
	int arr[] = { 2,10,1,11,8,7,156,520 };

	/*对整型数组进行排序*/
	qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof(int), &compare_int);

	for (int i = 0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		printf("%d\n", arr[i]);
	}

	/*对任何类型进行排序*/
	char  arr1[] = "abcdefghiABCDEFGHI";  // 按照字母排序不区分大小写
	// 减1是因为,字符0不参与排序
	qsort(arr1, sizeof(arr1) / sizeof(char)-1, sizeof(char), &compare_char);
	for (int i = 0; i < sizeof(arr1) / sizeof(arr1[0]); i++)
	{
		printf("%c\n", arr1[i]);
	}

	system("pause");

	return 0;
}

其实我们在使用指针是,常常还会使用到一个动态分配内存的函数 malloc(); 我们在使用的时候都需要进行类型强转,这其实就是,malloc返回一个void类型的指针,我们需要什么样的类型就强转成什么。这就体现了void*指针的优点, 可以让我们申请各种类型的内存,而不是设置成只能申请一种,只要我们将返回的指针强转成一个我们需要的类型就可以了。 

上面的代码,实现使用qsort分别对int类型数组和char类型数组进行了排序。 

void类型指针作为参数,可以使任何类型的数据传入函数。

函数指针可以让函数作为参数传入另外一个函数。 

你可能感兴趣的:(c++,链表,开发语言)