??? 文章由@不准备秃的大伟原创 ???
??? 若有转载,请联系博主哦~????
??? 致力学好编程的宝藏博主,代码兴国!???
????????许久不见,甚是想念,真的是时间时间,你慢些吧,不能再让头发变秃了?,我愿用我一生换我头发常青~~(^▽^ )。好的好的,今天是12月31号,是2023年的最后一天,博主这里提前祝大家新年快乐!
? ? ? ? 最后一天了,?博主在这里问各位铁汁们一句:“2022年定下的目标2023年都实现了吗?2023又要为2024定什么目标呢?” 或许有些铁汁会骄傲的拍拍胸脯说:“何止实现了,我还超了呢!”,或许也有铁汁会说:“嗐,2023年因为这样那样的原因,没有能完成去年定的目标,很后悔!”
? ? ? ? 其实无论你是处在哪种阶段,博主只想说:“向前看吧,过去的已经不存在了,过去一年里你是荣华富贵或是灰头土脸又如何,难道以后就不会改变了吗?就像我们头上的头发,终有一天也会变白,脱落,但是生活不还得继续吗?所以,抛下顾虑,放下过去的荣辱,在新的一年里继续努力,为更好的未来而前进吧!”
?????????鸡汤虽多,但不喝也无用。所以,为了更好的未来,我们铁汁们还是需要继续学习的是吧,还会继续给大伟点赞收藏,继续支持大伟的对吧~对吧~对吧~ヾ(≧▽≦*)o
? ? ? ? 呃哼,我们今天来看看C语言的核心:指针的最后一篇。今天我们要学的知识是:没了。
? ? ? ??
? ? ? ? 啊不是,应该是有关指针的内容基本没了,这一篇主要是一些扩展,别误解哦~? 好的,今天要学的内容是:回调函数,qsort使用和模拟实现,最后是有关指针的笔试题。
? ? ? ? 诶,但是在开始之前,我们先谈一谈上一篇博客最后提到的两段代码,什么,不记得了?哼,就知道会发生这种情况,快去看—————>指针(part three)
(*(void (*)())0)();
? ? ? ?大家整体看这段代码是不是难于理解?那如果我们把它分为几个区块,从内部一个一个分析呢?:
void (*)()
? 这是一个函数指针的声明。它声明了一个指向不带参数(void
)并返回 void
的函数的指针
(void (*)())0
? ?这是将整数 0
转换为指定类型的函数指针
(*(void (*)())0)
? ?这对函数指针进行了解引用。它将地址为 0
的值视为函数并调用它
?????????简单来说,这段代码试图调用内存地址为 0
处的函数
? ? ? ? 怎么说,铁汁们,从内部一步一步分解是不是就会相对好理解了?里面的内容其实是我们已经学过的知识的集合体啊,对不对。
void (*signal(int , void(*)(int)))(int);
? ——————————————————————————————————————————
signal
这是一个函数名
int
?这是signal
函数的第一个参数,表示信号编号
void(*)(int)
?这是signal
函数的第二个参数,是一个函数指针。它表示指向一个接受int
参数并返回void
的函数的指针。这个函数指针是信号处理函数,指定了在接收到信号时应采取的操作
(*signal(int, void(*)(int)))
?这部分表示signal
是一个接受两个参数并返回某种结果的函数。声明的最外层指定了返回的类型
void(*)(int)
?这指定了signal
函数的返回类型。它是一个函数指针,指向一个接受int
参数并返回void
的函数。这与signal
返回信号处理函数的函数指针的概念一致
?????????综合起来,signal
函数接受两个参数:一个表示信号编号的int
,一个表示信号处理函数的函数指针。它返回一个类型为void (*)(int)
的函数指针
? ? ? ? OK,这里把上一篇博客遗留下的问题解决了,现在开始这次的内容:
? ? ? ? 定义:回调函数就是?个通过函数指针调?的函数
简单来说:就是在函数内定义了另一个函数?,如:
int add(int a, int b)
{
return a + b;
}
void calc(int(*pf)(int, int))
{
int ret = 0;
int x, y;
printf("输?操作数:");
scanf("%d %d", &x, &y);
ret = pf(x, y);
printf("ret = %d\n", ret);
}
int main()
{
calc(add);
return 0;
}
????????calc函数接受一个函数指针 pf
,该指针指向一个接受两个整数参数并返回整数的函数。
? ? ? ? 以下是qsort函数的使用演示:
#include <stdio.h>
//qosrt函数的使?者得实现?个?较函数
int int_cmp(const void * p1, const void * p2)
{
return (*( int *)p1 - *(int *) p2);
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
int i = 0;
qsort(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
return 0;
}
? ? ? ? 以下是cpp官方给的qsort的解释:?????????其中的四个元素:
? ? ? ? 还是那句话,虽然我们程序猿不需要多好的英语,但是我们以后是需要看各种英文的文献的,所以我们从现在开始就要逐渐适应读英文的文章。
? ? ? ? 简单来说:qsort函数内部第一个元素:要排序的数组名,第二个元素:数组的大小,第三个元素:数组内存储的类型的字节大小,第四个元素:一个cmp函数,函数内实现的是两个指针的对比。(如上,*a -*b为升序,*b - *a 为降序,*a > *b 为升序,*a < *b 为降序)
? ? ? ? 拓展一下:qsort库函数底层是快排,时间复杂度是O(N*logN) ,在我们刷题的时候还蛮经常用的。
? ? ? ? 那现在我们来对qsort函数进行个模拟实现,当然,是以冒泡的方法,所以时间复杂度是O(N*N)。那我们来看看吧!:
int int_cmp(const void * p1, const void * p2)
{
return (*( int *)p1 - *(int *) p2);
}
void _swap(void *p1, void * p2, int size)//交换函数
{
int i = 0;
for (i = 0; i< size; i++)
{
char tmp = *((char *)p1 + i);
*(( char *)p1 + i) = *((char *) p2 + i);
*(( char *)p2 + i) = tmp;
}
}
void bubble(void *base, int count , int size, int(*cmp )(void *, void *))//这里函数嵌套函数
{
int i = 0;
int j = 0;
for (i = 0; i< count - 1; i++)
{
for (j = 0; j<count-i-1; j++)
{
if (cmp ((char *) base + j*size , (char *)base + (j + 1)*size) > 0)//若前面比后面大
{
_swap(( char *)base + j*size, (char *)base + (j + 1)*size, size);//交换
}
}
}
}
int main()
{
int arr[] = { 1, 3, 5, 7, 9, 2, 4, 6, 8, 0 };
int i = 0;
bubble(arr, sizeof(arr) / sizeof(arr[0]), sizeof (int), int_cmp);
for (i = 0; i< sizeof(arr) / sizeof(arr[0]); i++)
{
printf("%d ", arr[i]);
}
printf("\n");
return 0;
}
? ? ? ? 这个模拟实现是完全按照官方给的元素来写的,浓度比较高,大家好好吸收哦~
? ? ? ? 其实的话到这里有关指针的内容已经可以结束了,但是呢,学而不思则罔,学会了,还需要大量的练习,正如前段时间网上比较火的:????????
? ? ? ? 题目是做不完的,但是知识点是固定的,博主这里给大家出三道题,大家珍惜哦~
int main()
{
int aa[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
int *ptr1 = (int *)(&aa + 1);
int *ptr2 = (int *)(*(aa + 1));
printf( "%d,%d", *(ptr1 - 1), *(ptr2 - 1));
return 0;
}
? ? ? ? 解析:&aa+1越过了整个二维数组aa,所以ptr1指向的是二维数组后面的那个元素,然后ptr-1,指向的是10;而aa+1越过了整个二维数组的第一行,ptr2指向的是6,ptr2-1指向的是aa第一行的最后一个元素5。
? ? ? ? 答案就是10和5
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
? ? ? ? 定义了一个指针数组*a[],又定义了一个二级pa指向a的首元素“work”,pa++也就是a向后走一个元素,此时*pa就是“at”。
? ? ? ? 答案就是at
int main()
{
char *c[] = {"ENTER","NEW","POINT","FIRST"};
char**cp[] = {c+3,c+2,c+1,c};
char***cpp = cp;
printf("%s\n", **++cpp);
printf("%s\n", *--*++cpp+3);
printf("%s\n", *cpp[-2]+3);
printf("%s\n", cpp[-1][-1]+1);
return 0;
}
? ? ? ? 同二,二级指针cp内存放的是将*c内元素逆转过来的,而三级指针指向的就是cp首元素,所以**++cpp就是指向的cpp向后走一个元素,即c+2,即“POINT”;*--*++cpp+3就是++cpp 指向 cp 数组的下一个元素,*--*++cpp 得到一个指向 c[0] 的指针?"ENTER",然后 +3 得到 "ER"?;*cpp[-2]+3 中 cpp[-2] 得到 cp[0],*cpp[-2] 得到 c[3],然后 +3 得到 "ST";cpp[-1][-1]+中,cpp[-1] 即*(cpp-1)得到 cp[2],cpp[-1][-1] 即 *(*(cpp-1)-1) 得到 c[1],然后 +1 得到 "EW"。答案就是POINT? ER? ST? EW
????????????????
? ? ? ? ? ? ? ? C语言指针也就到此为止了,最后再次祝大家新年快乐,愿大家成为自己心目中的那个人。插一嘴哈~虽然指针结束了,但大伟的学习和博客还没有结束哦,希望大家以后继续支持大伟,加油!
????????本篇博客也就到此为止了,送大家一碗鸡汤,勉励自己以及这世界上所有追逐梦想的赤子趁年华尚好努力提升自己,莫欺少年穷!??