【理解指针(四)】
文章目录
- 一、指针数组
- 二、指针数组来模拟二维数组
- 三、字符指针变量
- 注意:
- 字符串的例子(曾经的一道笔试题)
- 四、数组指针变量
- 1、什么是数组指针变量
- 2、数组指针怎么初始化
- 五、二维数组传参的本质
- 六、函数指针
- 1、什么是函数指针变量
- 2、函数的地址
- 3、使用
- 4、 `typedef`关键字
- 结束语
一、指针数组
我们可以先来回顾一下整形数组和字符数组。
- 整形数组:
是存放整形的数组
- 字符数组:
是指存放字符的数组
类比上面两个例子之后,我们可以知道指针数组就是存放指针的数组,指针数组的每一个元素都是用来存放地址(指针)的。
二、指针数组来模拟二维数组
首先我们需要知道数组名是指数组首元素的地址
#include<stdio.h>
int main()
{int str[] = { 1,2,3,4,5 };int str1[] = { 3,4,5,6,7 };int str2[] = { 5,6,7,8,9 };int* pa[3] = { str,str1,str2 };for (int i = 0; i < 3; i++){for (int j = 0; j < 5; j++){printf("%d ", *(*(pa + i)) + j);}printf("\n");}return 0;
}
我们可以得到如下的结果:
第一次的for循环是循环的行,第二次的dor循环也就是列,数组名就是数组的首元素,我们这里的pa[i]找到数组元素指向的是整形一维数组,pa[i][j]就是指向整形一维数组的元素。
模拟出⼆维数组的效果,实际上并非完全是⼆维数组,因为每⼀行并非是连续的
画个图方便大家理解:
三、字符指针变量
我们知道字符指针是char*
常如下使用:
#include<stdio.h>
int main()
{char p = 'e';char* s = &p;printf("%c\n", *s);*s = 't';printf("%c\n", *s);return 0;
}
结果会分别打印出:e 和 t 。
当然还有其他适用方式:
#include<stdio.h>
int main()
{char str[] = "hello world!!!";char* pa = str;printf("%s\n", pa);return 0;
}
注意:
这里的hello world!!!
并没有放在指针变量pa
中,而是把这个字符串的首字符的地址放在了pa
中。
pa
也就是调用字符串中首字符的地址,而字符串的地址也是首字符元素的地址。
字符串的例子(曾经的一道笔试题)
#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)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;
}
这题的答案是str1 and str2 are not same
和str3 and str4 are same
我们大致来分析一下:
str1
和str2
都是存的相同的字符串内容,在内存中str1
和str2
是开辟了不同的空间存放相同的内容的,实质上完全没有必要存相同的内容开辟两个空间,两个空间的地址完全不一样,所以会打印出str1 and str2 are not same
;而str3
和str4
指向的是⼀个同⼀个常量字符串,C/C++会把常量字符串存储到单独的⼀个内存区域,指针指向同⼀个字符串的时候,他们实际会指向同⼀块内存,所以这里会打印出str3 and str4 are same
。
四、数组指针变量
1、什么是数组指针变量
首先我们可以来回顾一下:整形指针变量和浮点型指针变量
-
整形指针变量:
存放的是整型变量的指针,能够指向整形数据的指针。
形如:int* pa
-
浮点型指针变量:
存放的是浮点型变量的指针,能够指向浮点型数据的指针。
形如:float* pa
那么数组指针变量就是存放的是数组的地址,指向数组数据的指针。
形如:int(*p)[10]
这里的p是自己命名,10 也是根据自己写的代码来写。
p
先和*结合,所以p
是一个指针变量,指向的是一个大小为10个整形的数组。
综上:p是一个指针,指向一个数组,这就是数组指针。
2、数组指针怎么初始化
数组指针变量是⽤来存放数组地址的
int arr[5]={0};
&arr得到的就是数组的地址
int (*p)[5]=&arr//这个数组的地址存放在数组指针变量中
五、二维数组传参的本质
(二维数组我们可以看成许多一维数组的组成)
首先我们知道数组名是数组首元素的地址,那么⼆维数组的数组名表示的就是第⼀行的地址,也就是一维数组的地址,⼆维数组传参本质上也是传递了地址,传递的是第一行这个⼀维数组的地址
我们形参用指针写的形式如下:
#include<stdio.h>
void Shuzu(int(* pa)[5], int a, int b)
{for (int i = 0; i < a; i++){for (int j = 0; j < b; j++){printf("%d ", *(*(pa + i) + j));}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };Shuzu(arr, 3, 5);return 0;
}
当然形参我们也可以数组的形式写:
#include<stdio.h>
void Shuzu(int p[][5], int s, int c)
{for (int i = 0; i < s; i++){for (int j = 0; j < c; j++){printf("%d ", p[i][j]);}printf("\n");}
}
int main()
{int arr[3][5] = { {1,2,3,4,5},{6,7,8,9,10},{11,12,13,14,15} };Shuzu(arr, 3, 5);return 0;
}
六、函数指针
1、什么是函数指针变量
通过上面的种种类比我们知道了什么是数组指针,整形指针,那么我们可以知道函数指针变量就是用来存放函数地址的。
2、函数的地址
首先我们可以简单的写一个代码,看看函数是否有地址:
#include<stdio.h>
void Ad()
{printf("abder\n");
}
int main()
{Ad();printf("&Ad=%p\n", &Ad);printf("Ad=%p\n", Ad);return 0;
}
由结果我们可以知道函数有地址,函数名就是我们的地址
如果我们要将函数的地址存放起来,就得创建函数指针变量:
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}int(*pa)(int , int ) = Add;//&Add
其中==int(*)(int,int)==就是pa函数指针变量的类型。
3、使用
#include<stdio.h>
int Add(int x, int y)
{return x + y;
}
int main()
{int (*pa1)(int ,int) = Add;printf("%d\n", (*pa1)(2,4));printf("%d\n", pa1(5,6));return 0;
}
可以得出答案是6和11。
为什么第二个打印pa1可以不解引用?
因为pa1这个指针变量存放的是Add的地址,&符号与*相互直接抵消了,所以可以不使用解引用符号。
4、 typedef
关键字
typedef是用来类型重命名的
比如:
singed int 可能你觉得每次书写比较麻烦,你就可以直接有时候typedef来重命名
也就是:typedef singed int ty_t,这个时候,想要再使用singed int 就可以直接用ty_t替换,
本质上是一样的
1.但是函数指针的重命名有些许区别:
比如,我们想要把int(*pa)(int )
重命名为pa_t
:
typedef int(*pa_t)(int); //新类型的名字必须在*号的右边
2.数组指针重命名也是如此:
比如:我们需要把int(*pc)[10]
重命名为py_y
typedef int(*py_y)[10]; //新类型的名字也需要在*号的右边
结束语
这次的内容可能有些多,但是比较好理解,希望大家可以拿到自己想要的offer,最后,如果文章有什么打错字的地方,希望大家不要介意,也希望大家可以给我提出来。
最后,祝大家每天都开开心心,我们下次再见
相关文章:

