本文主要是介绍【C语言进阶】C语言指针进阶实战:优化与难题解析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
📝个人主页🌹:Eternity._
⏩收录专栏⏪:C语言 “ 登神长阶 ”
🤡往期回顾🤡:C语言指针进阶 (上)
🌹🌹期待您的关注 🌹🌹
❀C语言指针进阶
- 📒1. 函数指针
- 📙2. 函数指针数组
- 📚3. 指向函数指针数组的指针
- 📜4. 回调函数
- 📝5. 指针笔试题
- 📖6. 总结
前言:在C语言的浩瀚宇宙中,指针无疑是那颗最为璀璨而神秘的星辰。它既是连接数据与操作的桥梁,也是让许多初学者望而生畏的迷宫。一旦掌握了指针的精髓,C语言的世界便仿佛被彻底点亮,编程的效率和灵活性得以质的飞跃。然而,仅仅停留在指针的基本使用上,远不足以探索其全部魅力与力量。指针的进阶应用,尤其是如何通过指针优化程序性能、解决复杂难题,是每一位C语言开发者必须攀登的高峰
每个实战案例都将配以详细的代码示例与解释,旨在让读者不仅能够理解其背后的原理,更能够亲手实践,将所学知识转化为解决问题的能力。同时,我们也会对一些常见的指针难题进行深度解析,比如指针运算的陷阱、多级指针的理解难点等,帮助读者彻底克服这些学习障碍
让我们继续一同踏上这场充满挑战与收获的指针进阶之旅吧!
📒1. 函数指针
C语言中的函数指针是一种特殊的指针类型,它存储的不是变量的地址,而是函数的地址。通过函数指针,我们可以在运行时动态地调用函数,这增加了程序的灵活性和模块化。函数指针在回调函数、中断服务例程、以及实现函数表(如多态)等场景中非常有用
void test()
{printf("hehe\n");
}int main()
{printf("%p\n", test);printf("%p\n", &test);return 0;
}
输出的是两个地址,这两个地址是 test 函数的地址,那么我们怎么保存函数的地址呢?
定义:
// 保存函数的地址
void (*pfun1)();
解析:pfun1可以存放存储地址。pfun1先和*结合,说明pfun1是指针,指针指向的是一个函数,指向的函数无参数,返回值类型为void
我们再来看一下这两个代码
//代码1
(*(void (*)())0)();
//代码2
void (*signal(int , void(*)(int)))(int);
代码1:
这段代码尝试执行一个位于地址0处的函数。首先,(void (*)())0是一个类型转换,它将整数0转换为指向返回类型为void且不接受任何参数的函数的指针。然后,*操作符对转换后的指针进行解引用,尝试获取该函数指针指向的函数。最后,()用于调用该函数
代码2:
- signal是一个函数,它接受两个参数:
- 第一个参数是int类型,通常用于指定要处理的信号编号。
- 第二个参数是一个指向函数的指针,这个函数接受一个int参数(通常是信号编号)并返回void。
- signal函数的返回类型是一个指向函数的指针,这个函数也接受一个int参数并返回void
📙2. 函数指针数组
把函数的地址存到一个数组中,那这个数组就叫
函数指针数组
定义:
int (*parr1[10])();
// parr1 先和 [] 结合,说明 parr1是数组
// 存放int (*)() 类型的函数指针
举个例子来展示如何定义一个函数指针数组,并向其中添加函数指针,最后通过索引来调用这些函数
// 定义三个示例函数
void func1(int x)
{printf("Func1 called with %d\n", x);
}void func2(int x)
{printf("Func2 called with %d\n", x);
}void func3(int x)
{printf("Func3 called with %d\n", x);
}// 定义一个指向函数的指针类型,该函数接受一个int参数并返回void
typedef void (*FuncPtr)(int);int main() {// 创建一个函数指针数组,可以存储三个指向函数的指针 FuncPtr funcArr[3] = { func1, func2, func3 };// 通过索引调用函数 for (int i = 0; i < 3; i++) {funcArr[i](i + 1); // 调用函数,并将索引值+1作为参数传递 }return 0;
}
📚3. 指向函数指针数组的指针
指向函数指针数组的指针是一个
指针
指针指向一个 数组 ,数组的元素都是 函数指针
定义:
void test(const char* str)
{printf("%s\n", str);
}int main()
{//函数指针pfunvoid (*pfun)(const char*) = test;//函数指针的数组pfunArrvoid (*pfunArr[5])(const char* str);pfunArr[0] = test;//指向函数指针数组pfunArr的指针ppfunArrvoid (*(*ppfunArr)[5])(const char*) = &pfunArr;return 0;
}
📜4. 回调函数
回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应
// 定义一个回调函数的类型,该函数接受一个int参数并返回void
typedef void (*CallbackFunc)(int);// 一个需要回调函数的函数
void processData(int data, CallbackFunc callback)
{printf("Processing data: %d\n", data);// 调用回调函数 callback(data);
}// 用户定义的回调函数
void myCallback(int data) {printf("Callback called with data: %d\n", data);
}int main() {// 调用需要回调函数的函数,并传递用户定义的回调函数作为参数 processData(10, myCallback);return 0;
}
processData
函数接受一个整数和一个回调函数作为参数。在processData
函数内部,首先执行一些处理,然后调用回调函数callback
,并将之前接收到的整数data作为参数传递给回调函数。用户定义的回调函数myCallback
被传递给processData
函数,并在适当的时候被调用
回调函数广泛应用于事件处理、排序算法(如快速排序中的比较函数)
📝5. 指针笔试题
题目一:
int main()
{int a[5] = { 1, 2, 3, 4, 5 };int* ptr = (int*)(&a + 1);printf("%d,%d", *(a + 1), *(ptr - 1));return 0;
}
题目二:
int main()
{int a[3][2] = { (0, 1), (2, 3), (4, 5) };int* p;p = a[0];printf("%d", p[0]);return 0;
}
数组初始化时使用的 (0, 1) 形式的初始化实际上是逗号运算符(comma operator)的使用。逗号运算符会评估其两个操作数,但只返回最后一个操作数的值
这里 p 被赋值为 a[0] 的地址,即 &a[0][0]。然后 p[0] 访问了这个地址的内容,即 a[0][0],其值为1
题目三:
int main()
{char* a[] = { "work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;
}
这道题目比较简单,各位可以自己看看
题目四:
//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a)); // 16 数组大小
printf("%d\n",sizeof(a+0)); // 4 数组元素的大小
printf("%d\n",sizeof(*a)); // 4 首元素大小
printf("%d\n",sizeof(a+1)); // 4 数组元素的大小
printf("%d\n",sizeof(a[1])); // 4 数组元素的大小
printf("%d\n",sizeof(&a)); // 4 数组首元素的大小
printf("%d\n",sizeof(*&a)); // 16 数组大小
printf("%d\n",sizeof(&a+1)); // 4 数组元素的大小
printf("%d\n",sizeof(&a[0])); // 4 数组元素的大小
printf("%d\n",sizeof(&a[0]+1)); // 4 数组元素的大小
📖6. 总结
随着指针进阶学习的深入,我们仿佛揭开了C语言世界中最为神秘而又引人入胜的一角。在上一部分,我们已经见证了指针如何成为连接数据与内存的桥梁,而在这部分,我们更是将这份力量发挥到了极致
回顾这段学习之旅,我们不难发现,指针不仅是C语言的核心特性之一,更是编程世界中一把强大的双刃剑。它既能让我们实现高效的内存管理与复杂的数据操作,也可能因不当使用而引发难以察觉的错误与漏洞。因此,在享受指针带来的便利与乐趣的同时,我们也必须时刻保持警惕,遵循最佳实践,确保代码的安全与可靠
至此,我们的C语言指针进阶之旅即将画上圆满的句号。但请记住,学习永无止境,技术的海洋浩瀚无垠。愿每一位编程爱好者都能保持对技术的热爱与追求,继续在编程的道路上探索前行,创造属于自己的辉煌篇章
希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!
这篇关于【C语言进阶】C语言指针进阶实战:优化与难题解析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!