C语言深度解析之三:进阶指针(二)

今天更新指针剩下的进阶知识,主要知识为:

1.指向函数指针数组的指针

2.回调函数

3.指针和数组笔试题解析

4.指针的笔试题


一.指向函数指针数组的指针

顾名思义,指向函数指针数组的指针,它本身就是一个指针,指向一个数组,数组的内容都是函数指针,下图给出定义:

二.回调函数

回调函数的定义:是一个通过函数指针调用的函数。

如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

下面这张图就是最简单的一个回调函数的例子,我们可以看到在主函数中调用print_hehe(test),test指向某一个函数,而print_hehe内有空指针*p,当调用p的时候,p作为print_hehe的参数在这里就指向了test函数,这样就去调用了test函数,实现了函数的回调过程。

来看下面这段复杂的代码,目的是利用bubble_sort模拟实现qsort的快速排序,这就是利用了回调函数的作用,主函数中执行test,test中执行bubble_sort,而bubble_sort中含有参数cmp_int ,接下里去调用bubble_sort,cmp_int里面对应的参数(int (*cmp)(const void* e1, const void* e2)),这是一个函数指针,然后执行cmp的时候就会指向cmp_int函数,从而实现函数的回调。

void print_arr(int arr[], int sz)
{
	int i = 0;
	for (i = 0; i < sz; i++)
	{
		printf("%d ", arr[i]);
	}
}
int cmp_int(const void* e1, const void* e2)
{
	return (*(int*)e1 - *(int*)e2);
}
void Swap(char* buf1, char* buf2, int width)
{
	int i = 0;
	for (i = 0; i < width; i++)
	{
		char tmp = *buf1;
		*buf1 = *buf2;
		*buf2 = tmp;
		buf1++;
		buf2++;
	}
}
void bubble_sort(void* base, int num, int width, int (*cmp)(const void* e1, const void* e2))
{
	int i = 0;
	for (i = 0; i < num - 1; i++)
	{
		int j = 0;
		for (j = 0; j < num - 1 - i; j++)
		{
			//if (arr[j] > arr[j + 1])//比较
			if (cmp((char*)base + j * width, (char*)base + (j + 1) * width) > 0)
			{
				//交换
				Swap((char*)base + j * width, (char*)base + (j + 1) * width, width);
			}
		}
	}
}
void test4()
{
	int arr[] = { 9,8,7,6,5,4,3,2,1,0 };
	//排序为升序
	int sz = sizeof(arr) / sizeof(arr[0]);
	bubble_sort(arr, sz, sizeof(arr[0]), cmp_int);
	print_arr(arr, sz);
}
int main()
{
	test4();
	return 0;
}

三.指针和数组笔试题解析 

这一小节主要针对不同的数组类型以及sizeof和strlen函数辨析

3.1 int类型数组a,内含四个整形元素,sizeof

 3.2 char类型数组,内含六个字符类型,sizeof

3.3 char类型数组,内含六个字符类型,strlen

3.4 char类型数组,内含一个字符串,sizeof

3.5 char类型数组,内含一个字符串,strlen

3.6 char类型的*p指针

3.7 int类型的二维数组,sizeof

 四.指针笔试题解析

4.1

如图所示,这里首先定义了int类型的数组a,内含五个int类型的变量,接着对数组a取地址,这时候取出了整个数组的地址,+1之后该地址指向了1,2,3,4,5之后的首个地址,利用*ptr将数组指针转化为整型指针,第三句的第一个打印项目*(a+1)的含义是对a取出首元素地址来之后加一,此时地址指向2对应的地址,然后解引用打印结果为2,第二个打印项目*(ptr-1),ptr-1指向了元素5对应的地址,所以解引用后打印结果为5。

4.2

如图所示,p为结构体指针,字节大小为20个字节。

第一个printf的含义就是p+1,其实就是结构体指针加1,即p对应的指针地址向后加了20,结果为0x00100014,打印出来就是00100014,%p就是专门用来打印地址(指针)的,会补0!!

第二个printf中将p强制类型转换为整型,已经不是指针了!!所以这里加1就是加了一个1。

第三个printf中将p强制转换为整型指针,加1就是向后访问4个字节,所以加4。

4.3

%x是以十六进制打印,%o是八进制打印 。

首先分析*ptr1,首先取a地址取出了整个数组地址,加1后指向4的后面,打印时减1指向4。

接下里分析*ptr2,首先将a强制类型转换为int类型,int类型的整型加一就是加一个字节,所以必须知道a在内存中是如何存储的,按照小端模式,地址由低到高变化:

01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00 00

 (int)a+1之后就指向01 之后 也就是指向一个 00 00 00 02这四个字节,所以按照小段的存储方式访问之后应该是2000000(访问方式(从高地址向低地址读数据)为02 00 00 00)。

 4.4 

这个题出的非常的阴险,阴险就阴险在对数组a的初始化方法,注意看初始化内部并没有使用中括号,这里使用了逗号表达式,所以初识化只读进去了1,3,5,0,0,0,所以p[0]指向1。

 4.5 

先解析a[4][2],指向红色填充

 

再解析p[4][2],这里的含义就是*(*(p+4)+2),*p是能够指四个整型的指针,p+4解引用后再+2如图所示篮色填充,

两个地址之间相差四个字节,打印指令为低地址减去高地址,若以%d打印,那当然就是-4,但是如果要以%p打印,那么就是打印地址,那么需要打印的就是-4在内存中的存储形式,也就是补码:11111111111111111111111111111100,四个一就是一个F,所以打印出来就是FFFFFFFC。

明早还有全员核酸,还有三道笔试题没写,这次就发这么多,下次更。

今天在学习英雄哥leetcode指南,转载一下leetcode相关的知识,仅作学习,侵权删。

出自《LeetCode零基础指南》(第八讲) 二级指针_英雄哪里出来的博客-CSDN博客

 

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

何以过春秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值