关于我、重生到500年前凭借C语言改变世界科技vlog.13——深入理解指针(3)
文章目录
- 1.字符指针变量
- 2.数组指针变量
- 3.函数指针变量
- 4.函数指针数组
- 5.二维数组传参本质
- 6.拓展补充
- 希望读者们多多三连支持
- 小编会继续更新
- 你们的鼓励就是我前进的动力!
本章节接着学习常见的指针变量类型
1.字符指针变量
字符指针变量,顾名思义就是字符类型的指针,即 char*
常见的输出格式是这样的:
int main()
{char ch = 'w';char *pc = &ch;*pc = 'w';return 0;
}
这是存放一个字符的情况,如果存放字符串呢?
int main()
{const char* pstr = "hello bit.";printf("%s\n", pstr);return 0;
}
乍一看是存放字符串在指针变量中,但我们要记住指针变量是用来存放地址的
所以这里本质是把字符串 hello bit. 首字符的地址放到了pstr中,即字符 h 的地址
2.数组指针变量
上一篇 vlog 学到了指针数组,就是存放指针的数组,也可以理解为存放指针的集合(元素相同),那么数组指针就可以得出是存放数组地址的指针,是一种指针变量,指向数组
int *p1[10];
int (*p2)[10];
那么以上哪种是数组指针?
答案是下面那个
分析:[ ] 的优先级大于 * ,所以必须加上 [ ] 来保证 p 和 * 优先结合
p先和 * 结合,说明p是一个指针变量,然后指针指向的是一个大小为10个整型的数组
所以 p 是一个指针,指向一个数组,叫数组指针
int 表示 p指向的数组的元素类型, p 是数组指针变量名,10是指向数组的元素个数
3.函数指针变量
根据前面学过的类比,不难发现,函数指针变量应该是用来存放函数地址的,通过地址能够调用函数的
那么函数真的有地址吗?
#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test: %p\n", test);printf("&test: %p\n", &test);return 0;
}
通过以上代码可以发现函数确实有地址,用函数名就能代表其地址,当然也可以通过 &函数名 的方
式获得函数的地址,为了方便一般就不写取地址符
其语法形式为:
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;
函数参数的变量名可写可不写,取地址符也是
int 是指向函数的返回类型,pf3 是函数指针变量名,int x,int y 是 pf3 指向函数的参数类型和个数
#include <stdio.h>
int Add(int x, int y)
{return x+y;
}
int main()
{int(*pf3)(int, int) = Add;printf("%d\n", (*pf3)(2, 3));printf("%d\n", pf3(3, 5));return 0;
}
可以将通过函数指针调用指针指向的函数写一个我们之前写过的加法函数
这里通过解引用函数指针 pf3 的方式来调用它所指向的函数(也就是 Add 函数),传入参数 2 和 3,然后将返回的结果使用 printf
函数输出。实际上,在这种情况下,解引用操作符 * 在这里是可选的,因为在 C
语言中,函数名本身在求值时就会转换为指向该函数的指针,所以也可以直接写成 pf3(2, 3)
4.函数指针数组
在学习了指针数组的基础上,我们引入函数指针放入数组
那么以下哪种为正确的形式?
int (*parr1[3])();
int *parr2[3]();
int (*)() parr3[3];
答案是第一个
定义形式如下:返回值类型 (*数组名[数组大小])(参数列表)
parr1 先和 [ ] 结合,说明 parr1是数组,是 int (*)() 类型的函数指针
那么参数如何理解?其实就是每个元素代表的函数
#include <stdio.h>int add(int a, int b) {return a + b;
}int subtract(int a, int b) {return a - b;
}int main() {int (*func_array[2])(int, int) = {add, subtract};return 0;
}
在上述代码中,func_array 数组的两个元素分别被初始化为 add 函数和 subtract 函数的指针
5.二维数组传参本质
讲数组的时候说过二维数组其实可以看做是每个元素是一维数组的数组,也就是二维数组的每个元素是一个一维数组,那么二维数组的首元素就是第一行,是个一维数组
第一行的一维数组的类型就是 int [5] ,所以第一行的地址的类型就是数组指针类型 int(*)[5] ,那就意味着二维数组传参本质上也是传递了地址,传递的是第一行这个一维数组的地址,那么形参也是可以写成指针形式的,总的来说就是把二维数组当一维数组理解,第一行看成一维数组的第一个元素,首元素就是第一行一整行的地址
#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 ", *(*(p+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;
}
普通的遍历数组传参也可以这样写
这里的 *(p+i) 相当于获取二维数组的第 i 行的首地址(因为 p 是指向包含 5 个整数的数组的指针,p+i 就指向了第 i 行),然后 *(p+i)+j 就是指向第 i 行第 j 列元素的指针,最后 ((p+i)+j) 就是获取该位置的元素值并输出
虽然解引用通常是获取元素本身,但在指向二维数组行的指针这种特殊情况下,由于指针所指向的对象本身就是一个数组,解引用得到的就是这个数组的首地址,这是由 C 语言的指针和数组特性共同决定的
二维数组传参,形参的部分可以写成数组,也可以写成指针形式
6.拓展补充
补充一个关键字 typedef ,是用来类型重命名的,可以将复杂的类型,简单化
普通类型
typedef unsigned int uint;
//将unsigned int 重命名为uint
普通指针类型
typedef int* ptr;
数组函数指针类型
typedef int(*parr)[5]; //新的类型名必须在*的右边
typedef void(*pfun)(int);//新的类型名必须在*的右边
下一期 vlog 将对二分查找,转移表,冒泡排序等常见算法题目进行练习解析
建议对前面的知识都有系统性的理解后再来写题
主页传送门:DARLING Zero two♡ 的 blog
希望读者们多多三连支持
小编会继续更新
你们的鼓励就是我前进的动力!
相关文章:

关于我、重生到500年前凭借C语言改变世界科技vlog.13——深入理解指针(3)
文章目录 1.字符指针变量2.数组指针变量3.函数指针变量4.函数指针数组5.二维数组传参本质6.拓展补充希望读者们多多三连支持小编会继续更新你们的鼓励就是我前进的动力! 本章节接着学习常见的指针变量类型 1.字符指针变量 字符指针变量,顾名思义就是字…...
每日算法一练:剑指offer——数组篇(6)
1.点名 某班级 n 位同学的学号为 0 ~ n-1。点名结果记录于升序数组 records。假定仅有一位同学缺席,请返回他的学号。 示例 1: 输入: records [0,1,2,3,5] 输出: 4示例 2: 输入: records [0, 1, 2, 3, 4, 5, 6, 8] 输出: 7提示: 1 < records.le…...

【环境搭建】Apache ZooKeeper 3.8.4 Stable
软件环境 Ubuntu 20.04 、OpenJDK 11 OpenJDK 11(如果已经安装,可以跳过这一步) 安装OpenJDK 11: $ sudo apt-get update$ sudo apt-get install -y openjdk-11-jdk 设置 JAVA_HOME 环境变量: $ sudo gedit ~/.bash…...

算法练习——双指针
前言:大佬写博客给别人看,菜鸟写博客给自己看,我是菜鸟。 学前须知(对自己):这里的指针不一定指地址!也可能是数组下标。 1:移动零(双指针) 题目要求: 解题思路&#x…...

vue中el-table显示文本过长提示
1.el-table设置轻提示:show-overflow-tooltip“true“,改变轻提示宽度...

JS 字符串拼接并去重
1、includes 循环数组将某个字段拼接成新的字符串并去重(数组里面包含的一个对象,或者其他都OK) // 定义一个数组 let arr[.......] // 定义拼接的字符串 let a //循环数组将里面某个字段拼接在一起并去重 arr.forEach(item > {if(!a.in…...

