C语言学习系列-->看淡指针(3)

文章目录
- 一、字符指针变量
- 二、数组指针变量
- 2.1 概述
- 2.2 数组指针初始化
- 三、二维数组传参本质
- 四、函数指针
- 五、typedef关键字
- 六、函数指针数组
一、字符指针变量
在指针的类型中我们知道有⼀种指针类型为字符指针 char*
一般使用:
#include<stdio.h>int main() {char ch = 'w';char* pc = &ch;return 0;
}
进阶使用
#include<stdio.h>
int main() {const char* pstr = "hello";printf("%s", pstr);return 0;
}
本质是把字符串 hello ⾸字符的地址放到了pstr中。
把⼀个常量字符串的⾸字符 h 的地址存放到指针变量 pstr 中。
经典例题:
#include<stdio.h>int main() {char str1[] = "hello word.";char str2[] = "hello word.";const char* str3 = "hello word.";const char* str4 = "hello word.";if (str1 == str2)printf("str1 and str2 are same\n");elseprintf("str1 and str2 are not same\n");if (str3 == str4)printf("str3 and str4 are same\n");elseprintf("str3 and str4 are not same\n");return 0;
}
运行结果:

这⾥str3和str4指向的是⼀个同⼀个常量字符串。C/C++会把常量字符串存储到单独的⼀个内存区域,当⼏个指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存。但是⽤相同的常量字符串去初始化不同的数组的时候就会开辟出不同的内存块。所以str1和str2不同,str3和str4相同。
二、数组指针变量
2.1 概述
前面一篇文章我们讨论过指针数组,本质上是一个数组,一个存放指针的数组。
本节,我们要讨论的数组指针,后缀“指针”。
数组指针,指向的是数组的指针,存放的是数组的指针。
类比之前学的:
• 整形指针变量: int * pint; 存放的是整形变量的地址,能够指向整形数据的指针。
• 浮点型指针变量: float * pf; 存放浮点型变量的地址,能够指向浮点型数据的指针。
一般使用:
int (*p)[10];
解释:p先和*结合,说明p是⼀个指针变量变量,然后指着指向的是⼀个⼤⼩为10个整型的数组。所以p是⼀个指针,指向⼀个数组,叫 数组指针。
这⾥要注意:[]的优先级要⾼于号的,所以必须加上()来保证p先和结合。
2.2 数组指针初始化
数组指针变量是⽤来存放数组地址的,那怎么获得数组的地址呢?就是我们之前学习的 &数组名 。
int arr[10] = {0};
&arr;//得到的就是数组的地址
如果要存放个数组的地址,就得存放在数组指针变量中,如下:
int(*p)[10] = &arr;

我们调试也能看到 &arr 和 p 的类型是完全⼀致的。
int (*p) [10] = &arr;| | || | || | p指向数组的元素个数| p是数组指针变量名p指向的数组的元素类型
三、二维数组传参本质
过去我们有⼀个⼆维数组的需要传参给⼀个函数的时候,我们是这样写的:
#include<stdio.h>void test(int arr[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 ", arr[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 [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("%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;
}
⼆维数组传参,形参的部分可以写成数组,也可以写成指针形式。
四、函数指针
使用:
int (*pf3) (int x, int y)| | ------------ | | || | pf3指向函数的参数类型和个数的交代| 函数指针变量名pf3指向函数的返回类型int (*) (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;
}
运行结果:
5
8
注意:&函数名和函数名都是函数的地址
经典例题:
练习1:
( *(void (*)())0 )();
这里:void( * )()是一个函数指针类型,指向一个没有参数,返回值为void类型的函数,这个类型被放在一个括号里,说明要进行强制类型转换,这里把0强制类型转换成(void (*)())型,此时0就成了一个地址,指向一个void ()型函数,然后再通过解引用找到这个函数,进行传参,当然这个函数没有参数,所以最后一个括号是空的

练习2:
void (*signal(int, void(*)(int))) (int);
signal是一个函数的函数名
声明signal函数有两个参数,第一个参数是int型,第二个参数是函数指针类型
这里signal函数的返回值类型是void(*)(int)

五、typedef关键字
typedef 是⽤来类型重命名的,可以将复杂的类型,简单化。
⽐如,你觉得 unsigned int 写起来不⽅便,如果能写成 uint 就⽅便多了,那么我们可以使⽤:
typedef unsigned int uint;
//将unsigned int 重命名为uint
如果是指针类型,能否重命名呢?其实也是可以的,⽐如,将 int* 重命名为 ptr_t ,这样写:
typedef int* ptr_t;
但是对于数组指针和函数指针稍微有点区别:
⽐如我们有数组指针类型 int(*)[5] ,需要重命名为 parr_t ,那可以这样写:
typedef int(*parr_t)[5]; //新的类型名必须在*的右边
函数指针类型的重命名也是⼀样的,⽐如,将 void(*)(int) 类型重命名为 pf_t ,就可以这样写:
typedef void(*pfun_t)(int);//新的类型名必须在*的右边
简化上述练习2的代码:
typedef void(*pf_t)(int);//把void(*)(int)型重命名成pf_t,注意pf_t的位置int main()
{pf_t signal(int, pf_t);return 0;
}
六、函数指针数组
把函数指针(地址)存到数组里面,就叫做函数指针数组
int (*parr1[3])();
parr1 先和 [] 结合,说明 parr1是数组,数组的内容是什么呢?
是 int (*)() 类型的函数指针。

