语言深入理解指针(非常详细)(三)
目录
- 数组名的理解
- 使用指针访问数组
- 一维数组传参的本质
- 二级指针
- 指针数组
- 指针数组模拟二维数组
数组名的理解
在上⼀个章节我们在使用指针访问数组的内容时,有这样的代码:
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = &arr[0];
这里我们使用 &arr[0] 的方式拿到了数组第⼀个元素的地址,但是其实数组名本来就是地址,而且
是数组首元素的地址,我们来做个测试
#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 = %p\n", arr);
return 0;
}
输出结果如下:

我们发现数组名和数组首元素的地址打印出的结果⼀模⼀样,数组名就是数组首元素(第⼀个元素)的地
址。
但是我们再来看一个代码
#include <stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
printf("%d\n", sizeof(arr));
return 0;
}
如果是首元素的地址,那么sizeof(arr)也应该是首元素的大小,那么就是4或者是8,然而结果却是40。
其实首元素地址是对的,但是这里的sizeof(arr)是整个数组的地址(只是两个地址相同而已,但是还是有区别的就像sizeof(arr)),下面是两个例外:
• 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+1后与原来的地址相比较相差4个字节,而&arr+1后相差40个字节,刚好是整个数组元素的大小,因此我们可以推断,取整个元素地址时我们+1是移动整个数组的大小.
使用指针访问数组
#include <stdio.h>
int main()
{
int arr[10] = {0};
//输⼊
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", *(p+i));
}
return 0;
}
这个代码搞明白后,我们再试⼀下,如果我们再分析⼀下,数组名arr是数组首元素的地址,可以赋值给p,其实数组名arr和p在这里是等价的。那我们可以使用arr[i]可以访问数组的元素,那p[i]是否也可以访问数组呢
#include <stdio.h>
int main()
{
int arr[10] = {0};
//输⼊
int i = 0;
int sz = sizeof(arr)/sizeof(arr[0]);
//输⼊
int* p = arr;
for(i=0; i<sz; i++)
{
scanf("%d", p+i);
//scanf("%d", arr+i);//也可以这样写
}
//输出
for(i=0; i<sz; i++)
{
printf("%d ", p[i]);
}
return 0;
}
在第18行的地方,将* (p+i)换成p[i]也是能够正常打印的,所以本质上p[i]是等价于*(p+i)。
同理arr[i]应该等价于*(arr+i),数组元素的访问在编译器处理的时候,也是转换成首元素的地址+偏移
量求出元素的地址,然后解引用来访问的
其实在计算机处理时都是变成为*(arr+i)的形式
这种其实就类似于加法的交换性质
arr[i]=(arr+i)=(i+arr)=i[arr]
一维数组传参的本质
#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;
}

我们发现在函数内部是没有正确获得数组的元素个数
数组名是数组首元素的地址;那么在数组传参的时候,传递的是数组名,也就是说本质上数组传参本质上传递的是数组首元素的地址
所以函数形参的部分理论上应该使用指针变量来接收首元素的地址。那么在函数内部我们写sizeof(arr) 计算的是一个地址的大小(单位字节)而不是数组的大小(单位字节)。正是因为函数的参数部分的本质是指针,所以在函数内部是没办法求的数组元素个数的。
void test(int arr[])//参数写成数组形式,本质上还是指针
{
printf("%d\n", sizeof(arr));
}
void test(int* arr)//参数写成指针形式
{
printf("%d\n", sizeof(arr));//计算⼀个指针变量的⼤⼩
}
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
test(arr);
return 0;
}


