当前位置: 首页 > news >正文

善于运用指针--函数与指针

 

文章目录

  • 前言
  • 一、函数的指针
  • 二、函数指针运用
    • 1函数名地址
    • 2指针变量调用函数
    • 3指向函数的指针变量做函数参数
  • 二、返回指针值的函数
  • 总结

 


 

前言

如果在程序中定义了一个函数,在编译时会把函数的源代码转换为可执行代码并分配一段空间。这段空间有一个起始地址,也称为函数的入口地址。每次调用函数时都从该地址入口开始执行此函数代码。 


一、函数的指针

函数名就是函数的起始地址,就是函数的指针。

01f28c84c06e499b94c052cfbb34d8ac.png

二、函数指针运用

1.函数名地址

代码如下(示例):

int add(int x, int y)
{return x + y;
}
int main()
{printf("%p", add);//打印函数地址return 0;
}

打印结果为00007FF6BC9013D9 ,是函数地址,由此可见函数名是一个地址,定义指针变量可以将函数名直接赋给指针变量。


2.指针变量调用函数

代码如下(示例):

void swap(int*p1, int*p2)
{int tmp = *p1;*p1 = *p2;*p2 = tmp;
}
int main()
{int arr[] = { 1,2,3,4,5 };//swap(&arr[1], &arr[4]);  void (*pc)(int*, int*) = swap;//定义指向函数的指针变量(*pc)(&arr[1], &arr[4]);//用指针变量调用swap函数int i = 0;for (i = 0; i < 5; i++){printf("%d ", arr[i]);}return 0;
}

该处可以看出,swap函数的调用,指针*pc对应函数名,括号后面调用一样。

但是得注意,定义指针变量指向函数名(也就是函数地址)时,定义的类型应与函数返回值类型一致,后面括号里的量也应与被调函数的定义保持一致。

在给指针变量赋值时,只需给出函数名,无需给出函数参数。void (*pc)(int*, int*) = swap;

用指针变量调用函数时,只需用*pc代替函数名,在(*p)的括号根据需要写上实参

6fdfcd6ce1e04e12a360f424374a1710.png

函数指针变量不能进行算数运算

用函数名调用函数,只能调用所指定的一个函数,但是用指针变量调用函数,可以根据不同情况先后调用不同函数。

注意:定义的pc指针,只能指向参数类型为int、int,返回类型为void的函数。


3、用指向函数的指针做函数参数

指向函数的指针,把函数地址作为参数传递给其它函数 

用指向函数的指针做函数参数,这个函数的返回值类型是一个指针,参数是函数指针的参数


设计一个计算器,实现加减乘除:

代码如下:

void print()
{printf("********************************\n");printf("***** 1.add     2.sub **********\n");printf("***** 3.mul     4.div **********\n");printf("*****    0.esc   ***************\n");
}
int add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int mul(int x, int y)
{return x * y;
}
int div(int x, int y)
{return x / y;
}
int main()
{int a = 0;int b = 0;int ret = 0;int input = 0;print();scanf("%d", &input);switch (input){case 1:printf("请输入两个数\n");scanf("%d%d", &a, &b);ret=add(a, b);printf("%d", ret);break;case 2:printf("请输入两个数\n");scanf("%d%d", &a, &b);ret = sub(a, b);printf("%d", ret);break;case 3:printf("请输入两个数\n");scanf("%d%d", &a, &b);ret = mul(a, b);printf("%d", ret);break;case 4:printf("请输入两个数\n");scanf("%d%d", &a, &b);ret = div(a, b);printf("%d", ret);break;default:printf("输入错误");break;}return 0;
}

这里在case里反复重复的内容太多,代码不够简洁,这里add、sub、mul、div的函数参数和返回值都是同样类型的,因此可定义一个指针(即*p)用来指向这几个函数,再定义一个指针函数,参数为指向这几个函数的指针(即*p)


代码如下: 

void col(int(*p)(int,int))
{int a = 0;int b = 0;int ret = 0;printf("请输入两个数\n");scanf("%d%d", &a, &b);ret =(*p)(a, b);printf("%d", ret);
}void print()
{printf("********************************\n");printf("***** 1.add     2.sub **********\n");printf("***** 3.mul     4.div **********\n");printf("*****    0.esc   ***************\n");
}
int add(int x, int y)
{return x + y;
}
int sub(int x, int y)
{return x - y;
}
int mul(int x, int y)
{return x * y;
}
int div(int x, int y)
{return x / y;
}
int main()
{int input = 0;print();scanf("%d", &input);switch (input){case 1:col(add);break;case 2:col(sub);break;case 3:col(mul);break;case 4:col(div);break;default:printf("输入错误");break;}return 0;
}