【理解指针(四)】
文章目录 一、指针数组二、指针数组来模拟二维数组三、字符指针变量注意: 字符串的例子(曾经的一道笔试题) 四、数组指针变量1、什么是数组指针变量2、数组指针怎么初始化 五、二维数组传参的本质六、函数指针1、什么是函数指针变量2、函数的…...

Ribbon简介
目录 一 、概念介绍 1、Ribbon是什么 2、认识负载均衡 2.1 服务器端的负载均衡 2.2 客户端的负载均衡 3、Ribbon工作原理 4、Ribbon的主要组件 IClientConfig ServerList ServerListFilter IRule Iping ILoadBalancer ServerListUpdater 5、Ribbon支持…...

【感悟《剑指offer》典型编程题的极练之路】02字符串篇!
个人主页:秋风起,再归来~ 文章所属专栏:《剑指offer》典型编程题的极练之路 个人格言:悟已往之不谏,知来者犹可追 克心守己,…...
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建
通过 Docker 实现国产数据库 OpenGauss 开发环境搭建 一 前置准备 2.1 下载镜像 docker pull enmotech/opengauss:5.0.1构建镜像的 Dockerfile,方便后期实现个性化定制: FROM ubuntu:22.04 as builderARG TARGETARCHWORKDIR /warehouseRUN set -eux;…...

