脆皮之“指针和数组的关系”

文章目录

  • 1. 数组名的理解
  • 2. 使用指针访问数组
  • 3. 一维数组传参的本质
  • 4. 冒泡排序
  • 5. 二级指针
  • 6. 指针数组
  • 7. 指针数组模拟二维数组

hello,大家好呀,窝是脆皮炸鸡。这一期是关于数组和指针的,我觉得并不是很难,但是我觉着下一期可能稍难,大家有什么不懂的可以在评论区询问,加油,开始学习叭!!!

Ps:点赞收藏加关注,追番永远不迷路。

在这里插入图片描述

1. 数组名的理解

大家是否记得在上一期的指针内容里,我曾说过:数组名是数组首元素的地址。但是有两个例外,这两个例外是:sizeof(数组名),&数组名。除了这两个情况,其余情况下,数组名就是数组首元素的地址。

----------------------------------------------- 1 -----------------------------------------------

举个例子:sizeof(数组名)

	int arr[7] = { 0 };printf("sizeof(arr)=%d\n", sizeof(arr)); //这里sizeof是在计算arr的大小

大家知道此处打印的结果是什么吗,是28。如果按之前说的”数组名都是数组首元素的地址“,那首元素的地址占四个字节,为什么输出是28呢?

因为,此处数组名代表的并不是数组首元素地址。sizeof(数组名),其中的数组名表示的是整个数组,计算的是整个数组的大小,单位是字节。我们再回头看,这个数组共7个整数,一个整数占4个字节,所以一共占4*7=28个字节

----------------------------------------------- 2 -----------------------------------------------

举个例子:&数组名

int arr1[7] = { 0 };
printf("arr1    =%d\n", arr1);  //这里的数组名在两种情况外,是数组首元素地址
printf("&arr1   =%d\n", &arr1);  //整个数组的地址

事实上,打印出来的两个结果是相同的,都是数组首元素地址。

这是合乎情理的,arr1(不是那两种特殊情况)代表的是数组首元素地址;&arr1代表的是数组的地址。从下图可以看出,两者的起始地址一样。

在这里插入图片描述

在此处我们看不出它俩的差异。

大家是否记得之前的一句话“指针类型决定了指针的差异”。整型指针+1,跳过4个字节;字符指针+1,跳过1个字节。那数组指针+1,应当是跳过整个数组的。

printf("arr1    =%d\n", arr1);  //数组名
printf("arr1+1  =%d\n", arr1+1);  printf("&arr1   =%d\n", &arr1);  //整个数组的地址
printf("&arr1+1 =%d\n", &arr1+1);  

在这里插入图片描述

(最后两个:44到48,+4;44到72,+28)图上显示:数组首元素地址+1,跳过4个字节;数组地址+1,跳过28个字节,即跳过整个数组。

总结:&数组名:这里的数组名表示整个数组,取出的是整个数组的地址

2. 使用指针访问数组

在此强调一下:

  • 数组是数组(是一块连续的空间,可存放一个或多个数组)
  • 指针是指针(用于存放地址的变量)
  • 它俩不是一回事,但是可以使用指针来访问地址。

为什么可以用指针来访问数组?
1.数组在内存中是连续存放的(指针+1是很方便遍历数组的)
2.指针的元素很方便遍历数组,取出数组内容。

我注释掉的方法是以前学习的方法,没有注释的方法是使用指针来访问的

int main()
{int arr[6] = { 0 };//输入int index = 0;int sz = sizeof(arr) / sizeof(arr[0]);for (index = 0; index < sz; index++){/*scanf("%d", &arr[index]); */scanf("%d", arr + index); //arr是首元素地址,+1,跳过(4个字节)一个整数。//arr+index,第一次循环就是arr+0,即首元素地址;第二次循环,arr+1,即下一个整数}//输出for (index = 0; index < sz; index++){/*printf("%d ", arr[index]); */printf("%d ", *(arr + index));//将每个元素的地址解引用,即可找到地址所指向的对象}return 0;
}

将输出的两种方式对比,arr[index] 和 * (arr+index) 它俩是完全等价滴。【其实,编译器在看到arr[index]是转化成 *(arr+index)来看的】

3. 一维数组传参的本质

数组是可以通过实参传递给函数的,现在我们来讨论一下数组传参的本质。大家先思考一下,假设我们要将数组int arr[7]传过去,当时我们说过,数组传的是数组名(实参),形参用什么来接收嘞?int arr [ ](数组大小可忽略)

在这里插入图片描述
第一种我们直接计算,结果是正确的;但在函数里却错了,为什么呢?