这样的程序更简洁,更具可读性。


三、返回指针值的函数

函数返回值是一个地址或者指针。

字符串拷贝函数 

char* string_copy(char* str1, char* str2)
{char* start = str2;while (*str2++ = *str1++);return start;
}
int main()
{char arr1[] = "abcdef";char arr2[20] = { 0 };char* ret = string_copy(arr1, arr2);printf("% s\n", ret);return 0;
}

如上,函数的返回值是一个指针,这里将函数返回值赋给ret这个指针,通过指针指向的地址找到并打印字符,如果解引用,找到的会是字符数组的首地址的内容,只能打印“a”

在这里,%s, 传参ret是一个地址,打印该地址对应的字符串,遇到\0停止。

在C语言中,找到地址就相当于找到了值。


找学生序号对应的分数

int *score(int(*p)[3], int n)
{return *(p + n);
}
int main()
{int n = 0;int arr[][3] = { {1,2,3},{4,5,6},{7,8,9} };int i = 0;scanf("%d", &n);int* p = score(arr, n);for (i = 0; i < 3; i++){printf("%d", *(p + i));}return 0;
}

 这个地方的解引用是二维数组某行的首地址,也就是找到地址对应的行,依次打印数字

总结

(未完待续...)

 

相关文章:

善于运用指针--函数与指针

文章目录 前言一、函数的指针二、函数指针运用 1函数名地址2指针变量调用函数3指向函数的指针变量做函数参数二、返回指针值的函数总结 前言 如果在程序中定义了一个函数&#xff0c;在编译时会把函数的源代码转换为可执行代码并分配一段空间。这段空间有一个起始地址&#xf…...

Microi吾码低代码平台:前端源码的本地运行探索

文章目录 1.前端源码运行环境要求1.1 操作系统1.2 必备软件工具1.3 项目源码依赖 2.从Git仓库克隆前端源码3.安装项目依赖4.启动本地开发服务器5.常见问题与解决方案5.1 依赖安装失败5.2 端口冲突5.3 代码更新未生效 6.提升本地开发体验的技巧6.1 使用代理解决跨域问题6.2 集成…...

十一、容器化 vs 虚拟化-Docker 使用

文章目录 前言一、Docker Hello World二、Docker 容器使用三、Docker 镜像使用四、Docker 容器连接五、Docker 仓库管理六、Docker Dockerfile七、Docker Compose八、Docker Machine九、Swarm 集群管理 前言 Docker 使用‌ Docker 容器使用、镜像使用、容器连接、仓库管理、Do…...

实践项目2-自动计价电子秤

自动计价电子秤 一、功能说明 基于AVR单片机设计一自动计价电子秤。根据输入的价格以及检测的重量自动计算总价并打印&#xff08;串口模拟&#xff09;。 二、具体要求 1、开机后实时检测重量并显示&#xff1b; 2、通过按键输入并显示价格&#xff0c;具有修改功能&#…...

iOS如何操作更新推送证书

最近收到一份邮件,应该如何操作呢,证书还是跟以前一样冲钥匙串直接申请吗 Hello, As we announced in October, the Certification Authority (CA) for Apple Push Notification service (APNs) is changing. APNs will update the server certificates in sandbox on January…...

WSL2 在vscode无法连接copilot

报错情况&#xff1a; 本机可以使用copilot&#xff0c;但在WSL2上无法连接&#xff0c;报错信息如下&#xff1a; 检查网络情况&#xff1a; ping api.github.com 发现无法连接&#xff1a; github.com:Temporary failure in name resolution 在网上搜集的解决方法&#…...

HTA8998 实时音频跟踪的高效内置升压2x10W免电感立体声ABID类音频功放