【Java】LinkedList模拟实现
目录 整体框架IMyLinkedList接口IndexNotLegalException异常类MyLinkedList类成员变量(节点信息)addFirst(头插)addLast(尾插)在指定位置插入数据判断是否存在移除第一个相等的节点移除所有相等的节点链表的长度打印链表释放回收链表 整体框架 IMyLinkedList接口 这个接口用来…...
ubuntu下mysql常用命令
1. 登录数据库 mysql -u root -p 2.创建数据库 create database 数据库名字 mysql> create database yourdb; Query OK, 1 row affected (0.03 sec)3.显示数据库 show databases; 实操结果如下 mysql> show databases; -------------------- | Database | ---…...

燃气官网安全运行监测系统-阀井燃气监测仪-旭华智能
近年来,燃气爆炸事故频发,造成了重大人员伤亡和财产损失。这也再次为我们敲响警钟,燃气是我们日常生活中不可或缺的能源,但其潜在的危险性也是不容小觑。因此在重要节点加装燃气阀井气体监测仪,并将数据上传到系统平台…...
vue 文件预览(docx、.xlsx、pdf)
1.ifream <iframe src"" ></iframe> 注: src里面是文件地址 2.vue-office 支持vue2和vue3提供docx、.xlsx、pdf多种文档的在线预览方案 2.1安装 #docx文档预览组件 npm install vue-office/docx vue-demi#excel文档预览组件 npm install vue-office…...

