c语言学习--函数与指针
指针传递地址传递、引用传递值传递实参的值是非地址类型实参将自己的值的拷贝传递给形参形参与实参只有值相等是两个独立的变量。指针传递实参是地址指针变量、数组名形参接收到时地址函数内部使用形参可以修改外部的数据。#include stdio.h void fn1(int n) { n100; } void fn2(int *n) { *n100; } int main() { int num10; printf(num%d\n,num);// 10 fn1(num); printf(num%d\n,num);// 10 fn2(num); printf(num%d\n,num);// 110 return 0; }为什么调用fn1之后num的值还是10呢为什么fn2就是110呢调用fn1(num);这是值传递。main里面num 10调用 fn1 的时候把 num 里面的 10 复制一份给到 fn1 的形参变量n。⚠注意这里是复制一份fn1 里面的n是 fn1 函数自己栈上的局部变量和 main 的num是两块完全独立的内存两个盒子。调用fn2(num);num拿到 main 中 num 的内存地址把这个地址传给形参指针n。fn2 的指针变量n保存的是 main 里面 num 的地址。*n 100*解引用顺着地址直接找到 main 函数的 num 变量修改它里面的数据。main 的 num 直接变成 110。fn2 的指针变量n本身函数结束之后同样会销毁但是它已经通过地址把外面 num 的值改完了。指针函数是个函数返回指针地址注意指针函数不能返回局部变量的地址函数调用结束局部变量被销毁可以返回静态局部变量的地址。#include stdio.h #include string.h // 定义指针函数 返回两个字符串中较长的一个 char *get_longger_string(char *str1, char *str2) { return strlen(str1) strlen(str2) ? str1 : str2; } int main() { char *city Shanghai; printf(较长字符串%s \n, get_longger_string(city, Beijingnan)); return 0; }注意#include stdio.h // 定义函数 int *get_value() { // num 是局部变量函数调用结束会被销毁 int num 250; return num; } int main() { int *ptr get_value(); printf(ptr%p \n , ptr); printf(*ptr%d \n , *ptr); return 0; }错误现象: 编译的时候这串代码是没有问题的但是函数返回局部变量地址后运行时出现内存访问错误原因num是局部变量调用完之后其中的数据会被销毁。调用完之后是能拿到地址但是拿到的地址是销毁后的地址。现代系统会检测到这种错误并将地址重置为0NULL指针如何解决呢设置为静态局部变量。静态局部变量函数调用结束不销毁static int num 250;函数指针是个指针指向一个函数#include stdio.h // 定义函数 double avg(int a, int b) { return (a b) / 2.0; } int main() { // 打印地址 printf(avg: %p \n, avg); printf(avg: %p \n, avg); printf(*avg: %p \n, *avg); return 0; }打印出来的全是地址这是为什么1.avg在 C 语言中函数名会隐式转换为函数的入口地址代表函数代码在内存中存放的起始地址。avg→拿到函数代码块的首地址。2.avg取函数的地址对函数名取地址得到的还是函数入口地址。avg和avg输出结果完全一样。普通变量num是值num是地址两者不一样。 函数特殊avg、avg得到同一个函数入口地址。3.*avg*解引用函数指针。 函数指针解引用得到的还是这个函数本身又会再次转换成函数地址。 所以*avg依然打印函数入口地址。函数指针这套规则很特殊avg、avg、*avg、**avg、***avg全部等价全都是函数入口地址 你写多少层*解引用结果不变。// 调用函数 printf(%.2lf \n, avg(10, 40)); printf(%.2lf \n, (avg)(10, 40)); printf(%.2lf \n, (*avg)(10, 40));算出来的结果都是25.00对于函数avg、avg、*avg、****avg全部是同一个函数入口地址调用的是同一个函数传入同样参数返回值完全一样#include stdio.h // 定义函数 double avg(int a, int b) { return (a b) / 2.0; } int main() { // 函数指针 --------------------------------------------- // 定义函数指针 指针函数 avg 一下三种写法都一样 // double (*ptr)(int, int) avg; // double (*ptr)(int, int) *avg; double (*ptr)(int, int) avg; // 打印 printf(ptr: %p \n, ptr); printf(*ptr: %p \n, *ptr); printf(ptr: %p \n, ptr); // 使用函数指针调用avg printf(%.2lf \n, (*ptr)(70, 40)); printf(%.2lf \n, ptr(70, 40)); // printf(%.2lf \n, (ptr)(70, 40));// 这个不行因为这个是指针自己的地址 return 0; }为什么打印printf(ptr: %p \n, ptr);结果跟前面两个不一样呢因为指针ptr存放的值是函数的地址但是指针有他自己的地址所以取址后得到的是ptr自己的地址。总而言之有了函数的地址就可以调用函数总结函数的代码存放于内存的代码区调用函数的本质就是使用函数代码的地址去调用函数名、函数名、*函数名 都可以获取到函数代码的地址都可以调用函数。回调函数函数指针可以作为某个函数的参数来使用的简单来讲回调函数就是一个通过函数指针调用的函数。就是当参数的才是回调函数。回调函数作为另一个函数的参数在另一个函数的内部可以调用回调函数。// 函数指针声明格式返回值类型 (*指针名)(参数列表);#include stdio.h #include math.h // 定义函数, 需要接收一个函数作为参数 // cb 的类型是 void (*)(), 是个指针指向 void () 类型的数据 void A(void (*cb)()) { // 调用cb指向的函数 cb(); } void fn1() { printf(hello fn1); } // 定义函数实现对数组进行初始化赋值需要接收一个函数作为参数 void initarray(double *arr, int len, double (*cb)(double)) { for (int i 0; i len; i) { arr[i] cb((double)i); } } void fn2() { printf(hello fn2); } // 定义 initArray 的回调函数 double half(double n) { return n / 2; } int main() { A(fn1); printf(\n); double nums[6]; initarray(nums, 6, half); for (int i 0; i 6; i) { printf(%.2lf\n, nums[i]); } printf(\n); initarray(nums, 6, sqrt); for (int i 0; i 6; i) { printf(%.2lf , nums[i]); } printf(\n); initarray(nums, 6, cbrt); for (int i 0; i 6; i) { printf(%.2lf , nums[i]); } printf(\n); return 0; }A(fn1);fn1函数名转换为函数入口地址赋值给形参函数指针cb 在A函数内部执行cb()等价执行fn1()。initarray(nums,6,half);把half函数地址传给形参double (*cb)(double) 循环中arr[i] cb((double)i);实际调用half(i)把返回值赋值给数组。库函数也可以作为回调回调函数思想回调的核心思想框架函数只负责流程把具体业务逻辑交给外部传入的回调函数。 例子initarray只负责循环遍历数组框架生成什么数字交给回调函数half/sqrt/cbrt业务逻辑。 后续想要新的数组赋值规则只需要写新回调函数不用修改initarray内部代码。嵌入式开发中大量使用回调按键中断回调、定时器回调框架触发条件到了自动调用我们写好的回调函数。

