| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> C++知识库 -> C语言日记 25(2) 补充:二维数组与指针理解具体过程详解 -> 正文阅读 |
|
[C++知识库]C语言日记 25(2) 补充:二维数组与指针理解具体过程详解 |
一维数组名:首地址;指针常量 我们可以让指针指向一维数组名,然后再做相关操作 下面我们假设有一个二维数组,我们试图通过指针来对他进行操作:
结果: ? 我们可以看到,这里: A和(*A)输出的都是一个地址(而这里的这个地址显然就是第0行第0列的地址) 只有(**A)输出的结果是一个数值;是首个元素的值本身 A:二维数组名 { 书P83:数组名是数组首(个)元素的内存首地址 书P94:数组名就是指向数组首地址(第一个元素地址)的指针常量 } 所以,这里A代表整个二维数组的首(个)元素(A[0])的内存首地址; 或者说A作为指针指向A[0](整个二维数组的第0行)的首(个)元素的地址; { A[0]是(一个)由【A[0]([0])、A[0]([1])、A[0]([2])】这几个数组元素所组成(构成)的一个一维数组 而A[0],就是【A[0]([0])、A[0]([1])、A[0]([2])】这些(所有的)元素所组成的一个一维数组的总和,以A[0]作为这(个)整个的名称(名字) 我们可以不恰当地说:(不严谨) A[0]这个一维数组可以看作二维数组A[3][3]的一个子数组 } 而“A[0]的内存首地址”,即“一维数组的内存首(个元素的)地址”; 自然就是X系统给A[0]这个一维数组的首元素A[0][0]所安排的内存地址了。 *A:二维数组的一个一级指针 { C语言日记 25 指针与数组_宇 -Yu的博客-CSDN博客 “a[i]”改为“*(a+i)”,运行情况相同 当然,把数组名作指针名,他们仍然会有区别: 如数组会自动分配空间,而指针不能;数组名不能赋值,但指针可以 } *A作为一个一级指针,其实在本质上等价于A:(A[0]等价于(*A)) 指向A[0](整个二维数组的第0行)的首(个)元素的地址; 而(**A)在这里的这个输出语句里面,并不代表二级指针 相当于*(*A),即: 求A[0](整个二维数组的第0行)的首(个)元素的值; 那么对于二维数组 我们能否像对付一维数组那样(书P92),定义一个指针指向数组的首元素然后一个一个输出呢? 显然可以:
结果: 但是我们在这里要知道: 我们在实际使用来输出的工具仍是一个一级指针,说白了我们输出的方式和我们之前已经学过的方法没有任何区别,我们对此没有任何长进;而且,这里我们不能直接使用数组名A:
结果: 因此虽然以及指针就能(以二维数组构造的思维模式)输出整个数组,在这里我们还是应该把思维关注的重点放到二级指针之上。 那么我们是不是可以像书上说的那样,把二维数组名理解为一个指针的指针呢? 如果可以的话,即: 我们可以定义一个int **p(指针的指针),然后就可以将数组名赋给p,然后对二维数组进行相关操作; like:
?可是结果: ?也就是说: 书上说的所谓的“二维数组名为一个指针的指针”这个说法其实是完全错误的!!! “无法从“int [3][5]”转换为“int **”已经完全表示了二维数组名不是指针的指针; 而从C语言日记 25 指针与数组_宇 -Yu的博客-CSDN博客的例6-4(2)里面我们也看到了, 正确使用的打开方式为:
或者说是:
即: 先定义一个数组指针int (*p)[3],然后将数组名A赋给p,进行相关操作 即二维数组名是一个数组指针,p+1指向的是下一个数组(即下一行的地址) { 数组指针: 指向数组地址的指针,本质上就是个指针; 指针数组: 数组元素为指针的数组,其本质为数组。(例如 int *p[3],定义了p[0],p[1],p[2]三个指针) } ?二维数组指针具体例如:
注释: int(*p)[5]: 有点A[0]([0])的意思(味道),被赋址后指向的,就是数组名所代表的: 整个二维数组的首(个)元素(A[0])的内存首地址A[0]([0]); 所以我们可以说: 整个【(*p)[5]】(作为一个整体),被赋址后,就是一个指针 而拿他没有被赋址的时候单拎出来看,由于他被赋址后,就是一个指针,那么: 【(*p)[5]】自然就是一个指针变量;也就是说拿【(*p)[5]】封装好作为整体来看,他和(*p)本质上也没有什么区别 具体拆解【(*p)[5]】来看:(拿他和二维数组A[x]([y])对照比较) (*p)部分就相当于A[x]部分(行地址),[5]部分就相当于[y]部分(列地址); (*p)[5]表示的,是(一个)由【(*p)[0]、(*p)[1]、(*p)[2]、(*p)[3]、(*p)[4]】这几个数组元素所组成(构成)的一个一维数组; 同时这整个数组名,作为一个指针指向整个(这个)数组的首元素的地址(数组名不是本来就指向首地址嘛) 或者说,我们这里可以不严谨的不拘泥于符号,不拘泥于认为给我们规定好的死规矩: p[5]本身就是一个一维数组(这个总是很正常,没什么奇怪的了吧) 如同a[i]==&a[i][0],*(p+i)==&a[i][0]; 但是对于定义一个二维数组,我们可以让他“当p变为(p+1)的时候,让指针指向整个二维数组的第二行”推展至i,即: p+i==&a[i];*(p+i)==a[i]; 而拉出p本身看,它本身其实就代表着一个一维数组,“[5]"表示一维数组包含5个元素 *(p+2)+3表示a[2][3]地址(2加在p位置里面,3加在一维数组的5个位置里面;【从0加起】) *(*(p+2)+3))表示a[2][3]的值。 这里很有意思且一石二鸟的地方是: 一来(向外)“(*p)[5]”作为整个*(p+i)系列的首个元素,本身就对应了数组名找的是二维数组的首元素 同时(向内)数组名(*p)[5],本身就被看做(*p)[5]这个一维数组的首(个)元素(p[0])的地址(指针(指向这个地址)) 为什么**p不能用: 二维数组名即数组首地址,不是指针的指针。 表面上: 行地址即一维数组指针,而数组名指向行搜索即指针的指针。 但是如果A[3][3],int**p=A; 执行p++时,编译器如何知道长度(列宽:一行有多少列)? 所以,A[3][3]的地址类型,不是简单的“指针的指针”,而是行指针的指针。 而行宽是由定义的数组列数和元素类型所决定的; 例如:int类型就是4*3=12个字节。(数据对齐) 所以A的地址类型应该是int ()[3],而不是int **。 所以应该:int (*p)[3]=A; 其含义为: p是一个指向(含3个int类型元素的一维数组or行的)指针 其实我们完全可以将一种指针类型强制转为任何其他类型; 那为什么还要区分指针类型呢? 为了实现数据对齐,准确定位。 ?附: |
|
C++知识库 最新文章 |
【C++】友元、嵌套类、异常、RTTI、类型转换 |
通讯录的思路与实现(C语言) |
C++PrimerPlus 第七章 函数-C++的编程模块( |
Problem C: 算法9-9~9-12:平衡二叉树的基本 |
MSVC C++ UTF-8编程 |
C++进阶 多态原理 |
简单string类c++实现 |
我的年度总结 |
【C语言】以深厚地基筑伟岸高楼-基础篇(六 |
c语言常见错误合集 |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/11 12:40:10- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |