C语言——深入理解指针(3)
目录
1. 字符指针
2. 数组指针
2.1 数组指针变量
2.2 数组指针变量的初始化
3.二维数组传参(本质)
4. 函数指针
4.1 函数指针变量的创建
4.2 函数指针的使用
4.3 typedef
5. 函数指针数组
6. 转移表(函数指针数组的使用)

1. 字符指针
在指针的类型中有一种指针类型为字符指针 char*
#include<stdio.h>
int main()
{char ch = 'h';char* pc = &ch;//pc就是字符指针const char* pstr = "hello";//常量字符串//这里不是把字符串存在p中,而是把第一个字符的地址存放在p中//1,你可以把字符串相信成一个字符数组//2.当常量字符串出现在表达式中的时候,他点值是第一个字符的地址printf("%c\n", "hello"[3]);printf("%s\n", pstr);
}

举例:
#include <stdio.h>
int main()
{char str1[] = "hello bit.";char str2[] = "hello bit.";const char* str3 = "hello bit.";const char* str4 = "hello bit.";if (str1 == str2)//str1和str2是两个不同地址的字符数组。printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)//str3和str4指向的是同一个常量字符串。printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
注意:内容相同的常量字符串只会保存一份。
2. 数组指针
2.1 数组指针变量
在前面的文章中,我们学了指针数组,它是一种数组,里面存的是地址(指针)。
数组指针其实跟指针数组不同,数组指针是:指针变量。
我们回忆一下指针之前的一些指针变量:
整形指针变量: int * p1; 存放的是整形变量的地址,能够指向整形数据的指针。
浮点型指针变量: float * p2; 存放浮点型变量的地址,能够指向浮点型数据的指针。
那么数组指针变量就应该是:存放的是数组的地址,能够指向数组的指针变量。
数组指针变量
int (*p)[10];
p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。
注意:[]的优先级要高于*号的,所以必须加上()来保证p先和*结合
2.2 数组指针变量的初始化
int arr[10] = {0};
&arr;//得到的就是数组的地址
int(*p)[10] = &arr;//p数组指针指向arr数组的指针
&arr表示整个数组的地址
数组指针类型:
int (*p) [10] = &arr;| | || | || | p指向数组的元素个数| p是数组指针变量名p指向的数组的元素类型
3.二维数组传参(本质)
之前我们需要把一个二维数组传参给一个函数的时候,我们是这么写的
#include <stdio.h>
void test(int a[3][5], int r, int c)//这里的形参是二维数组
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
那还有什么其他的写法吗?

我们可以看到二维数组可以被分为多个一维数组,可以把每个一维数组看成一个元素,那么二维数组的首元素就是第一个一维数组。根据数组名是数组⾸元素的地址这个规则,⼆维数组的数组名表示的就是第⼀⾏的地址,是⼀维数组的地址。既然是数组地址我们就要用数组指针 int (*p)来存,但是一维数组里面还有很多数,这时我们就要在数组指针后面加个数组 int(*p)[] ,来把这些数存下来。
⼆维数组传参本质上也是传递了地址,传递的是第⼀行这个⼀维数组的地址。
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
#include <stdio.h>
void test(int (*p)[5], int r, int c)
{int i = 0;int j = 0;for (i = 0; i < r; i++){for (j = 0; j < c; j++){printf("%d ", a[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5}, {2,3,4,5,6},{3,4,5,6,7} };test(arr, 3, 5);return 0;
}
总结:⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
4. 函数指针
4.1 函数指针变量的创建
根据我们前面学的指针变量,我们大概可以推出,函数指针变量就是用来存放函数地址的,后面可以通过地址来调用函数。

函数是有地址的,且函数名就是函数的地址,我们可以通过&函数来获得函数的地址。要存地址,那就要用到指针,存函数的地址,就要用函数指针。函数指针的创建跟数组指针差不多。
int (*p) (int x, int y)| | ------------ | | || | p指向函数的参数类型和个数的交代| || 函数指针变量名|p指向函数的返回类型
举例:
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//int(*pf3)(int, int) = Add;int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的printf("%p\n", pf3);return 0;
}
4.2 函数指针的使用
#include <stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{//int(*pf3)(int, int) = Add;int(*pf3)(int x, int y) = &Add;printf("%d\n", pf3(1, 2));//pf3(1, 2)==Add(1,2)printf("%d\n", (*pf3)(1, 2));return 0;
}
我们根据之前学的来看两个代码
(*(void (*)())0)();
void (*signal(int , void(*)(int)))(int);
4.3 typedef
typedef 是用来给类型重名的,可以将复杂的类型,简单化。
typedef unsigned int uint;
//将unsigned int 重命名为uint
指针类型一样可以重命名。
typedef int* ptr_t;
//将 int* 重命名为 ptr_t
注意:数组指针和函数指针的类型重名有点不同
数组指针:
typedef int(*parr_t)[5]; //新的类型名必须在*的右边
//将指针类型 int(*)[5] ,重命名为 parr_t
函数指针:
typedef void(*pfun_t)(int);//新的类型名必须在*的右边
//将 void(*)(int) 类型重命名为 pf_t
5. 函数指针数组
数组是一个存放相同类型数组空间。那把函数的地址存到⼀个数组中,那这个数组就叫函数指针数组。
int (*parr1[3])();
int (*)() 类型的函数指针。
6. 转移表(函数指针数组的使用)
计算机的实现:
#include <stdio.h>
int add(int a, int b)
{return a + b;
}
int sub(int a, int b)
{return a - b;
}
int mul(int a, int b)
{return a * b;
}
int div(int a, int b)
{return a / b;
}
int main()
{int x, y;int input = 1;int ret = 0;int(*p[5])(int x, int y) = { 0, add, sub, mul, div }; //转移表--函数指针数组的存入do{printf("*************************\n");printf(" 1:add 2:sub \n");printf(" 3:mul 4:div \n");printf(" 0:exit \n");printf("*************************\n");printf("请选择:");scanf("%d", &input);if ((input <= 4 && input >= 1)){printf("输入要求的数:");scanf("%d %d", &x, &y);ret = (*p[input])(x, y);//函数指针数组的元素使用printf("ret = %d\n", ret);}else if (input == 0){printf("退出计算器\n");}else{printf("输入错误,请重新输入\n");}} while (input);return 0;
}相关文章:
C语言——深入理解指针(3)
目录 1. 字符指针 2. 数组指针 2.1 数组指针变量 2.2 数组指针变量的初始化 3.二维数组传参(本质) 4. 函数指针 4.1 函数指针变量的创建 4.2 函数指针的使用 4.3 typedef 5. 函数指针数组 6. 转移表(函数指针数组的使用ÿ…...
图书管理系统源码,图书管理系统开发,图书借阅系统源码配置和运行图解源码已附加
目录 配置简介和软件条件 数据库附件配置 vs应用程序web.config配置数据库链接字符串 数据库文件脚本代码 配置简介和软件条件 所需要的软件是Vs2017以上数据库是Sqlserver2012以上,如果数据库附件不了可以使用数据库脚本附件数据库脚本会在文章末尾写出来。可以…...
FFmpeg介绍
官方网站:http://www.ffmpeg.org/ 项目组成 libavformat 封装模块,封装了Protocol层和Demuxer、Muxer层,使得协议和格式对于开发者来说是透明的。FFmpeg能否支持一种封装格式的视频的封装与解封装,完全取决于这个库,…...
修改网卡PHY的灯-RK3568
文章目录 前言1.定制PHY的灯2.通过命令修改LED状态3.修改驱动效果前言 前面我们已经移植了网卡到开发板上面,也能够正常的进行通信,但是,我们会发现座子上面的灯并没有全部亮起来,而且这些灯的含义是什么,并没有讲解到,这里,就此问题,展开学习。 PHY 有一个重要的功能…...
11月29日作业
作业: 自己封装一个矩形类(Rect),拥有私有属性:宽度(width)、高度(height), 定义公有成员函数: 初始化函数:void init(int w, int h) 更改宽度的函数:set_w(int w) 更改高度的函数:set_h(int h) 输出该矩形的周长和面积函数:void show(…...
【从删库到跑路 | MySQL总结篇】表的增删查改(进阶下)
个人主页:兜里有颗棉花糖 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 兜里有颗棉花糖 原创 收录于专栏【MySQL学习专栏】🎈 本专栏旨在分享学习MySQL的一点学习心得,欢迎大家在评论区讨论💌 目录 一、联合…...
【机器学习 | 可视化系列】可视化系列 之 决策树可视化
🤵♂️ 个人主页: AI_magician 📡主页地址: 作者简介:CSDN内容合伙人,全栈领域优质创作者。 👨💻景愿:旨在于能和更多的热爱计算机的伙伴一起成长!!&…...
配置阿里云的yum仓库
目录 配置阿里云的yum源 清理官方yum源 下载阿里云的yum源 centos7下载阿里云yum源: 清理yum缓存:yum cleam all 生成自己的yum缓存:yum makecache 使用centos自带的官方yum源下载很慢,那今天来跟大家说说配置阿里云的yum仓…...
Kubernetes之kubeadm日志展示篇—K8S私有云worker节点gluster安装部署
文章目录 一. 服务器信息1.1 环境准备1.2 配置hosts解析记录 二. 安装与部署2.1 配置仓库 (所有节点)2.2 安装服务 (所有节点)2.3 启动服务 (所有节点)2.4 配置资源池 (主节点)2.5 创…...
P3368 【模板】树状数组 2 (区间修改,单点查询)
本题链接:【模板】树状数组 2 - 洛谷 题目: 输入 5 5 1 5 4 2 3 1 2 4 2 2 3 1 1 5 -1 1 3 5 7 2 4 输出 6 10 思路: 根据题意,这里是需要区间添加值,单点查询值。如果区间添加值中暴力去一个个加值,肯定…...
智慧城市运营管理平台解决方案:PPT全文61页,附下载
关键词:智慧城市建设方案,智慧城市解决方案,智慧城市的发展前景和趋势,智慧城市建设内容,智慧城市运营管理平台 一、智慧城市运营平台建设背景 随着城市化进程的加速,城市面临着诸多挑战,如环…...
Vue性能优化方法
一、前言 1.1 为什么需要性能优化 用户体验:优化性能可以提升用户体验,降低加载时间和响应时间,让用户更快地看到页面内容。SEO优化:搜索引擎更喜欢快速响应的网站,优化性能可以提高网站的排名。节约成本࿱…...
关于网站的favicon.ico图标的设置需要注意的几点
01-必须在网页的head标签中放上对icon图标的说明语句: 比如下面这样的语句: <link rel"shortcut icon" href"/favicon.ico">否则,浏览器虽然能读到图标,但是不会把图标显示在标签上。 02-为了和本地开…...
PHP中关于func_get_args()方法
首先呢这个函数出现的是比较早的,大致应该是PHP4出现的, func_get_args — 返回一个包含函数参数列表的数组 说明 func_get_args(): array 获取函数参数列表的数组。 该函数可以配合 func_get_arg() 和 func_num_args() 一起使用,从而使得用户自定义函数可以接…...
EMA训练微调
就是取前几个epoch的weight的平均值,可以缓解微调时的灾难性遗忘(因为新数据引导,模型权重逐渐,偏离训练时学到的数据分布,忘记之前学好的先验知识) class EMA():def __init__(self, model, decay):self.…...
Kafka集群部署详细教程
版本说明 Ubuntu 18.04.6Zookeeper 3.5.9Kafka 2.7.0JDK8 集群配置 操作系统ip域名Zookeeper 端口Kafka 端口Ubuntu 18.04.6192.168.50.131kafka1.com21819092Ubuntu 18.04.6192.168.50.132kafka2.com21819092Ubuntu 18.04.6192.168.50.133kafka3.com21819092 安装 vim, cu…...
交叉编译
1. 交叉开发 交叉编译: 在电脑把程序编写 编译 调试好 再下载到嵌入式产品中运行 编译: gcc 之前编译环境和运行环境是一样的 交叉编译: 编译 把编译代码和运行分开 编译代码在虚拟机中 运行…...
数据结构与算法之递归: LeetCode 46. 全排列 (Typescript版)
全排列 https://leetcode.cn/problems/permutations/ 描述 给定一个不含重复数字的数组 nums ,返回其 所有可能的全排列 。你可以 按任意顺序 返回答案。 示例 1 输入:nums [1,2,3] 输出:[[1,2,3],[1,3,2],[2,1,3],[2,3,1],[3,1,2],[3,…...
SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接)
SQL中 JOIN 的两种连接类型:内连接(自然连接、自连接、交叉连接)、外连接(左外连接、右外连接、全外连接) 1. 自然连接(natural join)(内连接) 学生表 mysql> sele…...
微信小程序记住密码,让登录解放双手
密码是用户最重要的数据,也是系统最需要保护的数据,我们在登录的时候需要用账号密码请求登录接口,如果用户勾选记住密码,那么下一次登录时,我们需要将账号密码回填到输入框,用户可以直接登录系统。我们分别…...
zRenamer 1.9 批量重命名工具
一、软件背景 1. 核心痛点来源 日常文件管理中,用户长期面临批量重命名低效、混乱、易出错的核心痛点: 手动操作繁琐:零散文件(照片、文档、视频)命名无规则,手动修改数百个文件耗时极长,重复…...
html 列表和表格的使用
1:列表是以结构化,易读性更强的方式提供信息的方法,我们学习了有序列表和无序列表。有序列表特点是有先后顺序,用数字,字母或数字标记,适合步骤,排名,流程,核心标签<o…...
Seaborn 绘图基础
在 Python 的数据可视化生态中,Seaborn 是建立在 Matplotlib 之上的高级统计绘图库。它面向数据分析任务提供了更直接的绘图接口,能够围绕变量的分布、关系与结构组织图形表达,因此特别适合教学入门与探索性数据分析。与只关注“如何画出线、…...
数学建模实战书籍精选:从入门到竞赛的全方位指南
1. 为什么你需要一本好的数学建模书? 数学建模就像学做菜,光看菜谱不动手永远成不了大厨。我见过太多同学抱着《高等数学》死磕,结果遇到实际问题连最简单的线性规划都写不出来。一本好的实战书能帮你少走三年弯路——当年我第一次参加国赛&a…...
COMSOL超声相控阵仿真模型 模型介绍:本链接有两个模型,分别使用压力声学与固体力学对超声相...
COMSOL超声相控阵仿真模型 模型介绍:本链接有两个模型,分别使用压力声学与固体力学对超声相控阵无损检测进行仿真,负有模型说明。 使用者可自定义阵元数、激发频率、激发间隔等参数,可激发出聚焦、平面等波形,可以一次…...
9. C++14新特性-std::tuple 的按类型寻址 (Type-based Tuple Addressing)
一、引言在现代 C 中,当我们想要在一个函数中返回多个不同类型的值,或者临时打包几个数据时,std::tuple(元组)是最标准的容器。然而,C11 提供的基于索引的元组访问方式,在工程实践中暴露出严重的…...
新手福音:通过快马平台零代码基础玩转picoclaw机器人板
作为一个刚接触嵌入式开发的新手,拿到picoclaw控制器时既兴奋又忐忑。这块小小的板子能控制电机、读取传感器,但如何让它动起来却让我一头雾水。好在发现了InsCode(快马)平台,不需要从零开始啃文档,就能快速生成可运行的示例代码。…...
闲置U盘秒变神器!Windows 11密码重置盘制作保姆级教程(含32/64位系统差异说明)
闲置U盘秒变系统急救神器:Windows 11密码重置盘全流程精解 那个抽屉角落积灰的旧U盘,可能比你想象中更有价值。当Windows 11的登录界面无情拒绝你输入的密码时,一个预先制作的密码重置盘就是打开数字大门的备用钥匙。不同于网上流传的简易教程…...
STM32H7 SPI4 FLASH HAL库配置优化实践
1. STM32H7 SPI4与FLASH通信基础 最近在做一个基于STM32H743IIT6的项目时,遇到了SPI4与FLASH通信的配置问题。SPI4工作在50MHz的高时钟频率下,调试过程中发现了一些有趣的细节。比如分频系数低于SPI_BAUDRATEPRESCALER_8时读取就会失败,而高于…...
多层循环神经网络|Multi-layer RNNs
----------------------------------------------------------------------------------------------- 这是我在我的网站中截取的文章,有更多的文章欢迎来访问我自己的博客网站rn.berlinlian.cn,这里还有很多有关计算机的知识,欢迎进行留言或…...
