C语言 #指针数组 #数组指针 #数组参数、指针参数

文章目录

前言

一、指针数组

1、概念:

2、指针数组有什么用呢?

二、数组指针

1、数组指针的定义

2、数组名与 &数组名 的区别

3、数组指针如何初始化?

4、数组指针的用法

三、根据代码区分 指针数组 和 数组指针

四、数组参数、指针参数

1、一维数组传参

2、二维数组传参

3、一级指针传参

4、二级指针传参

总结


前言

路漫漫其修远兮,吾将上下而求索。


一、指针数组

指针数组是一个存放指针的数组。这里就简单讲述,想要了解地更清楚可以戳此链接:http://t.csdnimg.cn/7R5S7

1、概念:

在前面我们学过字符数组、整型数组等,字符数组即数组中的元素是char 类型,char ch [10]; 则表示数组ch 中有10个为char 类型的元素; 整型数组即数组中的元素是 int 类型,int arr [10] ; 则表示数组arr 中有10个为int 类型的元素;(假设有10个元素)显然指针数组就应该其数组有10个元素为指针,即 int* p1[10] ; 则说明数组 p1中有10个为 Int * 类型的元素;

在 int * p1[10] ; 中p1 先与 [10] 结合,说明 p1 为数组,而其前面的int* 代表着数组p1 中的元素为 int * 类型;同理数组的元素也可以是 char * 、short * 、 long * 、 float * 、 double * 等类型。

2、指针数组有什么用呢?

举例:利用指针数组模拟实现二维数组

注:此处并不为二维数组,因为二维数组在内存中是连续存放的;而这里的模拟的二维数组并不是连续存放在一块空间中;

代码如下:

#include<stdio.h>int main()
{int arr1[] = { 1,1,1,1,1 };int arr2[] = { 2,2,2,2,2 };int arr3[] = { 3,3,3,3,3 };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("%d ", parr[i][j]);//利用下标进行访问}printf("\n"); //打印完一行就换行 }return 0;
}

 代码运行结果如下:

分析:arr1 、arr2 、 arr3 是整型数组;因为数组名代表着数组的首元素地址,所以数组parr 中的元素为数组名,本质就是 int* 类型的元素;所以指针数组parr 的类型为 int* ; 数组名可以看作数组名,也可以当作数组首元素的地址;故而想要访问指针数组中存放的数组名中的元素便有两种方式,一是通过数组的下标进行访问;二是利用地址的方式进行访问;

一:

利用下标访问数组parr 中的元素 --> parr [i] ; parr数组中的元素就是数组名,即 parr[0] 相当于 arr1, parr[1] 相当于 arr2 , parr [2] 相当于 arr3 ; 那么访问arr1 arr2 arr3 中的元素也可以利用下标的形式,即得到 parr [i][j] ;

二:

利用地址的方式来访问 parr 中的元素--> 数组名parr 代表着数组parr中首元素的地址,即指针,可以利用指针+1 来跳过一个元素再解引 --> *( parr + i ),所以得到了数组parr 中的元素;然而parr 中的数组名又可以看作其首元素地址 -->  * (*( parr + i ) + j) ;

二、数组指针

1、数组指针的定义

之前我们学过整型指针: int * p1,* 代表着变量 p1 为指针变量,指针p1 指向对象的类型为 int ; 字符指针 : char * p2, * 代表着变量 p2 为指针变量,指针 p2 指向对象的类型为char  ; 浮点型指针: float * p3 ,* 代表着变量 p3 为指针变量,指针变量p3 指向对象的类型为 float ;等,那么数组指针呢?应该就是指向数组的一个指针变量;

在学习数组的时候,曾说过数组的类型,详情可以戳此链接:http://t.csdnimg.cn/DTudO

注:例如: int arr[10] ; --> 整型数组arr的类型为 int [10] ; 即去掉数组名剩下的为数组的类型;

如果将以上例子中的数组arr 的地址存放起来 --> int (*p) [10] = &arr; 

 * 与变量 p 结合代表着变量p 为指针变量,int [10] 为数组arr 的类型,代表着数组有10 个为int 类型的元素; 

注:这里的 [ ] 的优先级高于 * ,所以要用() 将 *p 括起来,以保证 p 先与 * 结合。

2、数组名与 &数组名 的区别

eg .  int arr [10];