运行结果也验证了一维数组的传参本质就是指针
总结:一维数组传参,形参的部分可以写成数组的形式,也可以写成指针的形式
二级指针
指针变量也是变量,是变量就有地址。
因此二级指针是可以存放一级指针的地址。(在学二级指针时我感觉有点像数学中的复合函数,函数里面又有一个函数)
我们来看看一个代码
#include<stdio.h>
int mian(){
int a=10;
int *pa=&a;
int **ppa=&pa;
return 0;
}
我们分析一下这个代码
intp中代表p是指针变量,储存的是a的地址,而对应的a类型是整形类型,因此pa前面有一个int。
而int **p中int * 是表示pa的类型是指针变量,因此要用int来表示pa,而第二个*则表示ppa是指针变量,储存的是pa的地址
对于二级指针的运算有:
*ppa 通过对ppa中的地址进行解引用,这样找到的是 pa , *ppa 其实访问的就是 pa
int b = 20;
*ppa = &b;//等价于 pa = &b
*ppa 先通过 *ppa 找到 pa ,然后对 pa 进行解引用操作: *pa ,那找到的是 a
**ppa = 30;
//等价于*pa = 30;
//等价于a = 30
指针数组
指针数组是指针还是数组?
我们类比一下,整型数组,是存放整型的数组,字符数组是存放字符的数组。那指针数组呢?是存放指针的数组。
我们可以看出像(###)(xxx)这样的表示,###就是存放的元素,而xxx则是存放的方式

数组指针的每个元素都是用来存放地址(指针)的((数组)(指针)就是通过指针来存放数组)
如下图:

数组指针的每个元素是地址,又可以指向一块区域
指针数组模拟二维数组
#include <stdio.h>
int main()
{
int arr1[] = {1,2,3,4,5};
int arr2[] = {2,3,4,5,6};
int arr3[] = {3,4,5,6,7};
//数组名是数组⾸元素的地址,类型是int*的,就可以存放在parr数组中
int* parr[3] = {arr1, arr2, arr3};
int i = 0;
int j = 0;
for(i=0; i<3; i++)
{
for(j=0; j<5; j++)
{
printf("%d ", parr[i][j]);
}
printf("\n");
}
return 0;
}
我们来看看运行结果

这是二维数组的运行结果
arr[i]是访问parr数组的元素,parr[i]找到的数组元素指向了整型⼀维数组,parr[i][j]就是整型⼀维数
组中的元素。
上述的代码模拟出二维数组的效果,实际上并非完全是二维数组,因为每一行并非是连续的(其实就是因为在穿件数组时,因为不是同一个数组,因此中间不知道隔了多少的字节)

相关文章:
语言深入理解指针(非常详细)(三)
目录 数组名的理解使用指针访问数组 一维数组传参的本质二级指针指针数组指针数组模拟二维数组 数组名的理解 在上⼀个章节我们在使用指针访问数组的内容时,有这样的代码: int arr[10] {1,2,3,4,5,6,7,8,9,10}; int *p &arr[0];这里我们使用 &am…...
实训笔记8.31
实训笔记8.31 8.31笔记一、项目开发流程一共分为七个阶段1.1 数据产生阶段1.2 数据采集存储阶段1.3 数据清洗预处理阶段1.4 数据统计分析阶段1.5 数据迁移导出阶段1.6 数据可视化阶段 二、项目数据清洗预处理的实现2.1 清洗预处理规则2.1.1 数据清洗规则2.1.2 数据预处理规则 2…...
el-table 垂直表头
效果如下: 代码如下: <template><div class"vertical_head"><el-table style"width: 100%" :data"getTblData" :show-header"false"><el-table-columnv-for"(item, index) in getHe…...
B081-Lucene+ElasticSearch
目录 认识全文检索概念lucene原理全文检索的特点常见的全文检索方案 Lucene创建索引导包分析图代码 搜索索引分析图代码 ElasticSearch认识ElasticSearchES与Kibana的安装及使用说明ES相关概念理解和简单增删改查ES查询DSL查询DSL过滤 分词器IK分词器安装测试分词器 文档映射(字…...
机器学习:塑造未来的核心力量
着科技的飞速发展,机器学习已经成为我们生活中不可或缺的一部分。无论是搜索引擎、推荐系统,还是自动驾驶汽车和机器人,都依赖于机器学习算法。本文将探讨机器学习的基本概念、应用领域以及未来发展趋势。 一、机器学习的基本概念 机器学习…...
RK3568-i2c-适配8010rtc时钟芯片
硬件连接 从硬件原理图中可以看出,rtc时钟芯片挂载在i2c3总线上,设备地址需要查看芯片数据手册。编写设备树 &i2c3 {status "okay";rx8010: rx801032 {compatible "epson,rx8010";reg <0x32>;}; };使能驱动 /kernel/…...
Spring Security - 基于内存快速demo
基于内存方式 - 只作学习参考1.引入依赖<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-thymeleaf</artifactId></dependency>2.login.html、index.html、fail.htmllogin.html:<form method…...
6 | 从文本文件中读取单词并输出不重复的单词列表
Transformation 操作 Transformation 操作是用于从一个 RDD(Resilient Distributed Dataset)创建一个新的 RDD,通常是通过对原始 RDD 的元素进行映射、筛选、分组等操作来实现的。Transformation 操作不会立即执行,而是惰性计算,只有在 Action 操作触发时才会真正执行。以…...
【微信小程序篇】- 多环境(版本)配置
最近自己在尝试使用AIGC写一个小程序,页面、样式、包括交互函数AIGC都能够帮我完成(不过这里有一点问题AIGC的上下文关联性还是有限制,会经常出现对于需求理解跑偏情况,需要不断的重复强调,并纠正错误,才能得到你想要的…...
ssh配置(一、GitLabGitHub)
一. 为什么配置ssh 使用 ssh 克隆项目,更加安全方便。 git clone 项目时一般使用两种协议 https 和 ssh 。 二. 原理的通俗解释 ssh 解决的问题是登录时的用户身份验证问题,默认使用 RSA(也支持其他算法: RSA、DSA、ECDSA、EdD…...
开了抖店后就可以直播带货了吗?想在抖音带货的,建议认真看完!
我是王路飞。 关于抖店和直播带货的关系,其实很多人经常搞不清楚。 不然的话,也不会有这个问题的出现了:开了抖店后就可以直播带货了吗? 在我看来,这个问题很简单,但在不了解抖音电商和直播带货其中门道…...
【深度学习实验】数据可视化
目录 一、实验介绍 二、实验环境 三、实验内容 0. 导入库 1. 归一化处理 归一化 实验内容 2. 绘制归一化数据折线图 报错 解决 3. 计算移动平均值SMA 移动平均值 实验内容 4. 绘制移动平均值折线图 5 .同时绘制两图 6. array转换为tensor张量 7. 打印张量 一、…...
【Golang】函数篇
1、golang函数基本定义与使用 func 函数名 (形参列表) (返回值类型列表) {函数体return 返回值列表 }其中func用于表明这是一个函数,剩下的东西与其他语言的函数基本一致,在定义与使用的时候注意函数名、参数、返回值书写的位置即可。下面使用一个例子…...
在ubuntu上安装ns2和nam(ubuntu16.04)
在ubuntu上安装ns2和nam 版本选择安装ns2安装nam 版本选择 首先,版本的合理选择可以让我们避免很多麻烦 经过测试,ubuntu的版本选择为ubuntu16.04,ns2的版本选择为ns-2.35,nam包含于ns2 资源链接(百度网盘) 链接:https://pan.bai…...
SpringCloudAlibaba之Sentinel介绍
文章目录 1 Sentinel1.1 Sentinel简介1.2 核心概念1.2.1 资源1.2.2 规则 1.3 入门Demo1.3.1 引入依赖1.3.2 集成Spring1.3.3 Spring中资源规则 1.4 Sentinel控制台1.5 核心原理1.5.1 NodeSelectorSlot1.5.2 ClusterBuilderSlot1.5.3 LogSlot1.5.4 StatisticSlot1.5.5 Authority…...
苹果微信聊天记录删除了怎么恢复?果粉原来是这样恢复的
粗心大意删除了微信聊天记录?有时候,一些小伙伴可能只是想要删除一部分聊天记录,但是在进行批量删除时,不小心勾选到了很重要的对话,从而导致记录丢失。 如果这时想找回聊天记录该怎么办?微信聊天记录删除…...
JVM的故事——虚拟机字节码执行引擎
虚拟机字节码执行引擎 文章目录 虚拟机字节码执行引擎一、概述二、运行时栈帧结构三、方法调用 一、概述 执行引擎Java虚拟机的核心组成之一,它是由软件自行实现的,能够执行那些不被硬件直接支持的指令集格式。 对于不同的虚拟机实现,执行引…...
设计模式之适配器与装饰器
目录 适配器模式 简介 角色 使用 优缺点 使用场景 装饰器模式 简介 优缺点 模式结构 使用 使用场景 适配器模式 简介 允许将不兼容的对象包装成一个适配器类,使得其他类可以通过适配器类与原始对象进行交互,从而提高兼容性 角色 目标角色…...
服务器数据恢复- Ext4文件系统分区挂载报错的数据恢复案例
Ext4文件系统相关概念: 块组:Ext4文件系统的空间被划分为若干个块组,每个块组内的结构大致相同。 块组描述符表:每个块组都对应一个块组描述符,这些块组描述符统一放在文件系统的前部,称为块组描述符表。每…...
19-springcloud(上)
一 微服务架构进化论 单体应用阶段 (夫妻摊位) 在互联网发展的初期,用户数量少,一般网站的流量也很少,但硬件成本较高。因此,一般的企业会将所有的功能都集成在一起开发一个单体应用,然后将该单体应用部署到一台服务器…...
多模态2025:技术路线“神仙打架”,视频生成冲上云霄
文|魏琳华 编|王一粟 一场大会,聚集了中国多模态大模型的“半壁江山”。 智源大会2025为期两天的论坛中,汇集了学界、创业公司和大厂等三方的热门选手,关于多模态的集中讨论达到了前所未有的热度。其中,…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
应用升级/灾备测试时使用guarantee 闪回点迅速回退
1.场景 应用要升级,当升级失败时,数据库回退到升级前. 要测试系统,测试完成后,数据库要回退到测试前。 相对于RMAN恢复需要很长时间, 数据库闪回只需要几分钟。 2.技术实现 数据库设置 2个db_recovery参数 创建guarantee闪回点,不需要开启数据库闪回。…...
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする
日语学习-日语知识点小记-构建基础-JLPT-N4阶段(33):にする 1、前言(1)情况说明(2)工程师的信仰2、知识点(1) にする1,接续:名词+にする2,接续:疑问词+にする3,(A)は(B)にする。(2)復習:(1)复习句子(2)ために & ように(3)そう(4)にする3、…...
2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...
定时器任务——若依源码分析
分析util包下面的工具类schedule utils: ScheduleUtils 是若依中用于与 Quartz 框架交互的工具类,封装了定时任务的 创建、更新、暂停、删除等核心逻辑。 createScheduleJob createScheduleJob 用于将任务注册到 Quartz,先构建任务的 JobD…...
最新SpringBoot+SpringCloud+Nacos微服务框架分享
文章目录 前言一、服务规划二、架构核心1.cloud的pom2.gateway的异常handler3.gateway的filter4、admin的pom5、admin的登录核心 三、code-helper分享总结 前言 最近有个活蛮赶的,根据Excel列的需求预估的工时直接打骨折,不要问我为什么,主要…...
cf2117E
原题链接:https://codeforces.com/contest/2117/problem/E 题目背景: 给定两个数组a,b,可以执行多次以下操作:选择 i (1 < i < n - 1),并设置 或,也可以在执行上述操作前执行一次删除任意 和 。求…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
mac 安装nvm 及git 万恶之源 mac 安装这些东西离不开Xcode。及homebrew 一、先说安装git步骤 通用: 方法一:使用 Homebrew 安装 Git(推荐) 步骤如下:打开终端(Terminal.app) 1.安装 Homebrew…...