相关新闻

一杯奶茶钱,让五个专业设计师帮我做电商主图

一杯奶茶钱,让五个专业设计师帮我做电商主图

我把一个20W的USB充电器插头放在桌上,拍了两张照片,传进了我们平台的AI电商推广。 想看看这支分了五个角色的团队,怎么对付一个没什么设计预算、也没电商经验的新手卖家。 结果有点出乎意料。它先审计了我。 先填表,六个格 打…

2026/8/23 7:27:46 阅读更多 →
数学建模实战:从问题驱动到模型构建与验证的完整闭环

数学建模实战:从问题驱动到模型构建与验证的完整闭环

1. 从“学”到“用”:数学建模学习的核心困境与破局点如果你正在搜索“数学建模学习”,大概率已经看过不少教程,下载过一堆代码,甚至啃过几篇优秀论文。但一个普遍的现象是:很多人学了很久,感觉知识点都懂&…

2026/8/23 7:26:46 阅读更多 →
信息熵贪心策略在Wordle游戏优化中的应用与美赛C题实战解析

信息熵贪心策略在Wordle游戏优化中的应用与美赛C题实战解析

1. 项目概述:从“思路模型代码”到一套完整的竞赛解决方案每年二月的那个周末,对于全球数以万计的大学生来说,都是一个不眠之夜。美国大学生数学建模竞赛(MCM/ICM),我们习惯简称为“美赛”,其C题…

2026/8/23 7:26:46 阅读更多 →

最新新闻

模型构建三大路径:代码驱动、可视化与混合式构建全解析

模型构建三大路径:代码驱动、可视化与混合式构建全解析

1. 项目概述:模型构建的三种核心路径 在数据驱动的决策和自动化流程中,模型构建是核心环节。无论是数据分析师想预测下季度的销售额,还是工程师需要自动化处理地理信息数据,都绕不开“如何构建一个模型”这个问题。我从业这些年&a…

2026/8/23 8:25:28 阅读更多 →
【Agent】【memory】2.Chat Summary Memory Buffer 功能分析

【Agent】【memory】2.Chat Summary Memory Buffer 功能分析

本分析报告针对 LlamaIndex 框架中的 Chat Summary Memory Buffer 功能进行全面解析,这是一个用于管理对话历史的内存缓冲区组件。 1. 案例目标 Chat Summary Memory Buffer 案例的主要目标是: 演示如何使用 ChatSummaryMemoryBuffer 类来管理对话历史…

2026/8/23 8:25:28 阅读更多 →
工业级实时数据可视化系统:WebSocket+Redis+Canvas实战

工业级实时数据可视化系统:WebSocket+Redis+Canvas实战

1. 这不是“画个图表就完事”的玩具系统——它是一套能扛住每秒200数据点、毫秒级响应、生产环境可直接上线的实时可视化骨架你搜“实时数据可视化”时,刷出来的大多是Jupyter里跑个plt.plot()、或者用ECharts配个假数据轮播的Demo。但真正要落地——比如工厂产线传…

2026/8/23 8:25:28 阅读更多 →
描述系统日志架构

描述系统日志架构

系统日志记录操作系统内核和其他进程为系统运行时发生的事件记录日志。这些日志用于系统审核和问题的故障排除。您可以使用文本实用程序(如 less 和 tail 命令)来检查这些日志。红帽企业 Linux 使用基于 syslog 协议的标准日志记录系统来记录系统消息。许…

2026/8/23 8:25:28 阅读更多 →
从工业富联财报看AI转型:利润与现金流背离的技术逻辑分析

从工业富联财报看AI转型:利润与现金流背离的技术逻辑分析

最近在分析上市公司财报时,发现一个很有意思的现象:有些公司利润表光鲜亮丽,但现金流量表却“骨感”得吓人。比如工业富联,其2023年财报显示净利润同比暴增,但经营活动现金流净额却大幅下滑。这背后究竟是AI转型带来的…

2026/8/23 8:25:28 阅读更多 →
深入解析TCP保活机制:原理、配置与高可用长连接实践

深入解析TCP保活机制:原理、配置与高可用长连接实践

1. 项目概述:TCP保活机制是什么,以及我们为什么需要它在网络编程和系统运维的日常里,TCP连接就像一条条看不见的“数据管道”,连接着客户端和服务器。我们通常认为,一旦握手成功建立了连接,这条管道就是稳定…

2026/8/23 8:24:28 阅读更多 →

日新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

周新闻

[光学原理与应用-521]:对光的错误理解与纠偏

[光学原理与应用-521]:对光的错误理解与纠偏

首先光是一种能量的载体和形态,宏观上观察到的光是由无数个微观的光量子组成的,每个光子在产生的瞬间,其在真空的空间中以确定不变的速度沿着一个初始的方向一直向前,在微观层面,每个光量子的运动轨迹是以波函数所展现…

2026/8/23 0:00:50 阅读更多 →
SIP通话转接原理与REFER方法实战解析

SIP通话转接原理与REFER方法实战解析

1. 通话转接不是“挂断再拨号”,而是SIP会话的动态重定向你有没有遇到过这样的场景:客服坐席A正在和客户通电话,突然需要把这通对话无缝转给专家坐席B,客户完全感知不到中间的断连——既没听到忙音,也没被要求重新拨号…

2026/8/23 0:00:50 阅读更多 →
Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

Kolla-ansible单节点OpenStack部署实战:从环境准备到排坑指南

1. 为什么选择Kolla-ansible来部署单节点OpenStack?如果你正在寻找一种能把OpenStack从“概念”快速变成“可用的实验环境”的方法,那么Kolla-ansible几乎是当前最主流、最省心的选择。我见过太多人卡在手动编译依赖、配置服务、处理版本冲突的泥潭里&am…

2026/8/23 0:00:50 阅读更多 →

月新闻

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南

免费解锁百度网盘SVIP加速:macOS用户必备的下载提速终极指南 【免费下载链接】BaiduNetdiskPlugin-macOS For macOS.百度网盘 破解SVIP、下载速度限制~ 项目地址: https://gitcode.com/gh_mirrors/ba/BaiduNetdiskPlugin-macOS 还在为百度网盘macOS版的龟速下…

2026/8/22 18:08:39 阅读更多 →
终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换

终极ncmdump指南:3分钟实现网易云NCM音乐解密与格式转换 【免费下载链接】ncmdump 项目地址: https://gitcode.com/gh_mirrors/ncmd/ncmdump 还在为网易云音乐下载的NCM格式文件无法在其他播放器播放而烦恼吗?ncmdump解密工具帮你轻松解决这个困…

2026/8/22 7:31:03 阅读更多 →
HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

HarmonyOS 应用开发《掌上英语》第81篇: 智能体卡片:为英语学习 App 打造桌面级学习助手

AgentCard 智能体卡片:为英语学习 App 打造桌面级学习助手适用平台:HarmonyOS 7.0 (API 26 Beta)一、引言 HarmonyOS 7.0(API 26 Beta)新增了 AgentCard 智能体卡片能力,这是继 HMAF(鸿蒙智能体框架&#x…

2026/8/22 3:22:48 阅读更多 →