显然,数组名arr 代表着其首元素的地址;

数组名不是为首元素地址吗?为什么此处 sizeof(arr) 的结果为40 byte? 因为数组名不能只能理解为其首元素地址;

数组名通常表示的都是其首元素的地址;

但是有两个例外

1、sizeof(数组名) ,这里的数组名表示整个数组,所以计算的是整个数组的大小

2、&数组名,这里的数组名表示的依然是整个数组,所以 &数组名 取出的是整个数组的地址;

分析:&arr[0] 、arr 针对的是数组中的首元素地址,即此地址的类型为一个整型,也就是 int* ,那么这些地址 +1 便会跳过 4 byte;而&arr 取出来整个数组的地址,即此地址的类型为40byte ,那么&arr +1 便会跳过 40byte ;

观察代码的运行结果也可得知,0136FBD8 --> 0136FBDC 之间差距了 4byte;  而 0136FBD8--> 0136FC00 --> 十六进制差了:28 --> 十进制:2*16+8*1 = 40,单位为字节;

3、数组指针如何初始化?

注:想要存放数组的地址,指针变量类型中的[ ]里必须要标明数组的元素个数

站在数组arr 的角度来看,它有10个元素,但站在指针变量 p 的角度来看,它认为自己指向的数组里面没有元素,即为0--> 指针变量p 的类型为 int (*)[0] ;

所以初始化数组指针时,一定要标明数组元素的个数;

4、数组指针的用法

数组指针不适合用于一维数组中,至少是用到二维、三维数组之中;

例二:(常见用法)

代码如下:

#include<stdio.h>void print(int(*p)[4], 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][4] = { {1,2,3,4},{1,2},{1,2,3}};print(arr, 3, 4);//二维数组的首元素是其第一行的元素,即一维数组return 0;
}

代码运行结果如下:

注:二维数组数组名代表着其首元素的地址,而二维数组的首元素是其一行元素,即一维数组,所以在函数形参部分要用数组指针来接收 (当然,实参传的是二维数组,也可以用二维数组来接收);既然形参是一维数组,即一维数组名,而一维数组名又为其首元素地址;于是乎此处便又有两种方式来访问二维数组arr 中的所有元素;一是利用数组的下标进行访问,二是利用地址进行访问;

利用数组下标进行访问: p[i][j] ; 形参 int(*p)[4] 接受了实参 arr ,arr 为二维数组,其数组名代表着其第一排元素的地址即一维数组的地址,而变量 p 为指向一维数组的指针变量,即 可以将p看作二维数组名arr  ;那么利用数组的下标进行访问即可得到   p[i][j] ;

利用地址进行访问:*(*(p + i) + j) ;形参中变量 p为一个指向一维数组的指针变量;指针变量的类型为 int ( * )[4] ,所以 p+1 ,便会跳过此一维数组而访问到下一个一维数组(即二维数组的下一个元素);又可以将一维数组名当作其首元素的地址,*( p + i ) 为一维数组的数组名,*( p + i) + j 代表着访问到各个元素的地址,想要得到元素就要对地址进行解引用操作,即 *(*(p + i) + j ) ; 

三、根据代码区分 指针数组 和 数组指针

int arr[5] ;

int * parr1[10] ;

int (*parr2)[10] ;

int (*parr3[10]) [5];

分析:

1、arr 与 [ ] 先结合,代表着 arr 为数组,即数组arr 有10个int 类型的元素;所以arr 是整型数组;

2、 由于 [ ] 的优先级高于 * ,故而 parr1 先于 [ ] 结合,代表着parr1 为数组,即数组 parr1 有10个为 int * 类型的元素;所以 parr1 是整型指针数组;

3、( ) 将* 与 parr2 括起来,代表着parr2 先与 * 结合,代表着变量 parr2 为指针变量,指针变量 parr2 指向了有10个为 int* 元素的数组,即此数组的类型为 int (*) [10] ;所以 parr2 为数组指针;

4、由于[ ] 的优先级高于* ,所以parr3 先与 [ ] 结合,代表着parr3 为数组,即有10个为 int (*)[5] 类型的数组,所以数组 parr3 为存放数组指针的数组;所以parr3 为数组指针数组;(可以理解为二维数组)

四、数组参数、指针参数

1、一维数组传参

一维数组的数组名有两种理解方式,一是理解为数组名代表着整个数组,想要访问数组中的元素的话就用下标访问即可;二是,将一维数组名当作其首元素的地址,那么想要访问此一维数组中的元素就要利用地址进行访问;

所以形参接收形式上可以划分为两种,一是用一维数组来接受,二是利用其元素类型的指针来接收;

注:形参用一维数组来接收实参传过来的一维数组时,形参部分可以不用写数组元素的个数,但是写了也不会报错,因为编译器根本就不会用这个值;

例3:

 int arr1[10] = {0} ;

若是将数组arr1传参,那么形参部分便可以写作:

int arr[ ]         //形参部分用一维数组来接收,省略了数组的元素个数

int arr[10]       //形参部分用一维数组来接收,并未省略了数组的元素个数

int * p             //形参部分用传过来数组元素类型的指针来接收

同理,例4:

int* arr2[10] = { 0 } ;

若是将数组arr2传参,那么形参部分便可以写作:

int* arr [ ]       //形参部分用一维数组来接收,省略了数组的元素个数

int* arr [10]        //形参部分用一维数组来接收,并未省略了数组的元素个数

int** p      //形参部分用传过来数组元素类型的指针来接收;数组arr2 中的元素类型为int* ;

此处 int** p第二个 * 代表了变量p 是指针变量,即指针变量p 指向的对象类型为 int* ;

2、二维数组传参

同理,二维数组的数组名也有两种理解,一是理解为数组名代表着整个数组,想要访问数组中的元素的话就用下标访问即可;二是,将一维数组名当作其首元素的地址,只不过二维数组的首元素是其第一行的元素,那么想要访问此二维数组中的元素就要利用地址进行访问;

所以二维数组的形参接收形式上可以划分为两种,一是用二维数组来接受,二是利用此二维数组首元素(其第一行元素)的类型的指针来接收;

注:

1、形参用二维数组来接收实参传过来的二维数组时,形参部分可以不用写数组行的信息,但是写了也不会报错,因为编译器根本就不会用这个值;但是不可省略列的信息;

2、二维数组的首元素为其第一行的元素

例4:

int arr3 [3][5] = { 0 } ;

若是将数组arr3传参,那么形参部分便可以写作:

int arr[ ][5]     //形参部分用二维数组来接收,省略了数组行的信息

int arr[3][5]     //形参部分用二维数组来接收,没有省略了数组行的信息

int (*p) [5]       //形参部分用此二维数组的首元素类型的指针来接收;

                       //二维数组首元素的类型为int [5] , * 代表着变量 p 为指针变量,指针变量p 的类型为 int (*) [5] ,指针变量指向的对象的类型为 int [5];

3、一级指针传参

若是实参传一级指针,那么实参是怎么样的类型,形参就用什么类型的指针接收即可;

那么有哪些数据传参需要用一级指针变量来接受呢:

1、一级指针变量

2、对变量进行& 操作

3、数组的数组名(其数组的元素不为指针,数组名为其首元素地址;不论几维数组)

4、二级指针传参

若是实参传二级指针,那么实参是怎么样的类型,形参就用什么类型的指针接收即可;

那么有哪些数据传参需要用二级指针变量来接受呢:

1、二级指针变量

2、对一级指针变量进行& 操作

3、指针数组的数组名(指针数组的元素为指针;不论几维数组)


总结

1、指针数组是一个存放指针的数组。

2、想要访问指针数组中存放的数组名中的元素便有两种方式,一是通过数组的下标进行访问;二是利用地址的方式进行访问;

3、数组名通常表示的都是其首元素的地址;

但是有两个例外

1、sizeof(数组名) ,这里的数组名表示整个数组,所以计算的是整个数组的大小

2、&数组名,这里的数组名表示的依然是整个数组,所以 &数组名 取出的是整个数组的地址;

4、数组指针的初始化:想要存放数组的地址,指针变量类型中的[ ]里必须要标明数组的元素个数

5、[ ] 的优先级高于 *

6、那么有哪些数据传参需要用一级指针变量来接受呢:a、一级指针变量     b、对变量进行& 操作  c、数组的数组名(其数组的元素不为指针,数组名为其首元素地址;不论几维数组)