1、特征 输出功率(fIN1kHz,RL4Ω&#xff0c;BTL) VBAT 4V, 2x10.6W(VOUT9V,THDN10%) VBAT 4V, 2x8.6W (VOUT9V,THDN1%) 内置升压电路模式可选择:自适应实时音频跟踪 升压(可提升播放时间50%以上)、强制升压 最大升压值可选择&#xff0c;升压限流值可设置 ACF防破音功能 D类…...

用ChatGPT-o1进行论文内容润色效果怎么样?

目录 1.引导问题发现 2.角色设定 3.整理常问修改 4.提供样例 5.小细节 小编在这篇文章中分享如何充分利用ChatGPT-o1-preview来提升论文润色的技巧。小编将持续跟进最新资源和最新的调研尝试结果&#xff0c;为宝子们补充更多实用的写作技巧。这些技巧将有助于您更有效地利…...

《探索 Jetpack Compose:构建现代化 Android UI 的利器》

Jetpack Compose 是谷歌推出的现代化 UI 框架&#xff0c;用于简化 Android 应用开发中的 UI 构建。它使用声明式编程方式&#xff0c;允许开发者以简洁直观的方式创建动态和响应式的 UI。本文将从基础概念到进阶用法&#xff0c;带你全面了解 Compose 的核心功能和使用技巧。 …...

cocos creator 的 widget组件的使用及踩坑

以下的内容基于cocos creator 3.8版本&#xff0c;如有错误&#xff0c;恳请指出。 &#x1f449;官方文档的指引 应用&#xff1a;以上官方指引有非常清晰的使用方式&#xff0c;接下来说明一些注意事项&#xff1a; 1、与canvas搭配的使用&#xff0c;解决多分别率适配问题。…...

Baumer工业相机的EMVA1288 数据报告简介

项目场景&#xff1a; Baumer工业相机堡盟VCX系列和VLX系列为堡盟全系列相机中的主流常用相机和高端相机&#xff0c;性能强大、坚固可靠&#xff0c;易于集成&#xff0c;常用与一般行业的检测定位识别使用。 对应的高端相机系列具有极为丰富的强大技术功能&#xff0c;可轻…...

Docker 安装 中文版 GitLab

Docker 安装系列 安装GitLab、解决服务器内存不足问题、使用域名/IP地址访问项目 1、拉取 [rootTseng ~]# docker pull twang2218/gitlab-ce-zh:latest latest: Pulling from twang2218/gitlab-ce-zh 8ee29e426c26: Pull complete 6e83b260b73b: Pull complete e26b65fd11…...

uni-app 个人课程表页面

uni-app 个人课程表页面 插件参考地址 大部分代码都是参考了上述代码&#xff0c;只对代码做出了优化 1. 页面模板 在 schedule.vue 文件中&#xff0c;编写页面结构&#xff1a; <template><view><u-navbar title"个人中心"><view class&q…...

FPGA工作原理、架构及底层资源

FPGA工作原理、架构及底层资源 文章目录 FPGA工作原理、架构及底层资源前言一、FPGA工作原理二、FPGA架构及底层资源 1.FPGA架构2.FPGA底层资源 2.1可编程输入/输出单元简称&#xff08;IOB&#xff09;2.2可配置逻辑块2.3丰富的布线资源2.4数字时钟管理模块(DCM)2.5嵌入式块 …...

【OpenCV】平滑图像

二维卷积(图像滤波) 与一维信号一样&#xff0c;图像也可以通过各种低通滤波器&#xff08;LPF&#xff09;、高通滤波器&#xff08;HPF&#xff09;等进行过滤。LPF 有助于消除噪音、模糊图像等。HPF 滤波器有助于在图像中找到边缘。 opencv 提供了函数 **cv.filter2D()**&…...

LeetCode300. 最长递增子序列(2024冬季每日一题 30)

给你一个整数数组 nums &#xff0c;找到其中最长严格递增子序列的长度。 子序列 是由数组派生而来的序列&#xff0c;删除&#xff08;或不删除&#xff09;数组中的元素而不改变其余元素的顺序。例如&#xff0c;[3,6,2,7] 是数组 [0,3,1,6,2,2,7] 的 子序列。 示例 1&…...

vue H5如何实现copy功能

vue H5如何实现copy功能 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><link rel"stylesheet" href"https://unpkg.com/vant2.12/lib/index.css" /><title></title><st…...

Golang使用etcd构建分布式锁案例

在本教程中&#xff0c;我们将学习如何使用Go和etcd构建分布式锁系统。分布式锁系统对于管理对分布式系统中共享资源的并发访问至关重要。它有助于维护一致性&#xff0c;防止竞争条件&#xff0c;并确保在任何给定时间只有一个进程独占访问资源。 我们将使用Go作为编程语言&am…...

Windows 和 Ubuntu 双系统安装

复现论文的时候&#xff0c;个别包只有Linux版本&#xff0c;并且源码编译比较麻烦&#xff0c;所以干脆直接安装一个双系统&#xff08;WinUbuntu&#xff09;&#xff0c;方便复现论文。 参考视频链接&#xff1a;Windows 和 Ubuntu 双系统的安装和卸载 0.所需工具 4G以上U…...

多媒体文件解复用(Demuxing)过程

多媒体文件的解复用&#xff08;Demuxing&#xff09;过程指的是从一个多媒体容器文件&#xff08;如 MP4、MKV、AVI 等&#xff09;中提取不同类型的多媒体数据流&#xff08;例如视频流、音频流、字幕流等&#xff09;的过程。 容器文件本身并不包含实际的视频或音频数据&…...

Windows Cleaner:如何系统性地解决Windows磁盘空间管理难题

Windows Cleaner&#xff1a;如何系统性地解决Windows磁盘空间管理难题 【免费下载链接】WindowsCleaner Windows Cleaner——专治C盘爆红及各种不服&#xff01; 项目地址: https://gitcode.com/gh_mirrors/wi/WindowsCleaner Windows Cleaner是一款基于Python和PyQt5框…...

别再瞎学 C 语言了!真・胎教级入门教程 | NO.3 万字详解分支与循环 | 下篇

欢迎大家来到<<别再瞎学 C 语言了&#xff01;真・胎教级入门教程 | NO.3 万字详解分支与循环>>下篇学习.在上期中我们已经了解了分支与循环中的if语句,关系操作符,条件操作符,逻辑操作符和switch语句.这一期我们继续来了解剩下的内容.6. while循环在C语言中有三种…...

WechatDecrypt:3步快速解密微信聊天记录的终极指南

WechatDecrypt&#xff1a;3步快速解密微信聊天记录的终极指南 【免费下载链接】WechatDecrypt 微信消息解密工具 项目地址: https://gitcode.com/gh_mirrors/we/WechatDecrypt 还在为无法查看加密的微信聊天记录而烦恼吗&#xff1f;WechatDecrypt是一款专业的微信消息…...

从AMD Ryzen数据误读看硬件市场分析:如何辨别数据信号与噪声

1. 从一则旧闻谈起&#xff1a;数据解读的陷阱与行业洞察2017年7月&#xff0c;一则关于AMD Ryzen处理器市场份额的新闻在科技圈引发了不小的讨论。当时&#xff0c;多家媒体援引第三方基准测试软件Passmark的数据&#xff0c;宣称AMD凭借新发布的Ryzen架构&#xff0c;正在从英…...

ANSYS Maxwell 静电仿真避坑指南:模型设置、求解失败与结果解读的5个常见问题

ANSYS Maxwell 静电仿真避坑指南&#xff1a;模型设置、求解失败与结果解读的5个常见问题 当你第一次成功运行ANSYS Maxwell的静电仿真时&#xff0c;那种成就感是真实的。但很快你会发现&#xff0c;能跑通仿真和得到可信结果之间&#xff0c;隔着无数个深夜调试的坑。这篇文章…...

基于RAG的AI知识库构建:从原理到工程实践

1. 项目概述&#xff1a;一个面向AI的知识库构建方案最近在折腾AI应用开发的朋友&#xff0c;估计都绕不开一个核心问题&#xff1a;如何让大语言模型&#xff08;LLM&#xff09;更精准、更可靠地使用你自己的数据&#xff1f;无论是想打造一个能回答公司内部文档问题的智能客…...

从LTV-M501到系统集成:高速光耦隔离通信的选型与实战设计

1. 高速光耦隔离通信的核心价值 第一次接触工业现场总线改造项目时&#xff0c;我被电机控制器和PLC之间的通信干扰问题折磨了整整两周。直到老工程师递给我几个LTV-M501光耦&#xff0c;问题才迎刃而解。这种通过光信号传递电信号的器件&#xff0c;就像给通信线路装上了"…...

深入STM32以太网驱动层:DP83848 PHY芯片初始化、中断处理与lwip数据收发的HAL库实现详解

STM32与DP83848以太网驱动开发实战&#xff1a;从PHY初始化到lwIP协议栈深度整合 在嵌入式系统开发中&#xff0c;以太网通信已成为工业控制、物联网网关等场景的标配功能。本文将深入探讨基于STM32F1系列微控制器与DP83848物理层芯片的以太网驱动开发全流程&#xff0c;重点剖…...

蓝牙技术与FPGA实现:原理、优化与实践

1. 蓝牙技术基础与核心原理蓝牙技术自1994年由爱立信首次提出以来&#xff0c;已成为短距离无线通信领域的事实标准。这项技术之所以能在众多无线方案中脱颖而出&#xff0c;关键在于其独特的物理层设计和灵活的协议架构。1.1 2.4GHz ISM频段特性蓝牙工作在2.4GHz工业、科学和医…...

ReportPortal故障排除:常见部署问题和解决方案大全

ReportPortal故障排除&#xff1a;常见部署问题和解决方案大全 【免费下载链接】reportportal Main Repository. ReportPortal starts here - see readme below. 项目地址: https://gitcode.com/gh_mirrors/re/reportportal ReportPortal是一款功能强大的测试自动化报告…...