❀❀❀ 文章由@不准备秃的大伟原创 ❀❀❀
♪♪♪ 若有转载,请联系博主哦~ ♪♪♪
❤❤❤ 致力学好编程的宝藏博主,代码兴国!❤❤❤
许久不见,甚是想念,真的是时间时间,你慢些吧,不能再让头发变秃了 ,我愿用我一生换我头发常青~~(^▽^ )。好的好的,今天是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
//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;
}
还是那句话,虽然我们程序猿不需要多好的英语,但是我们以后是需要看各种英文的文献的,所以我们从现在开始就要逐渐适应读英文的文章。
简单来说: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 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语言指针也就到此为止了,最后再次祝大家新年快乐,愿大家成为自己心目中的那个人。插一嘴哈~虽然指针结束了,但大伟的学习和博客还没有结束哦,希望大家以后继续支持大伟,加油!