当前位置: 首页 > news >正文

深入理解指针2:数组名理解、一维数组传参本质、二级指针、指针数组和数组指针、函数中指针变量

目录

1、数组名理解

2、一维数组传参本质

3、二级指针

4、指针数组和数组指针

5、函数指针变量


1、数组名理解

首先来看一段代码:

int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0;
}

输出的结果是:40,如果arr是数组首元素的地址,那输出应该是4/8才对。

其实数组名就是数组首元素(第一个元素)的地址是对的,但是有两个例外:

  • sizeof(数组名)。sizeof中单独放数组名,这里的数组表示整个数组,计算的是整个数组的大小,单位是字节
  • &数组名。这里的数组名表示整个数组,取出的是整个数组的地址(不是首元素的地址)。

除此之外,任何地方使用数组名,数组名都表示首元素的地址。

再来看一段代码:

#include <stdio.h>
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };printf("&arr[0] = %p\n", &arr[0]);printf("&arr[0]+1 = %p\n", &arr[0] + 1);printf("arr = %p\n", arr);printf("arr+1 = %p\n", arr + 1);printf("&arr = %p\n", &arr);printf("&arr+1 = %p\n", &arr + 1);return 0;
}

输出结果:

这里我们发现&arr[0]和&arr[0]+1相差4个字节,arr和arr+1相差4个字节,是因为&arr[0]和 arr 都是首元素的地址,+1就是跳过1个元素。

但是&arr 和 &arr + 1 相差40个字节,这就是因为&arr是数组的地址,+1 操作是跳过整个数组的。

2、一维数组传参本质

先看一段代码:

#include <stdio.h>
void test(int arr[])
{int sz2 = sizeof(arr) / sizeof(arr[0]);printf("sz2 = %d\n", sz2);
}
int main()
{int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };int sz1 = sizeof(arr) / sizeof(arr[0]);printf("sz1 = %d\n", sz1);test(arr);return 0;
}

输出结果

在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组首元素的地址。所以函数形参的部分理论上应该使用指针变量来接受首元素的地址。

3、二级指针

假设有下面的声明:

int zippo[4][2];//内含int数组的数组
  • 因为zippo是数组首元素的地址,所以zippo的值和&zippo[0]相同。而zippo[0]本身是一个内含两个整数的数组,所以zippo[0]的值和它首元素(一个整数)的地址(即&zippo[0][0]的值相同。简而言之,zippo[0]是一个占用一个int大小对象的地址。所以zippo和zippo[0]的值相同。
  • 给指针或地址加1,其值会增加对应类型大小的值。在这方面,zippo和zippo[0]不同,因为zippo指向的对象占用了两个int大小,而zippo[0]指向的对象只占用一个int大小。因此,zippo+1和zippo[0]+1的值不同。
  • zippo[0]是该数组首元素(zippo[0][0])的地址,所以 *(zippo[0])表示存储在zippo[0][0]上的值。与此类似,*zippo代表该数组首元素(zippo[0])的值,但是zippo[0]本身是一个int类型值的地址。该值的地址是&zippo[0][0]。所以*zippo就是&zippo[0][0]。**zippo与*&zippo[0][0]等价。

#include <stdio.h>
int main()
{int zippo[4][2] = { {2,4},{6,8},{1,3},{5,7} };printf("   zippo = %p,      zippo + 1 = %p\n", zippo, zippo + 1);printf("zippo[0] = %p,   zippo[0] + 1 = %p\n", zippo[0], zippo[0] + 1);printf("  *zippo = %p,     *zippo + 1 = %p\n", *zippo, *zippo + 1);printf("zippo[0][0] = %d\n", zippo[0][0]);printf("  *zippo[0] = %d\n", *zippo[0]);printf("    **zippo = %d\n", **zippo);printf("zippo[2][1] = %d\n", zippo[2][1]);printf("*(*(zippo+2) + 1) = %d\n", *(*(zippo + 2) + 1));return 0;
}

运行结果:

zippo 二维数组首元素的地址(每个元素都是内含两个 int 类型元素的一维数组)

zippo+2  二维数组的第 3个元素 (即一维数组)的地址

*(zippo+2) 二维数组的第 3个元素(即一维数组)的首元素(一个 int 类型的值)地址

*(zippo+2) + 1  二维数组的第 3个元素(即一维数组)的第 2个元素(也是一个 int 类型的值)地址

*(*(zippo+2) + 1)  二维数组的第 3个一维数组元素的第 2个int 类型元素的值,即数组的第3行第2
列的值 (zippo[2][1])

4、指针数组和数组指针

指针数组的本质其实是数组,它里面存放的是指针,数组中每个元素的类型是指针类型(int*或char*)。

指针数组的创建方式:

int * arr[10] = {0};

数组指针的本质其实是指针变量,存放的是数组的地址,能够指向数组的指针变量。

数组指针的创建方式:

int (*pt)[10];

 数组指针的初始化:

int arr[10] = {0};
int (*pt)[10] = &arr;

字符指针变量:

char* p = "hello";

这里本质上是把字符串“hello”,首字符h的地址存放在p中。

5、函数指针变量

我们先来看一段代码:

#include <stdio.h>
void test()
{printf("hehe\n");
}
int main()
{printf("test:  %p\n", test);printf("&test: %p\n", &test);return 0;
}

运行结果:

这说明函数是有地址的,和数组一样,函数名就是函数的地址。当然也可以通过&函数名的方式后的函数的地址。

如果我们要将函数的地址存放起来,就得创建函数指针变量。

void test()
{printf("hehe\n");
}
void (*pf1)() = &test;
void (*pf2)() = test;int Add(int x, int y)
{return x + y;
}
int(*pf3)(int, int) = Add;
int(*pf3)(int x, int y) = &Add;//x和y写上或者省略都是可以的

函数指针变量的使用:通过函数指针调用指针指向的函数。

#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

相关文章:

深入理解指针2:数组名理解、一维数组传参本质、二级指针、指针数组和数组指针、函数中指针变量

目录 1、数组名理解 2、一维数组传参本质 3、二级指针 4、指针数组和数组指针 5、函数指针变量 1、数组名理解 首先来看一段代码&#xff1a; int main() {int arr[10] { 1,2,3,4,5,6,7,8,9,10 };printf("%d\n", sizeof(arr));return 0; } 输出的结果是&…...

【C/C++】C语言实现单链表

C语言实现单链表 简单描述代码运行结果 简单描述 用codeblocks编译通过 源码参考连接 https://gitee.com/IUuaena/data-structures-c.git 代码 common.h #ifndef COMMON_H_INCLUDED #define COMMON_H_INCLUDED#define ELEM_TYPE int //!< 链表元素类型/*! brief 返回值类…...

VBA数据库解决方案第九讲:把数据库的内容在工作表中显示

《VBA数据库解决方案》教程&#xff08;版权10090845&#xff09;是我推出的第二套教程&#xff0c;目前已经是第二版修订了。这套教程定位于中级&#xff0c;是学完字典后的另一个专题讲解。数据库是数据处理的利器&#xff0c;教程中详细介绍了利用ADO连接ACCDB和EXCEL的方法…...

蓝桥杯刷题-12-公因数匹配-数论(分解质因数)不是很理解❓❓

蓝桥杯2023年第十四届省赛真题-公因数匹配 给定 n 个正整数 Ai&#xff0c;请找出两个数 i, j 使得 i < j 且 Ai 和 Aj 存在大于 1 的公因数。 如果存在多组 i, j&#xff0c;请输出 i 最小的那组。如果仍然存在多组 i, j&#xff0c;请输出 i 最小的所有方案中 j 最小的那…...

机器视觉学习(十二)—— 绘制图形

目录 一、绘制函数参数说明 1.1 cv2.line(&#xff09;绘制直线 1.2 cv2.rectangle&#xff08;&#xff09;绘制矩形 1.3 cv2.circle&#xff08;&#xff09; 绘制圆形 1.4 cv2.ellipse&#xff08;&#xff09;绘制椭圆 1.5 cv2.polylines&#xff08;&#xff09;绘制…...

软考信息处理技术员2024年5月报名流程及注意事项

2024年5月软考信息处理技术员报名入口&#xff1a; 中国计算机技术职业资格网&#xff08;http://www.ruankao.org.cn/&#xff09; 2024年软考报名时间暂未公布&#xff0c;考试时间上半年为5月25日到28日&#xff0c;下半年考试时间为11月9日到12日。不想错过考试最新消息的…...

linux:du和df区别

文章目录 1. 概述2. du 命令2. df 命令3. 区别总结 1. 概述 du 和 df 都是 Linux 系统中用于查看磁盘空间使用情况的命令&#xff0c;但它们的功能和用法有所不同。 2. du 命令 du 是 “disk usage” 的缩写&#xff0c;用于显示文件或目录的磁盘使用情况。du 命令用于查看指…...

MacOS Docker 部署 Redis 数据库

一、简介 Redis是一个开源的、使用C语言编写的、基于内存亦可持久化的Key-Value数据库&#xff0c;它提供了多种语言的API&#xff0c;并支持网络交互。Redis的数据存储在内存中&#xff0c;因此其读写速度非常快&#xff0c;每秒可以处理超过10万次读写操作&#xff0c;是已知…...

个推助力小米汽车APP实现智能用户触达,打造智能出行新体验

4月3日&#xff0c;小米SU7首批交付仪式在北京亦庄的小米汽车工厂总装车间举行&#xff0c;全国28城交付中心也同步开启首批交付。随着小米SU7系列汽车的正式发售和交付&#xff0c;小米汽车APP迎来了用户体量的爆发式增长。 小米汽车APP是小米汽车官方推出的手机应用&#xff…...

科研 | SCI、SCIE、ESCI、JIF、IF、IEEE Fellow

文章目录 SCISCIESCIE和SCI的区别SCIE和ESCI的区别JIF和IF有什么不同吗&#xff1f;IEEE Fellow SCI 科学引文索引&#xff08;Science Citation Index&#xff0c;SCI&#xff09;是由Clarivate Analytics&#xff08;原Thomson Reuters&#xff09;维护的一个重要的学术引文…...

10倍提效!用ChatGPT编写系统功能文档。。。

系统功能文档是一种描述软件系统功能和操作方式的文档。它让开发团队、测试人员、项目管理者、客户和最终用户对系统行为有清晰、全面的了解。 通过ChatGPT&#xff0c;我们能让编写系统功能文档的效率提升10倍以上。 ​《Leetcode算法刷题宝典》一位阿里P8大佬总结的刷题笔记…...

【Linux进阶之路】地址篇

文章目录 一、ipv4地址1. 基本概念2. 分类3.CIDR4.特殊的ip地址 二、IP协议1. 协议字段2.分片与重组3.路由 三、NAT技术1.公有和私有2.NAT3.NAPT 四、ARP协议1.MAC地址2.ARP 五、DHCP协议六、DNS协议尾序 一、ipv4地址 1. 基本概念 概念&#xff1a;IP地址&#xff0c;英文全…...

代码随想录第34天| 1005.K次取反后最大化的数组和 134. 加油站 135. 分发糖果

1005.K次取反后最大化的数组和 1005. K 次取反后最大化的数组和 - 力扣&#xff08;LeetCode&#xff09; 代码随想录 (programmercarl.com) 贪心算法&#xff0c;这不就是常识&#xff1f;还能叫贪心&#xff1f;LeetCode&#xff1a;1005.K次取反后最大化的数组和_哔哩哔…...

Rust线程间通信通讯channel的理解和使用

Channel允许在Rust中创建一个消息传递渠道&#xff0c;它返回一个元组结构体&#xff0c;其中包含发送和接收端。发送端用于向通道发送数据&#xff0c;而接收端则用于从通道接收数据。不能使用可变变量的方式&#xff0c;线程外面修改了可变变量的值&#xff0c;线程里面是拿不…...

Vue3组件基础示例

组件是vue中最推崇的&#xff0c;也是最强大的功能之一&#xff0c;就是为了提高重用性&#xff0c;减少重复性的开发。 如何使用原生HTML方法实现组件化 在使用原生HTML开发时&#xff0c;我们也会遇到一些常见的功能、模块&#xff0c;那么如何在原生HTML中使用组件化呢&am…...

如何使用PL/SQL Developer工具导出clob字段的表?

1 准备测试数据 导出测试对象&#xff1a;表test_0102&#xff0c;others字段为clob类型 --创建中间表test_0101 create table test_0101( id number, name varchar2(20), others clob);--插入100条测试数据 beginfor i in 1..100 loopinsert into test_0101 values(i,i||_a,l…...

蓝桥杯刷题 深度优先搜索-[NewOJ P1158]N皇后(C++)

题目描述 n皇后问题&#xff1a;n 个皇后放置在 nn 的棋盘上&#xff0c;并且使皇后彼此之间不能相互攻击。 上面布局用序列2 4 6 1 3 5表示&#xff0c;第i个数字表示第i行皇后放的列号。 按照这种格式输出前3个解&#xff0c;并统计总解数。 输入格式 输入一个正整数n&a…...

python实例2.2:编写一个装饰器,计算任何一个函数执行的时间(详解及其知识点拓展)

目录 一、编写一个装饰器,计算任何一个函数执行的时间 二、装饰器详解,及其用法举例...

Jenkins 持续集成 【CICD】

持续集成 &#xff08;Continuous integration&#xff0c;简称CI&#xff09; 持续集成是一种开发实践&#xff0c;它倡导团队成员频繁的集成他们的工作&#xff0c;每次集成都通过自动化构建&#xff08;包括编译、构建、打包、部署、自动化测试&#xff09;来验证&#xff…...

【CHI】(十二)Memory Tagging

目录 1. Introduction 2. Message extensions 3. Tag coherency 4. Read transaction rules 4.1 TagOp values 4.2 Permitted initial MTE tag states 5. Write transactions 5.1 Permitted TagOp values 5.2 TagOp, TU, and tags relationship 6. Dataless transact…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器

一.自适应梯度算法Adagrad概述 Adagrad&#xff08;Adaptive Gradient Algorithm&#xff09;是一种自适应学习率的优化算法&#xff0c;由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率&#xff0c;适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...

vscode(仍待补充)

写于2025 6.9 主包将加入vscode这个更权威的圈子 vscode的基本使用 侧边栏 vscode还能连接ssh&#xff1f; debug时使用的launch文件 1.task.json {"tasks": [{"type": "cppbuild","label": "C/C: gcc.exe 生成活动文件"…...

MVC 数据库

MVC 数据库 引言 在软件开发领域,Model-View-Controller(MVC)是一种流行的软件架构模式,它将应用程序分为三个核心组件:模型(Model)、视图(View)和控制器(Controller)。这种模式有助于提高代码的可维护性和可扩展性。本文将深入探讨MVC架构与数据库之间的关系,以…...

JUC笔记(上)-复习 涉及死锁 volatile synchronized CAS 原子操作

一、上下文切换 即使单核CPU也可以进行多线程执行代码&#xff0c;CPU会给每个线程分配CPU时间片来实现这个机制。时间片非常短&#xff0c;所以CPU会不断地切换线程执行&#xff0c;从而让我们感觉多个线程是同时执行的。时间片一般是十几毫秒(ms)。通过时间片分配算法执行。…...

.Net Framework 4/C# 关键字(非常用,持续更新...)

一、is 关键字 is 关键字用于检查对象是否于给定类型兼容,如果兼容将返回 true,如果不兼容则返回 false,在进行类型转换前,可以先使用 is 关键字判断对象是否与指定类型兼容,如果兼容才进行转换,这样的转换是安全的。 例如有:首先创建一个字符串对象,然后将字符串对象隐…...

USB Over IP专用硬件的5个特点

USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中&#xff0c;从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备&#xff08;如专用硬件设备&#xff09;&#xff0c;从而消除了直接物理连接的需要。USB over IP的…...

视觉slam十四讲实践部分记录——ch2、ch3

ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...

【网络安全】开源系统getshell漏洞挖掘

审计过程&#xff1a; 在入口文件admin/index.php中&#xff1a; 用户可以通过m,c,a等参数控制加载的文件和方法&#xff0c;在app/system/entrance.php中存在重点代码&#xff1a; 当M_TYPE system并且M_MODULE include时&#xff0c;会设置常量PATH_OWN_FILE为PATH_APP.M_T…...

TSN交换机正在重构工业网络,PROFINET和EtherCAT会被取代吗?

在工业自动化持续演进的今天&#xff0c;通信网络的角色正变得愈发关键。 2025年6月6日&#xff0c;为期三天的华南国际工业博览会在深圳国际会展中心&#xff08;宝安&#xff09;圆满落幕。作为国内工业通信领域的技术型企业&#xff0c;光路科技&#xff08;Fiberroad&…...

通过 Ansible 在 Windows 2022 上安装 IIS Web 服务器

拓扑结构 这是一个用于通过 Ansible 部署 IIS Web 服务器的实验室拓扑。 前提条件&#xff1a; 在被管理的节点上安装WinRm 准备一张自签名的证书 开放防火墙入站tcp 5985 5986端口 准备自签名证书 PS C:\Users\azureuser> $cert New-SelfSignedCertificate -DnsName &…...