我们仔细看一下,print(arr),不是那两种例外情况,所以arr是数组首元素地址,要是地址的话,我们应该用int* arr接收的,然后(首元素地址4个字节) / (首元素地址4个字节)=1。到这我们就找到问题了。【之前我们之所以用int arr[ ]接收,只是为了方便理解,当时还没有学指针。】数组传参的时候,形参可以写成数组(易理解,但其实本质还是指针),也可以写指针变量。

总结:从中可以看出,数组传参的本质,传递的是首元素的地址,即便我们将形参写成数组的形式,它本质上也是一个指针变量。

那如果我们就是想将数组传过去呢?这时,我们不仅需要将数组名传过去,还需要将数组元素个数sz传过去,接下来举例:先将数组传给函数,再通过函数打印数组。

void print(int* arr, int sz)
{int index = 0;for (index = 0; index < sz; index++){printf("%d ", *(arr + index));}
}
int main()
{int arr[10] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);print(arr, sz);  将数组大小也传过去return 0;
}

4. 冒泡排序

冒泡排序的核心思想就是:两两相邻的元素进行比较。不满足顺序就交换,满足顺序就比较下一对。

以 “将乱序的数字变为有序的数字(升序/降序) ” 为例进行分析。(我这里是升序)

  1. 首先输入数列元素。
  2. 然后冒泡排序,确定冒泡排序需要几趟(index)
  3. 在每一趟里,又要进行几次比较。把什么进行比较呢?将【第一个(下标为0的元素)】和【第二个元素(下标为1的元素)】比较,第二个和第三个比较…(j),总是将arr[j]和arr[j+1]进行比较
  4. 最后打印出来。

先展示第一趟冒泡排序:看完图片之后发现,一趟冒泡排序只将一个数字放在它本应该在的位置。

在这里插入图片描述

第二趟冒号排序:
在这里插入图片描述

之后的和这类似,现在思考一下:

  1. 我有10个元素,需要几趟冒号排序呢?9趟(你想想,9个数字都已经在正确的位置了,最后一个元素的位置肯定正确呀)所以,sz个元素,sz-1趟
  2. 10个元素,第一趟进行9次比较,第二趟进行8次比较,所以:sz个元素,第一次进行sz-1次比较,第二次进行sz-2次比较…那么在循环里,如何描述几次比较呢?sz-1写成sz-1-index(第一趟index是0,这里就是sz-1),sz-2就是sz-1-1(因为此时index是1,所以是sz-1-1)
void input(int* arr, int sz);  //用于输入数字
void bubble(int* arr, int sz);  //用于冒泡排序
void print(int* arr, int sz);  //用于打印排序好的数组int main()
{int arr[10] = { 0 };int sz = sizeof(arr) / sizeof(arr[0]);//输入数字input(arr, sz);//将乱序的数字排序bubble(arr, sz);//最后将升序的数字打印出来print(arr, sz);
}
void input(int* arr, int sz)  //用于输入数字
{int index = 0;for (index = 0; index < sz; index++){scanf("%d", arr + index);}
}
void bubble(int* arr, int sz)  //用于冒泡排序
{int i = 0;for (i = 0; i < sz - 1; i++) //这是确定几趟{int j = 0;for (j = 0; j < sz - 1 - i; j++)//一趟里面比较几次{if (arr[j] > arr[j + 1]) //判断:如果前一个数字>后一个,交换{int tmp = 0;tmp = arr[j];arr[j] = arr[j + 1];arr[j + 1] = tmp;}}}
}
void print(int* arr, int sz)  //用于打印排序好的数组
{int q = 0;for (q = 0; q < sz; q++){printf("%d ", *(arr + q));}
}

5. 二级指针

我们之前学习的都是一级指针,比如:int*,char*,float*
一级指针是用来存放(普通变量)的地址
二级指针是用来存放(一级指针变量)的地址
int* ,int**

	int a = 90;int* pa = &a;  //pa是一级指针变量

这里,我将a的地址放在指针变量pa里,但是大家想想,指针变量也是变量,它也有自己的地址,我们又可以将指针变量的地址存储起来放在ppa。并且我们可以通过ppa找到最开始的普通变量a:printf(“%d”,**ppa); 也可以通过ppa改变a的值。

int*      * ppa = &pa;  //ppa是二级指针变量//这个*说明ppa是指针变量
//int*说明ppa指向的pa的类型是int*

之前我们可以通过一级指针访问数组元素,但是在这里说明,二级指针和二维数组没有任何关系。

6. 指针数组

大家可以将指针当作定语,数组是主语。所以指针数组本质上是数组。

字符数组:char arr[10]; 存放字符的数组
整型数组:int arr[10]; 存放整型的数组
指针数组:它是一个存放指针的数组,它的每个元素都是指针类型(int或者char等等)。
char* arr[10] :存放字符指针的数组。int* arr[10]:存放整型指针的数组。