7、那么有哪些数据传参需要用二级指针变量来接受呢:a、二级指针变量  b、对一级指针变量进行& 操作   c、指针数组的数组名(指针数组的元素为指针;不论几维数组)

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

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

相关文章

Shell编程之正则表达式与文本三剑客

目录 一、正则表达式 1.引言--什么是正则表达式 1.1正则表达式的功能 2.基础正则表达式&#xff08;BRE&#xff09; 2.1特殊字符 2.2定位符 2.3非打印字符 3.扩展正则表达式(ERE) 4.元字符操作的案列 二、命令小工具 1.cut&#xff1a;列截取工具 2.sort排序 …

【Android】使用ViewPager2与TabLayout实现顶部导航栏+页面切换

【Android】使用ViewPager2与TabLayout实现顶部导航栏&#xff0b;页面切换 TabLayout与ViewPager2概述 TabLayout TabLayout 是 Android 支持库中的一个组件&#xff0c;它是 Design 支持库的一部分。TabLayout 提供了一个水平的标签页界面&#xff0c;允许用户在不同的视图…

CogVideo 实测,智谱「清影」AI视频生成,全民免费,连 API 都开放了!

不得不说&#xff0c;AI 视频生成界最近非常火热~ 前有快手「可灵」开放内测&#xff0c;一下子带火了老照片修复&#xff0c;全网刷屏&#xff1a; 怕是你还没拿到内测资格&#xff0c;被称为 “国货之光” 的「可灵」就结束了免费无限量模式。每天只有66点的免费额度&#x…

鸿蒙(API 12 Beta2版)【创建NDK工程】

创建NDK工程 下面通过DevEco Studio的NDK工程模板&#xff0c;来演示如何创建一个NDK工程。 说明 不同DevEco Studio版本的向导界面、模板默认参数等会有所不同&#xff0c;请根据实际工程需要&#xff0c;创建工程或修改工程参数。 通过如下两种方式&#xff0c;打开工程创…

2024-07-27 Unity Excel —— 使用 EPPlus 插件读取 Excel 文件

文章目录 1 前言2 项目地址3 使用方法3.1 写入 Excel3.2 读取 Excel3.3 读写 csv 文件 4 ExcelSheet 代码 1 前言 ​ 前几日&#xff0c;一直被如何在 Unity 中读取 Excel 的问题给困扰&#xff0c;网上搜索相关教程相对古老&#xff08;4、5 年以前了&#xff09;。之前想用 …

【openavis】明厨亮灶算法仓

明厨亮灶算法仓主要用于学校食堂&#xff0c;餐厅等饮食卫生安全监管场景&#xff0c;目前包含的算法如下&#xff1a; 算法类型 算法卡片 明厨亮灶算法仓 老鼠检测 垃圾桶未盖 厨师服检测 厨师帽检测 口罩检测 手套检测 动火离人 1. 算法规格介绍&#xff1a; 算…

基于STM32瑞士军刀--【FreeRTOS开发】学习笔记(一)|| RISC / 底层代码执行步骤 / 汇编指令

