今天更新指针剩下的进阶知识,主要知识为:
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零基础指南》(第八讲) 二级指针_英雄哪里出来的博客-优快云博客