opencv 图像预处理
图像预处理 在计算机视觉和图像处理领域,图像预处理是一个重要的步骤,它能够提高后续处理(如特征提取、目标检测等)的准确性和效率。OpenCV 提供了许多图像预处理的函数和方法,以下是一些常见的图像预处理操作&…...

SAP B1 功能模块字段介绍 - 价格清单(下)
目录 背景 五、业务伙伴的特殊价格 1. 单据逻辑功能 2. 部分字段解释 3. 操作流程 3.1 时间相关 3.2 数量相关 4. 实例 六、复制特殊价格到选择标准 1. 单据逻辑功能 2. 部分字段解释 七、全局更新特殊价格 编辑 1. 单据逻辑功能 2. 部分字段解释 八、价格更…...

传智杯 第六届-复赛-D
题目描述: 小红定义两个字符串同构,当且仅当对于i∈[1,n],b[i]−a[i]i∈[1,n],b[i]-a[i]i∈[1,n],b[i]−a[i]是定值。例如,"bacd"和"edfg"是同构的。 现在小红拿到了一个长度为n的字符串a,她想知道&a…...

Java - 数组实现大顶堆
题目描述 实现思路 要实现一个堆,我们首先要了解堆的概念。 堆是一种完全二叉树,分为大顶堆和小顶堆。 大顶堆:每个节点的值都大于或等于其子节点的值。 小顶堆:每个节点的值都小于或等于其子节点的值。 完全二叉树ÿ…...

ifuse挂载后,在python代码中访问iOS沙盒目录获取app日志
上一次使用pymobiledevice3,在python代码中访问app的沙盒目录并分析业务日志,在使用过程中发现,在获取app日志的时候速度很慢,执行时间很长,需要30-61秒,所以这次尝试使用libimobiledevic和ifuse࿰…...
Windows WSL环境下安装 pytorch +ROCM 支持AMD显卡
官方文档:Install PyTorch for ROCm — Use ROCm on Radeon GPUs 一、操作系统及驱动 windows 下安装WSL 环境( windows subsystem for Linux), 安装ubuntu 22.04环境。 安装 rocm 软件包: sudo apt update wget https://repo.radeon.com/amdgpu-insta…...
uniapp中skymap.html(8100端口)提示未登录的排查与解决方法
问题: 目前账号已经登录,uniapp的其他端口均可以访问到数据,唯独skymap.html中的8100会提示未登录。(8100是后端网关gateway端口) 分析: 在 skymap.html 中遇到未登录提示的问题,通常是由于该…...
训练模型时梯度出现NAN或者INF(禁用amp的不同level)
判断参数梯度位nan或inf的代码: for name, param in model.named_parameters():if param.grad is not None:if torch.isnan(param.grad).any() or torch.isinf(param.grad).any():print(f"grad layer [{name}] is NaN or Inf") 首先来说可能得原因&…...
Maven核心概念
一、项目对象模型(POM) 1. 定义 POM(Project Object Model)是 Maven 项目的核心配置文件,它以 XML 格式描述了项目的基本信息、项目依赖、构建配置等。可以说,POM 是 Maven 理解和处理项目的基础。 2. 基…...

Sonatype Nexus 部署手册
文章目录 一、前言二、软件环境2.1 版本变更:2.1.1 变更存储的原因2.2.2 H2作为存储的注意点 三、资源配置四、开始部署4.1 部署jdk174.2 离线部署nexus4.2.1 下载4.2.2 部署1. 上传到服务器2. 解压3. 添加用户4. 修改启动参数5. 迁移sonatype-work ,并授…...

