【C语言进阶】C语言指针进阶实战:优化与难题解析

news2024/9/19 10:57:57

📝个人主页🌹: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()
{
	//函数指针pfun
	void (*pfun)(const char*) = test;
	
	//函数指针的数组pfunArr
	void (*pfunArr[5])(const char* str);
	pfunArr[0] = test;
	
	//指向函数指针数组pfunArr的指针ppfunArr
	void (*(*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语言指针进阶之旅即将画上圆满的句号。但请记住,学习永无止境,技术的海洋浩瀚无垠。愿每一位编程爱好者都能保持对技术的热爱与追求,继续在编程的道路上探索前行,创造属于自己的辉煌篇章

在这里插入图片描述

希望本文能够为你提供有益的参考和启示,让我们一起在编程的道路上不断前行!
谢谢大家支持本篇到这里就结束了,祝大家天天开心!

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2082991.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Java常用API(BigInteger)

在Java中&#xff0c;整数有四种类型&#xff1a;byte&#xff0c;short&#xff0c;int&#xff0c;long 在底层占用字节个数&#xff1a;byte 1个字节&#xff0c;short2个字节&#xff0c;int 4个字节&#xff0c;long 8个字节 对象一旦创建&#xff0c;里面的值是不能改变…

Go wv(WebView2) GUI框架介绍和使用

说明 wv(webview2) 是Go语言基于LCL和WebView2基础上封装的框架&#xff0c;用于开发Windows GUI软件。 介绍 LCL(Lazarus Component Library) &#xff1a;跨平台原生UI组件库. wv(WebView2): Microsoft Edge WebView2 控件允许在本机应用中嵌入 web 技术(HTML、CSS 以及 …

俄罗斯应用本地化中需要考虑的不同格式的特点

在为俄罗斯市场本地化应用程序时&#xff0c;调整各种格式以符合当地惯例至关重要。这些格式&#xff0c;包括日期和时间、数字、货币、地址等&#xff0c;在确保应用程序对俄罗斯用户来说自然和用户友好方面发挥着重要作用。以下是本地化过程中应考虑的一些关键格式特征。 日…

算法之二分查找法

用二分查找法刷leetcode算法题目的时候&#xff0c;经常遇到视频看着理解很透彻&#xff0c;当上手写时一看就会&#xff0c;一写就废。二分查找法涉及边界条件很多&#xff0c;逻辑很简单&#xff0c;就是写不好。何时写 while(left<right)&#xff0c;while(left<right…

【大模型】llama系列模型基础

前言&#xff1a;llama基于transformer架构&#xff0c;与GPT相似&#xff0c;只用了transformer的解码器部分。本文主要是关于llama&#xff0c;llama2和llama3的结构解读。 目录 1. llama1.1 整体结构1.2 RoPE1.3 SwiGLU 激活函数 2. llama22.2 GQA架构2.3 RLHF3. llama3 参考…

【数据结构入门】排序算法之插入排序与选择排序

目录 前言 一、排序的概念及运用 1.排序的概念 2.排序的运用 3.常见排序算法 二、插入排序与选择排序 2.1插入排序 2.1.1直接插入排序 1&#xff09;基本思想 2&#xff09;具体步骤 3&#xff09;算法特性 4&#xff09;算法实现 2.1.2希尔排序 1) 基本思想 2&…

从苹果智能看端上大模型应用

将生成式人工智能集成到边缘设备本身就是一个重大挑战&#xff0c;我们需要在智能手机和计算机有限的计算能力和内存范围内高效地运行高级模型。确保这些模型运行迅速&#xff0c;而不会耗尽电池寿命或使设备过热&#xff0c;端上的局限增加了大模型应用的复杂性。此外&#xf…

LeetCode 算法:杨辉三角 c++

原题链接&#x1f517;&#xff1a;杨辉三角难度&#xff1a;简单⭐️ 题目 给定一个非负整数 numRows&#xff0c;生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1]…

关于异常断电后jmeter的jmx文件异常变成二进制文件并成功恢复的心酸历程

今日下午正在编写jmeter接口&#xff0c;正在调试中&#xff0c;突然断电&#xff08;由于四川高温&#xff0c;导致电力紧缺的很&#xff09;&#xff0c;来电了后我正常启动电脑&#xff0c;打开后&#xff0c;赶紧打开jmeter&#xff0c;并打开最近打开的文件&#xff0c;我…

『功能项目』怪物受击的动画事件【10】

我们打开上一篇09着色器光透魔法球的项目&#xff0c; 本章要做的事情是在场景中创建一个怪物对象&#xff0c;当怪物被主角的魔法球击中后播放受击动画效果&#xff0c;此类技术用到动画事件帧&#xff0c;在动画上创建脚本。 首先打开资源商店选择一个免费资源的怪物模型加载…

静态ISP代理IP适合什么应用场景?

随着互联网的普及和发展&#xff0c;越来越多的设备和应用需要接入网络。在这些情况下&#xff0c;动态主机配置协议 (DHCP) 成为一种常见的选择&#xff0c;因为它会自动为客户端分配 IP 地址。然而&#xff0c;在某些特定场景下&#xff0c;静态 IP 地址 (ISP) 可能是更好的选…

哈夫曼树例题

从这道题可以看出需要构建哈夫曼树 构造哈夫曼树如下 9和5最小&#xff0c;构成左右树&#xff0c;二者之和是14&#xff0c;放入数组&#xff0c;5和9从数组去掉 14和16最小&#xff0c;构成左右树&#xff0c;二者之和是30&#xff0c;放入数组&#xff0c;14和16从数组去…

基于yolov8的玻璃瓶塑料瓶检测系统python源码+onnx模型+评估指标曲线+精美GUI界面

【算法介绍】 基于YOLOv8的玻璃瓶塑料瓶检测系统是一个利用深度学习技术的先进解决方案&#xff0c;专注于对图像、视频或实时摄像头流中的玻璃瓶和塑料瓶进行快速准确的检测与定位。该系统通过YOLOv8这一高效的目标检测算法&#xff0c;能够在多种应用场景下展现卓越的性能。…

Java面试题·解释题

系列文章目录 总章 Java解释题 文章目录 系列文章目录前言面向对象编程是什么&#xff1f;Java的跨平台原理Java的安全性Java的三大版本Java开发运行过程什么是JVM&#xff1f;什么是JDK&#xff1f;什么是JRE&#xff1f;JDK,JRE,JVM三者关系概括Java的数据类型&#xff1f;J…

有没有比较好用的在线翻译工具?实力推荐这4款。

当我们面对外文资料时&#xff0c;可能需要翻阅厚重的词典&#xff0c;耗费大量的时间和精力。在翻译这方面&#xff0c;很多人都十分依赖翻译工具的&#xff0c;因为这些工具只需几秒钟就能给出翻译结果&#xff0c;提高了我们的学习和工作的效率。但是随着翻译工具越来阅读&a…

灵感枯竭?ChatGPT助你轻松完成开题报告!

在学术探索的征途中&#xff0c;撰写论文开题报告是一项至关重要的初步工作。这项工作不仅标志着您研究旅程的起点&#xff0c;也是展现您研究思路和方法论的关键时刻。ChatGPT&#xff0c;作为一款前沿的人工智能工具&#xff0c;将以其深度学习能力&#xff0c;成为您学术探索…

【大模型系列篇】预训练模型:BERT GPT

2018 年&#xff0c;Google 首次推出 BERT&#xff08;Bidirectional Encoder Representations from Transformers&#xff09;。该模型是在大量文本语料库上结合无监督和监督学习进行训练的。 BERT 的目标是创建一种语言模型&#xff0c;可以理解句子中单词的上下文和含义&…

数学问题+贪心

前言&#xff1a;一开始我想的就是我每次都设置一个cnt记录每次增加量&#xff0c;后面都增加这个量&#xff0c;但是发现我忘记要把这个量先加到后面的元素上面去 正确的做法就是每次 a [ i ] > a [ i − 1 ] a[ i ] > a[ i-1 ] a[i]>a[i−1] 的时候再进行处理&…

量化交易backtrader实践(四)_评价统计篇(3)_更多评价与可视化

前情回顾 在第(1)节中&#xff0c;我们对于backtrader内置的评价指标一个接一个的进行了实践测试&#xff0c;其中第10个是金融投资组合分析库 - pyfolio&#xff0c;当时我们先去实践了Analyzer中的pyfolio指标&#xff08;其实就是03&#xff0c;07&#xff0c;08&#xff0…

Python TensorFlow入门与实践

摘要 本文旨在详细介绍如何使用Python和TensorFlow进行基本的深度学习任务。我们将从安装TensorFlow开始&#xff0c;逐步讲解如何创建简单的神经网络模型&#xff0c;并通过一个具体的示例来演示如何训练模型。此外&#xff0c;我们还将讨论一些高级主题&#xff0c;如卷积神…