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…...
智能健身器材核心技术解析:从光学编码器到电机驱动的安华高方案
1. 项目概述:当健身器材遇上“芯”动力如果你拆开一台近两年新出的智能动感单车、划船机或者高端跑步机,大概率会在其控制主板的核心位置,发现一枚印着“Avago”或“Broadcom”标志的芯片。这不是偶然。安华高科技(Avago Technolo…...
为什么你的DeepSeek JSON总是parse error?资深架构师用AST语法树对比揭示4种LLM输出结构幻觉根源
更多请点击: https://intelliparadigm.com 第一章:JSON解析失败的表象与系统性归因 JSON解析失败在现代Web服务、微服务通信及前端数据消费中极为常见,其表象往往表现为程序崩溃、空值传播、或静默丢弃数据,而非明确的错误提示。…...
Multisim仿真实战:石英晶体振荡器电路设计与性能调优
1. 石英晶体振荡器基础与Multisim入门 石英晶体振荡器是电子电路中常见的精密频率源,它的核心是一块经过特殊切割的石英晶体。当给晶体施加电压时,它会产生机械振动,这种振动又反过来产生电信号,形成稳定的振荡。我在实际项目中经…...
实测Taotoken在低功耗arm7设备上的API调用延迟与稳定性表现
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 实测Taotoken在低功耗arm7设备上的API调用延迟与稳定性表现 1. 测试背景与目的 在边缘计算或资源受限的嵌入式场景中,…...
ZipCPU/dspfilters:轻量级C++ IIR滤波器库的设计原理与嵌入式应用
1. 项目概述:从零开始理解一个数字信号处理滤波器库最近在整理一些嵌入式音频处理的项目,又翻出了ZipCPU/dspfilters这个仓库。这其实是一个在GitHub上存在了相当一段时间的C数字信号处理(DSP)滤波器库,由ZipCPU&#…...
LunaTranslator:打破语言壁垒,让视觉小说触手可及
LunaTranslator:打破语言壁垒,让视觉小说触手可及 【免费下载链接】LunaTranslator 视觉小说翻译器 / Visual Novel Translator 项目地址: https://gitcode.com/GitHub_Trending/lu/LunaTranslator 还在为日文、英文的视觉小说而烦恼吗࿱…...
AI应用网关ai-proxy:统一管理多模型API调用,实现路由、缓存与限流
1. 项目概述:一个为AI应用量身打造的智能代理网关如果你正在开发或部署基于大语言模型(LLM)的应用,比如一个聊天机器人、一个代码助手,或者一个内容生成工具,那么你大概率会遇到一个头疼的问题:…...
stm32开发者如何快速接入大模型api实现智能对话功能
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 STM32开发者如何快速接入大模型API实现智能对话功能 为嵌入式设备增加自然语言交互能力,是许多STM32开发者希望实现的功…...
从 SU01 到 SAP HANA,DBMS 用户管理里的 SSO 选项到底在管什么
项目里讨论 SSO 时,大家很容易把它想成一个单点登录按钮,好像在某处勾选一下,用户就能从 SAP GUI、Fiori、报表工具一路无感访问到数据库。到了 SAP NetWeaver AS 和 SAP HANA 组合的系统里,这个理解会带来不少误会。因为从 ABAP 侧维护 DBMS 用户的 SSO 选项,只是在用户主…...
如何通过浏览器脚本实现网盘文件直链下载:LinkSwift 完全指南
如何通过浏览器脚本实现网盘文件直链下载:LinkSwift 完全指南 【免费下载链接】Online-disk-direct-link-download-assistant 一个基于 JavaScript 的网盘文件下载地址获取工具。基于【网盘直链下载助手】修改 ,支持 百度网盘 / 阿里云盘 / 中国移动云盘…...