TLV320AIC3104IRHBR 数据手册 一款低功耗立体声音频编解码器 立体声耳机放大器芯片麦克风
TLV320AIC3104 是一款低功耗立体声音频编解码器,具有立体声耳机放大器以及在单端或全差分配置下可编程的多个输入和输出。该器件包括基于寄存器的全面电源控制,可实现立体声 48kHz DAC 回放,在 3.3V 模拟电源电压下的功耗低至 14mW࿰…...
(8)结构体、共用体和枚举类型数据
1. 结构体、共用体的定义及区别,typedef 定义别名 结构体的定义 结构体是一种用户自定义的数据类型,它可以将不同类型的数据组合在一起。例如,定义一个表示学生信息的结构体: // 定义结构体类型 struct Student struct Student {char name[20];int age;float score; };共…...

Jedis操作和springboot整合redis
Jedis-springboot整合redis Jedis 引入jedis依赖 注意事项 测试相关数据类型 Key String List set hash zset 案例 spring boot整合redis 引入相关依赖 在application.properties中配置redis 配置 创建redis配置类 创建测试类 Jedis 引入jedis依赖 <depen…...
基于AI大模型的复杂扫描件PDF信息提取与规整
前言 场景大致是会上传一个几十页的扫描件PDF,让AI在当中找出我需要的字段,本文会隐去具体行业信息和具体的AI提示词内容,只分享技术相关内容,请见谅。 AI模型选择 针对我们行业的使用场景,我主要测试了GPT、Claude以…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
Linux简单的操作
ls ls 查看当前目录 ll 查看详细内容 ls -a 查看所有的内容 ls --help 查看方法文档 pwd pwd 查看当前路径 cd cd 转路径 cd .. 转上一级路径 cd 名 转换路径 …...
Java多线程实现之Callable接口深度解析
Java多线程实现之Callable接口深度解析 一、Callable接口概述1.1 接口定义1.2 与Runnable接口的对比1.3 Future接口与FutureTask类 二、Callable接口的基本使用方法2.1 传统方式实现Callable接口2.2 使用Lambda表达式简化Callable实现2.3 使用FutureTask类执行Callable任务 三、…...
汇编常见指令
汇编常见指令 一、数据传送指令 指令功能示例说明MOV数据传送MOV EAX, 10将立即数 10 送入 EAXMOV [EBX], EAX将 EAX 值存入 EBX 指向的内存LEA加载有效地址LEA EAX, [EBX4]将 EBX4 的地址存入 EAX(不访问内存)XCHG交换数据XCHG EAX, EBX交换 EAX 和 EB…...

Maven 概述、安装、配置、仓库、私服详解
目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...
2023赣州旅游投资集团
单选题 1.“不登高山,不知天之高也;不临深溪,不知地之厚也。”这句话说明_____。 A、人的意识具有创造性 B、人的认识是独立于实践之外的 C、实践在认识过程中具有决定作用 D、人的一切知识都是从直接经验中获得的 参考答案: C 本题解…...
python报错No module named ‘tensorflow.keras‘
是由于不同版本的tensorflow下的keras所在的路径不同,结合所安装的tensorflow的目录结构修改from语句即可。 原语句: from tensorflow.keras.layers import Conv1D, MaxPooling1D, LSTM, Dense 修改后: from tensorflow.python.keras.lay…...
4. TypeScript 类型推断与类型组合
一、类型推断 (一) 什么是类型推断 TypeScript 的类型推断会根据变量、函数返回值、对象和数组的赋值和使用方式,自动确定它们的类型。 这一特性减少了显式类型注解的需要,在保持类型安全的同时简化了代码。通过分析上下文和初始值,TypeSc…...
离线语音识别方案分析
随着人工智能技术的不断发展,语音识别技术也得到了广泛的应用,从智能家居到车载系统,语音识别正在改变我们与设备的交互方式。尤其是离线语音识别,由于其在没有网络连接的情况下仍然能提供稳定、准确的语音处理能力,广…...

Unity中的transform.up
2025年6月8日,周日下午 在Unity中,transform.up是Transform组件的一个属性,表示游戏对象在世界空间中的“上”方向(Y轴正方向),且会随对象旋转动态变化。以下是关键点解析: 基本定义 transfor…...