相关文章:
C语言学习系列-->看淡指针(3)
文章目录 一、字符指针变量二、数组指针变量2.1 概述2.2 数组指针初始化 三、二维数组传参本质四、函数指针五、typedef关键字六、函数指针数组 一、字符指针变量 在指针的类型中我们知道有⼀种指针类型为字符指针 char* 一般使用: #include<stdio.h>int main…...
Java抽象类详解
抽象类 抽象类的概念 在面向对象的概念中,所有的对象都是通过类来描绘的,但是反过来,并不是所有的类都是来描绘对象的,如果一个类中没有包含足够的信息来描绘一个具体的对象,这样的类就是抽象类。比如: 说…...
06-微信小程序-注册程序-场景值
06-微信小程序-注册程序 文章目录 注册小程序参数 Object object案例代码 场景值场景值作用场景值列表案例代码 注册小程序 每个小程序都需要在 app.js 中调用 App 方法注册小程序实例,绑定生命周期回调函数、错误监听和页面不存在监听函数等。 详细的参数含义和使…...
多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)
多种方法实现 Nginx 隐藏式跳转(隐式URL,即浏览器 URL 跳转后保持不变)。 一个新项目,后端使用 PHP 实现,前端不做路由,提供一个模板,由后端路由控制。 Route::get(pages/{name}, [\App\Http\Controllers\ResourceController::class, getResourceVersion])...
视频汇聚云平台EasyCVR视频监控管理平台进行SDN转推的操作步骤
视频汇聚/视频云存储/集中存储/视频监控管理平台EasyCVR能在复杂的网络环境中,将分散的各类视频资源进行统一汇聚、整合、集中管理,实现视频资源的鉴权管理、按需调阅、全网分发、云存储、智能分析等,视频智能分析平台EasyCVR融合性强、开放度…...
SQL 语句继续学习之记录二
三, 聚合与排序 对表进行聚合查询,即使用聚合函数对表中的列进行合计值或者平均值等合计操作。 通常,聚合函数会对null以外的对象进行合计。但是只有count 函数例外,使用count(*) 可以查出包含null在内的全部数据行数。 使用dis…...
【Python原创设计】基于Python Flask 机器学习的全国+上海气象数据采集预测可视化系统-附下载链接以及详细论文报告,原创项目其他均为抄袭
基于Python Flask 机器学习的全国上海气象数据采集预测可视化系统 一、项目简介二、开发环境三、项目技术四、功能结构五、运行截图六、功能实现七、数据库设计八、源码获取 一、项目简介 在信息科技蓬勃发展的当代,我们推出了一款基于Python Flask的全国上海气象数…...
Unity进阶–通过PhotonServer实现人物选择和多人同步–PhotonServer(四)
文章目录 Unity进阶–通过PhotonServer实现人物选择和多人同步–PhotonServer(四)服务端客户端 Unity进阶–通过PhotonServer实现人物选择和多人同步–PhotonServer(四) 服务端 服务端结构如下: UserModel using System; using System.Collections.Generic; usin…...
【Go 基础篇】Go语言获取用户终端输入:实现交互式程序的关键一步
介绍 在许多编程场景中,我们需要编写交互式程序,以便用户可以在终端中输入数据并与程序进行交互。Go语言提供了丰富的方式来获取用户终端输入,使得编写交互式程序变得简单而有趣。本篇博客将深入探讨Go语言中获取用户终端输入的各种方法&…...
学习笔记:Opencv实现拉普拉斯图像锐化算法
2023.8.19 为了在暑假内实现深度学习的进阶学习,Copy大神的代码,记录学习日常 图像锐化的百科: 图像锐化算法-sharpen_lemonHe_的博客-CSDN博客 在环境配置中要配置opencv: pip install opencv-contrib-python Code and lena.png…...
如何在前端实现WebSocket发送和接收UDP消息(多线程模式)
目录 简介:步骤1:创建WebSocket连接步骤2:创建Web Workers步骤3:发送和接收UDP消息(多线程模式)结束语: 简介: 本文将继续介绍如何在前端应用中利用WebSocket技术发送和接收UDP消息…...
【微服务】一文了解 Nacos
一文了解 Nacos Nacos 在阿里巴巴起源于 2008 2008 2008 年五彩石项目(完成微服务拆分和业务中台建设),成长于十年双十一的洪峰考验,沉淀了简单易用、稳定可靠、性能卓越的核心竞争力。 随着云计算兴起, 2018 2018 20…...
量子计算对信息安全的影响:探讨量子计算技术对现有加密方法和信息安全基础设施可能带来的颠覆性影响,以及应对策略
第一章:引言 随着科技的迅猛发展,量子计算作为一项颠覆性的技术正逐渐走入我们的视野。量子计算以其强大的计算能力引发了全球科技界的广泛关注。然而,正如硬币的两面,量子计算技术所带来的不仅仅是计算能力的巨大飞跃࿰…...
ajax-axios-url-form-serialize 插件
AJAX AJAX 概念 1.什么是 AJAX ? mdn 使用浏览器的 XMLHttpRequest 对象 与服务器通信 浏览器网页中,使用 AJAX技术(XHR对象)发起获取省份列表数据的请求,服务器代码响应准备好的省份列表数据给前端,前端拿到数据数…...
【AIGC】单图换脸离线版软件包及使用方法
云端再好,都不如放自己手里啊,想怎么就怎么玩。云端再好,都不如放自己手里啊,想怎么就怎么玩。 Roop作为一个新出的开源项目,配置起来还是有一定难度的。 我已经把各种依赖,模型,环境配置已经…...
8.19论文阅读
文章目录 Graph-Segmenter: Graph Transformer with Boundary-aware Attention for Semantic Segmentation方法 SCSC: Spatial Cross-scale Convolution Module to Strengthen both CNNs and Transformers方法 Deformable Mixer Transformer with Gating for Multi-Task Learni…...
HAProxy
目录 HAProxy HAProxy介绍 主要特性 LVS、nginx、HAProxy区别 nginx LVS HAProxy 负载均衡策略 Haproxy搭建 Web 群集 Haproxy服务器 编译安装 Haproxy Haproxy服务器配置 添加haproxy 系统服务 节点服务器部署 日志定义 HAProxy HAProxy介绍 HAProxy是可提供高…...
基于EasyExcel的Excel读取
1.引入依赖 <dependency><groupId>com.alibaba</groupId><artifactId>easyexcel</artifactId><version>2.2.11</version> </dependency>2.读取器代码: package com.vz.utils.excel;import com.alibaba.excel.Eas…...
链路聚合详解
链路聚合详解 华为交换机链路聚合:Linux链路聚合bond配置 华为交换机链路聚合: 方式一:配置手工负载分担方式的链路聚合 [CORE1] interface Eth-Trunk 1 [CORE1-Eth-Trunk1] trunkport GigabitEthernet 0/0/5 to 0/0/6 [CORE1-Eth-Trunk1] p…...
Shell编程学习之if分支语句的应用
Shell编程中的if分支语句:伪代码表示:注意符号和表达式之间的空格; if [ 表达式1 ] then分支1 elif [ 表达式2 ] then分支2 elif [ 表达式3 ] then分支3 else其它 fi按整型的方式,if分支语句比较字符串的大小:等于&am…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
使用分级同态加密防御梯度泄漏
抽象 联邦学习 (FL) 支持跨分布式客户端进行协作模型训练,而无需共享原始数据,这使其成为在互联和自动驾驶汽车 (CAV) 等领域保护隐私的机器学习的一种很有前途的方法。然而,最近的研究表明&…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
C++八股 —— 单例模式
文章目录 1. 基本概念2. 设计要点3. 实现方式4. 详解懒汉模式 1. 基本概念 线程安全(Thread Safety) 线程安全是指在多线程环境下,某个函数、类或代码片段能够被多个线程同时调用时,仍能保证数据的一致性和逻辑的正确性…...
【HarmonyOS 5 开发速记】如何获取用户信息(头像/昵称/手机号)
1.获取 authorizationCode: 2.利用 authorizationCode 获取 accessToken:文档中心 3.获取手机:文档中心 4.获取昵称头像:文档中心 首先创建 request 若要获取手机号,scope必填 phone,permissions 必填 …...
[ACTF2020 新生赛]Include 1(php://filter伪协议)
题目 做法 启动靶机,点进去 点进去 查看URL,有 ?fileflag.php说明存在文件包含,原理是php://filter 协议 当它与包含函数结合时,php://filter流会被当作php文件执行。 用php://filter加编码,能让PHP把文件内容…...
【 java 虚拟机知识 第一篇 】
目录 1.内存模型 1.1.JVM内存模型的介绍 1.2.堆和栈的区别 1.3.栈的存储细节 1.4.堆的部分 1.5.程序计数器的作用 1.6.方法区的内容 1.7.字符串池 1.8.引用类型 1.9.内存泄漏与内存溢出 1.10.会出现内存溢出的结构 1.内存模型 1.1.JVM内存模型的介绍 内存模型主要分…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement
Cilium动手实验室: 精通之旅---13.Cilium LoadBalancer IPAM and L2 Service Announcement 1. LAB环境2. L2公告策略2.1 部署Death Star2.2 访问服务2.3 部署L2公告策略2.4 服务宣告 3. 可视化 ARP 流量3.1 部署新服务3.2 准备可视化3.3 再次请求 4. 自动IPAM4.1 IPAM Pool4.2 …...