它的用处:(1)可以将相同类型的变量的地址存储在数组中,不用再一个一个的存储
(2)存储之后又可以遍历数组(元素是地址)再解引用打印最初的变量

	int a = 90;int b = 41;int c = 50;int* arr[3] = { &a,&b,&c };int index = 0;for (index = 0; index < 3; index++){printf("%d ", *(arr[index]));}

7. 指针数组模拟二维数组

我先创建3个一维数组,再用过int*将它们关联起来(可以达到用1个一维数组维护3个一维数组的效果)

这是模拟出来的,不是真的二维数组

int arr1[4] = { 1,2,3,4 };
int arr2[4] = { 1,1,2,4, };
int arr3[4] = { 2,4,6,8 };
int* ARR[3] = { arr1,arr2,arr3 };
//这里的arr1并不是那两种例外,所以是数组首元素的地址
//我们想通过首元素地址然后遍历这个数组的所有元素
int i = 0;
for (i = 0; i < 3; i++)
{int j = 0;for (j = 0; j < 4; j++){printf("%d ", ARR[i][j]);//ARR[i]等价于*(ARR+i) ,ARR[i][j]等价于*(*(ARR+I)+j)}}printf("\n");
}

在这里插入图片描述

ARR [i] 是访问ARR数组的元素,ARR [i] 找到的数组元素指向了整型一维数组,ARR[i][j]就是整型一维数组中的元素。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/9933.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

自定义el-select下拉菜单的内容以及数据回显的内容

最终的效果 下拉选项的自定义内容好实现&#xff0c;因为他有默认插槽&#xff0c;所以直接在el-option标签里面写自定义内容就可以实现 <el-selectref"seriesBorderTypeRef"class"series-border-type"change"changeSeriesBorderType"v-model…

ESLint: Unexpected ‘debugger‘ statement.(no-debugger)(debugger报红)

ESLint: Unexpected debugger statement.(no-debugger) 解决办法&#xff1a; 找到.eslintrc.js文件中rules的no-debugger更改为0即可

gpustat 不能使用问题

突然间就不能用了&#xff0c;可能是环境出了问题&#xff0c;如果GPU没问题的话&#xff0c;那么换个环境重新安装试一下&#xff08;pip install gpustat&#xff09;&#xff0c;目前是换个环境就可以了&#xff08;做个笔记&#xff09;

信息系统项目管理师0101:项目建议与立项申请(7项目立项管理—7.1项目建议与立项申请)

点击查看专栏目录 文章目录 第七章 项目立项管理7.1项目建议与立项申请1.立项申请概念2.项目建议书内容记忆要点总结第七章 项目立项管理 项目立项管理是对拟规划和实施的项目技术上的先进性、适用性,经济上的合理性、效益性,实施上的可能性、风险性以及社会价值的有效性、可…

镜舟科技亮相2024中国移动算力网络大会、Qcon、DTC等多项活动

在刚刚过去的 4 月份&#xff0c;镜舟科技受邀参与一系列技术交流活动&#xff0c;与移动云、金科创新社、infoQ、墨天轮、开科唯识等媒体及合作伙伴展开积极交流&#xff0c;并分享其在数据技术、金融等垂直行业领域的创新实践&#xff0c;从产业侧、业务侧、技术侧洞察需求、…

idea-自我快捷键-2

1. 书签 创建书签&#xff1a; 创建书签&#xff1a;F11创建特色标记书签&#xff1a;Ctrl F11快速添加助记符书签&#xff1a;ctrl shift 数字键 查看书签&#xff1a; shift F11快速定位到助记符书签&#xff1a;Ctrl 数字键 删除书签&#xff1a; delete 2. 自动…

【最新点云数据增强综述】深度学习点云数据增强技术的进展

深度学习(DL)已成为点云分析任务(如检测、分割和分类)的主流和有效方法之一。为了减少深度学习模型训练过程中的过拟合,提高模型性能,尤其是在训练数据的数量和/或多样性有限的情况下,增强往往至关重要。虽然各种点云数据增强方法已被广泛应用于不同的点云处理任务中,但…

docker搭建mysql集群实现主从复制

前言 随着业务的增长&#xff0c;一台数据服务器已经满足不了需求了&#xff0c;负载过重。这个时候就需要减压了&#xff0c;实现负载均衡和读写分离&#xff0c;一主一丛或一主多从。 主服务器只负责写&#xff0c;而从服务器只负责读&#xff0c;从而提高了效率减轻压力。 …

融资融券概念和操纵流程,案例解析

融资融券是一种金融工具&#xff0c;它允许投资者在证券市场上进行杠杆交易。简单来说&#xff0c;融资就是借钱买股票&#xff0c;融券就是借股票卖出。这种交易方式可以帮助投资者在短期内获得更高的收益&#xff0c;但同时也伴随着较高的风险。 案例背景&#xff1a; 假设…

基于VOLOPV2的自动驾驶环境感知系统

基于VOLOPV2的自动驾驶环境感知系统是一个复杂的系统&#xff0c;它主要负责实时检测并识别周围环境中的各种物体和信息&#xff0c;为自动驾驶车辆提供必要的感知数据。以下是对该系统的一个简要介绍&#xff1a; 环境感知是自动驾驶系统中的一个关键部分&#xff0c;它依赖于…

静态分析-RIPS-源码解析记录-03

既然有源码可以debug&#xff0c;那么直接跑测试用例&#xff0c;来跟踪处理逻辑感觉比直接看代码理逻辑更快一些&#xff0c;尤其是涉及到了扫描阶段&#xff0c;不然不容易弄清某刻某个变量的取值。 对于所有漏洞而言&#xff0c;都是由sink点到source点检测是否有过滤函数&…

数据库管理-第187期 23ai:怎么用SQL创建图(20240510)

数据库管理187期 2024-05-10 数据库管理-第187期 23ai:怎么用SQL创建图&#xff08;20240510&#xff09;1 安装PGX1.1 数据库配置对应用户1.2 使用RPM包安装Graph Server1.3 安装Oracle Graph Client1.4 访问PGX页面 2 SQL Property Graph2.1 创建SQL属性图2.2 关于点和边图元…

副业兼职没那么难,视频号带货,1天稳定500,适合新手操作

向大家推荐一个项目&#xff1a;视频号书单号带货玩法。我已经实践了一段时间&#xff0c;并成功售出了1200多单&#xff0c;赚取了2万多元。这个项目表现相当出色&#xff0c;强烈推荐给大家&#xff01; 周周近财&#xff1a;让网络小白少花冤枉钱&#xff0c;赚取第一桶金 …

[机器学习-03] Scikit-Learn机器学习工具包学习指南:主要功能与用法解析

&#x1f3a9; 欢迎来到技术探索的奇幻世界&#x1f468;‍&#x1f4bb; &#x1f4dc; 个人主页&#xff1a;一伦明悦-CSDN博客 ✍&#x1f3fb; 作者简介&#xff1a; C软件开发、Python机器学习爱好者 &#x1f5e3;️ 互动与支持&#xff1a;&#x1f4ac;评论 &…

芋道系统springcloud模块启动报错,枚举类不能为空

问题描述&#xff1a; Error starting ApplicationContext. To display the conditions report re-run your application with debug enabled. 2024-05-10 15:50:15.756 | ERROR 9120 | main [TID: N/A] o.s.b.d.LoggingFailureAnalysisReporter | ************************…

Vue创建todolist

电子书 第三章&#xff1a; https://www.dedao.cn/ebook/reader?idV5R16yPmaYOMqGRAv82jkX4KDe175w7xRQ0rbx6pNgznl9VZPLJQyEBodb89mqoO 没有使用VUE CLI创建项目。 创建步骤&#xff1a; 1&#xff0c; 用Vite 创建项目 2&#xff0c; npm run dev 运行程序 参照之前的文…

数据结构与算法学习笔记八-二叉树的顺序存储表示法和实现(C语言)

目录 前言 1.数组和结构体相关的一些知识 1.数组 2.结构体数组 3.递归遍历数组 2.二叉树的顺序存储表示法和实现 1.定义 2.初始化 3.先序遍历二叉树 4.中序遍历二叉树 5.后序遍历二叉树 6.完整代码 前言 二叉树的非递归的表示和实现。 1.数组和结构体相关的一些知…

搭建Harbor仓库

文章目录 Harbor仓库搭建Harbor仓库安装 docker 服务修改配置文件 Harbor仓库 搭建Harbor仓库 下载 Harbor 仓库 安装 docker 服务 # step 1: 安装必要的一些系统工具 yum install -y yum-utils device-mapper-persistent-data lvm2 # Step 2: 添加软件源信息 yum-config-m…

QT--5

1> 将网络聊天室重新实现一遍 服务器端 #include "widget.h" #include "ui_widget.h"Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget) {ui->setupUi(this);ser new QTcpServer(this); }Widget::~Widget() {delete ui; }vo…

Aapache Tomcat AJP 文件包含漏洞(CVE-2020-1938)

1 漏洞描述 CVE-2020-1938 是 Apache Tomcat 中的一个严重安全漏洞&#xff0c;该漏洞涉及到 Tomcat 的 AJP&#xff08;Apache JServ Protocol&#xff09;连接器。由于 AJP 协议在处理请求时存在缺陷&#xff0c;攻击者可以利用此漏洞读取服务器上的任意文件&#xff0c;甚至…