云架构(二) 大使模式
Ambassador pattern (https://learn.microsoft.com/en-us/azure/architecture/patterns/ambassador) 简单描述 创建一个助手服务,这个服务代表消费服务或者应用程序发送网络请求。大使服务可以看做是与客户机同一个位置的进程外代理。 这种…...
.NET Path类库的特殊方法
在.NET中Path类库是非常常用的一个类库,包含很多我们常用的方法,常用的方法这里就不详细说明了,这里记录下几个非常规的方法。 获取随机文件名: //将返回随机的文件名Console.WriteLine(Path.GetRandomFileName()); 获取禁止在路…...
【JVM】JVM常用性能调优参数详细介绍
JVM常用性能调优参数详细介绍 一、何时进行JVM调优二、性能调优三、JVM调优的基本原则四、JVM调优目标五、JVM调优的步骤六、JVM参数七、JVM参数解析及调优八、JVM参数使用手册8.1 内存相关8.2 GC策略相关8.3 GC日志相关8.4 异常相关8.5 问题定位及优化相关九、参考文档一、何时…...
React中的受控组件与非受控组件
受控组件与非受控组件 受控组件 组件(input, select)的状态与state的值绑定,组件的状态全程响应外部数据 class TestComponent extends React.Component {constructor (props) {super(props);this.state { username: lindaidai };}render () {return <input …...
uniapp实现u-datetime-picker时间选择器的默认日期定位,解决default-value不生效问题
uniapp实现u-datetime-picker,设置默认定位日期,解决default-value不生效问题 想实现的效果是点开时间选择器默认显示当前日期,而不是该选择器最早的日期 给选择器添加ref属性,如下: <u-datetime-picker :show&q…...
react native 使用ScrollView实现下拉更新,上拉加载更多
在React Native中,要实现下拉更新和上拉加载更多的功能,你需要自定义ScrollView组件,监听滚动事件并根据滚动的位置来判断何时触发更新和加载更多的操作。以下是一个基本的实现思路: 监听滚动事件:使用ScrollView的on…...
vue2完结
笔记 关于不同版本的Vue: 1.vue.js与vue.runtime.xxx.js的区别:(1)vue.js是完整版的Vue,包含:核心功能模板解析器(2)vue.runtime.xxx.js是运行版本的Vue,只包含核心功能,没有模板解析器 2.因为…...
前端网页之间传递参数
在多页面应用中,我们可能面临着前端页面之间传递参数的情况,在一个页面获取到一些参数信息后,到另一个页面去进行后续处理,需要将前一个页面得到的一些参数带到第二个页面。当参数较少时,可以在跳转第二个页面时通过se…...
【常见面试题】Golang中,协程数最多可以开多少个?
参考: Goroutine 究竟可以开多少? 一、先说结论: 能开多少个协程,取决于单个协程处理方法所占用的CPU和内存资源(也就是看你计算机运行的应用程序的具体代码逻辑)。 二、具体来说: 如果是C…...

RabbitMQ基础笔记
视频链接:【黑马程序员RabbitMQ入门到实战教程】 文章目录 1.初识MQ1.1.同步调用1.2.异步调用1.3.技术选型 2.RabbitMQ2.1.安装2.1.1 Docker2.1.1 Linux2.1.1 Windows 2.2.收发消息2.2.1.交换机2.2.2.队列2.2.3.绑定关系2.2.4.发送消息 2.3.数据隔离2.3.1.用户管理2…...
大型项目管理神器:掌握yarn monorepo的安装和使用
I. 引言 在当今的前端开发中,由于项目规模的不断增长和多团队协同,Monorepo成为了越来越流行的开发模式。Monorepo指的是将多个相关项目或者模块打包在一起的软件开发模式,它可以让开发人员更好地组织管理代码,减少重复的代码&am…...

算法打卡day28|贪心算法篇02|Leetcode 122.买卖股票的最佳时机 II、55. 跳跃游戏、45.跳跃游戏 II
算法题 Leetcode 122.买卖股票的最佳时机 II 题目链接:122.买卖股票的最佳时机 II 大佬视频讲解:买卖股票的最佳时机 II视频讲解 个人思路 因为只有一只股票,且两天作一个交易单元,那每次只收集正利润就可以最终最多可以获取的利润…...
【位运算】消失的两个数字(hard)
消失的两个数字(hard) 题⽬描述:解法(位运算):Java 算法代码:更简便代码 题⽬链接:⾯试题 17.19. 消失的两个数字 题⽬描述: 给定⼀个数组,包含从 1 到 N 所有…...

理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
基于数字孪生的水厂可视化平台建设:架构与实践
分享大纲: 1、数字孪生水厂可视化平台建设背景 2、数字孪生水厂可视化平台建设架构 3、数字孪生水厂可视化平台建设成效 近几年,数字孪生水厂的建设开展的如火如荼。作为提升水厂管理效率、优化资源的调度手段,基于数字孪生的水厂可视化平台的…...
unix/linux,sudo,其发展历程详细时间线、由来、历史背景
sudo 的诞生和演化,本身就是一部 Unix/Linux 系统管理哲学变迁的微缩史。来,让我们拨开时间的迷雾,一同探寻 sudo 那波澜壮阔(也颇为实用主义)的发展历程。 历史背景:su的时代与困境 ( 20 世纪 70 年代 - 80 年代初) 在 sudo 出现之前,Unix 系统管理员和需要特权操作的…...

3-11单元格区域边界定位(End属性)学习笔记
返回一个Range 对象,只读。该对象代表包含源区域的区域上端下端左端右端的最后一个单元格。等同于按键 End 向上键(End(xlUp))、End向下键(End(xlDown))、End向左键(End(xlToLeft)End向右键(End(xlToRight)) 注意:它移动的位置必须是相连的有内容的单元格…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
Python+ZeroMQ实战:智能车辆状态监控与模拟模式自动切换
目录 关键点 技术实现1 技术实现2 摘要: 本文将介绍如何利用Python和ZeroMQ消息队列构建一个智能车辆状态监控系统。系统能够根据时间策略自动切换驾驶模式(自动驾驶、人工驾驶、远程驾驶、主动安全),并通过实时消息推送更新车…...
NPOI操作EXCEL文件 ——CAD C# 二次开发
缺点:dll.版本容易加载错误。CAD加载插件时,没有加载所有类库。插件运行过程中用到某个类库,会从CAD的安装目录找,找不到就报错了。 【方案2】让CAD在加载过程中把类库加载到内存 【方案3】是发现缺少了哪个库,就用插件程序加载进…...

【Linux手册】探秘系统世界:从用户交互到硬件底层的全链路工作之旅
目录 前言 操作系统与驱动程序 是什么,为什么 怎么做 system call 用户操作接口 总结 前言 日常生活中,我们在使用电子设备时,我们所输入执行的每一条指令最终大多都会作用到硬件上,比如下载一款软件最终会下载到硬盘上&am…...
【Kafka】Kafka从入门到实战:构建高吞吐量分布式消息系统
Kafka从入门到实战:构建高吞吐量分布式消息系统 一、Kafka概述 Apache Kafka是一个分布式流处理平台,最初由LinkedIn开发,后成为Apache顶级项目。它被设计用于高吞吐量、低延迟的消息处理,能够处理来自多个生产者的海量数据,并将这些数据实时传递给消费者。 Kafka核心特…...