本篇文章基于韦东山老师讲课笔记和自己理解编写。 RISC ARM芯片属于精简指令集计算机(RISC&#xff1a;Reduced Instruction Set Computing)&#xff0c;它所用的指令比较简单&#xff0c;有如下特点&#xff1a; ① 对内存只有读、写指令 ② 对于数据的运算是在CPU内部实现 …

你在找提升效率的解决方案还是追求效果的解决方案

企业在寻求“解决方案”时&#xff0c;最好先想清楚&#xff0c;你是想提升某项工作的效率&#xff0c;还是要改善某项工作的效果&#xff1f; 提升效率的解决方案主要是为了在保证质量的前提下提升某项确定工作的完成速度。以政务解决方案为例&#xff1a;当任何人都能通过移…

HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据

HAL STM32 SPI/ABZ/PWM方式读取MT6816磁编码器数据 &#x1f4da;MT6816相关资料&#xff08;来自商家的相关资料&#xff09;&#xff1a; 资料&#xff1a;https://pan.baidu.com/s/1CAbdLBRi2dmL4D7cFve1XA?pwd8888 提取码&#xff1a;8888&#x1f4cd;驱动代码编写&…

某量JS逆向

https://chat.sensetime.com/wb/chat 目录 一、发起请求 二、观察发现只有入参 __data__ 进行了加密&#xff0c;返回是明文 三、 观察JS调用栈 四、从JS中搜索 __data__ 五、使用XHR对Ajax请求进行断点 六、再次发起请求就会断点拦住请求 七、对XHR入口分析 八、逐个…

【C++】选择结构- 嵌套if语句

嵌套if语句的语法格式&#xff1a; if(条件1) { if(条件1满足后判断是否满足此条件) {条件2满足后执行的操作} else {条件2不满足执行的操作} } 下面是一个实例 #include<iostream> using namespace std;int main4() {/*提示用户输入一个高考分数&#xff0c;根据分…

花几千上万学习Java,真没必要!(二十九)

1、基本数据类型包装类&#xff1a; 测试代码1&#xff1a; package apitest.com; //使用Integer类的不同方法处理整数。 //将字符串转换为整数&#xff08;parseInt&#xff09;和Integer对象&#xff08;valueOf&#xff09;&#xff0c; //将整数转换回字符串&#xff08;…

【计算机网络】DNS命令练习与抓包分析实验

一&#xff1a;实验目的 1&#xff1a;掌握DNS缓存的清除方法&#xff0c;了解DNS缓存的作用和影响。 2&#xff1a;熟悉nslookup和dig等DNS查询工具的使用&#xff0c;理解DNS查询的基本原理和过程。 3&#xff1a;通过抓包和分析&#xff0c;深入了解DNS查询和响应消息的格…

html+css 实现悬浮按钮

前言&#xff1a;哈喽&#xff0c;大家好&#xff0c;今天给大家分享htmlcss 绚丽效果&#xff01;并提供具体代码帮助大家深入理解&#xff0c;彻底掌握&#xff01;创作不易&#xff0c;如果能帮助到大家或者给大家一些灵感和启发&#xff0c;欢迎收藏关注哦 &#x1f495; 文…

Python+Flask+MySQL+日线指数与情感指数预测的股票信息查询系统【附源码,运行简单】

PythonFlaskMySQL日线指数与情感指数预测的股票信息查询系统【附源码&#xff0c;运行简单】 总览 1、《股票信息查询系统》1.1 方案设计说明书设计目标工具列表 2、详细设计2.1 登录2.2 程序主页面2.3 个人中心界面2.4 基金详情界面2.5 其他功能贴图 3、下载 总览 自己做的项…

【iOS】——属性关键字

属性关键字的类型 在iOS中属性关键字分为四种类型&#xff1a; 可访问性: readonly ,readwrite原子性 &#xff1a; atomic &#xff0c;nonatomic内存管理 &#xff1a; retain/strong/copy&#xff0c; assign/unsafe_unretained&#xff0c;weak方法命名&#xff1a;sette…

Linux 动静态库

一、动静态库 1、库的理解 库其实是给我们提供方法的实现&#xff0c;如上面的对于printf函数的实现就是在库中实现的&#xff0c;而这个库也就是c标准库&#xff0c;本质也是文件&#xff0c;也有对应的路径 2、区别 静态库是指编译链接时&#xff0c;把库文件的代码全部加入…

前端canvas——赛贝尔曲线

曲线之美&#xff0c;不在于曲线本身&#xff0c;而在于用的人。 所以就有了这期赛贝尔曲线。 新规矩&#xff0c;先上个GIT。 效果图 开局一张图&#xff0c;代码全靠编。 代码 画骨 先想着怎么画一个心形吧&#xff0c;等你想好了&#xff0c;就知道怎么画了。 首先就还…

Cyberchef基础概念之-循环语句操作-Jump/Label

在本专栏的前面的文章介绍了fork,merge,subsection,register等多种概念来解决实际场景的问题。本文将介绍的Jump/Label的操作类似于编程语言中的for和while的功能&#xff0c;相信在学会使用jump操作后&#xff0c;将有助于解决更为复杂的数据处理问题。 本文将详细的介绍该操…

每日OJ_力扣+牛客_另类加法_不用加号的加法

目录 力扣面试题 17.01. 不用加号的加法 解析代码 牛客另类加法 解析代码 力扣面试题 17.01. 不用加号的加法 面试题 17.01. 不用加号的加法 设计一个函数把两个数字相加。不得使用 或者其他算术运算符。 示例: 输入: a 1, b 1 输出: 2提示&#xff1a; a, b 均可能…