有任何不懂的问题可以评论区留言,能力范围内都会一一回答
数组学完了,但是其实我们发现会有很多问题,比如二维数组为何可以不明确行但必需明确列呢?那多维数组呢,以及为啥说int(*)[2]能表示int[3][2],但是他们不是一样的,以及int arr[1][2]那么arr,&arr,arr[0]的区别在哪怎样理解方便,接下来我将会分几期陈述我的理解,有出错的地方欢迎讨论和指出错误
以char arr[2][3] = {'a','b','c','d','e','f'};为例,我们先看arr &arr arr[0]这三个。
那我们该怎么去理解二维数组呢,这里我们(以char arr [2][3]为例)将arr理解成一个一维数组但是这个一维数组里面有2个元素,每个元素都是一个数组,每个元素所代表的一维数组里面包含3个元素
&arr | arr | arrr[0] |
取地址和数组名取的是整个数组地址 | 数组首元素代表首元素地址,这个地方我们arr将其理解成一个一维数组,所以arrr首元素就为arr[0] | 数组首元素代表首元素地址,这个地方我们arr[0]作为一个含有三个元素的一维数组, 所以arr[0]表示其首元素地址也就是arr[0][0] |
但是我们接下来思考,为何明明这三个地址是一模一样的呢我将从俩个我理解的维度做出解释
第一,我们要思考数组包括指针都是用来找值的对吧,那么请思考如果我们我们可以取数组的地址并且可以一次性通过*把整个数组的元素的值取出来会发生什么,
这个时候就出现问题了,我能一次把所有都取出来,但是如果某次我想通过指针用其中部分的值怎么办,不用*肯定是不行的,但是用*取出来的是整个数组的值,这个地方就出现问题了,由于数组我们大部分时候用的是其中部分值,所以我们通过指针指向数组中我们需要用到的最小数据单位,这样可以使我们指针能操作更精细的程序,更小巧高效,这样可以实现数组能做到的指针也可以,arr[0][0]能做到的通过指针也可以。
不得不说发明指针的人真是个天才,这样使数组和指针的功能同步了.
第二,我们要知道地址只和编译器有关,不管是int,short,char类型指针都大小相同,要么就是32位架构4个字节,要么就是64价位架8个字节,那么如果我们取整个数组的地址,通过指针可以一次性得到整个数组的值,那么意味着,我这个取地址去到了所有数组元素的值,假设这个数组有3个元素编译器是64位架构,也就是一个8个字节的值(整个数组的地址)包含3个8个字节的元素(所有元素地址),这从类型存放角度完全说不通,就像int arr[2] 和int a=2这两个占用内存完全不可能相同
那么我们取出来的这几个值通过*得到的是什么呢,相信大家一眼就可以猜出来是'a',但是从上面的角度怎么理解呢,由于*&arr和arr一样这个地方我就全部表示出来了
这个地方就能体现出arr,&arr,arr[0]的区别了,这三个都可以表示成地址,
arr表示的地址是一维数组arr[0]的地址,arr[0]故取地址后就变成了二级指针的地址。
(这个地方一维数组和一维指针可以互相表示arr[0]等价于*arr+0)
arr[0]表示的是0维数组地址arr[0][0]的地址,故取地址后变成了一级指针地址
arr表示的是二维数组,那么就可以理解成&arr是一个三级指针的地址,
(这个地方二维数组和二维指针可以互相表示arr[0][0]等价于*((*arr+0)+0))
一级指针用1个*即可实现,二级指针用2个*即可实现,三级指针用3个*即可实现
那么到这里可能很多人就有点晕了,你一会说指针指向数据类型最小单位,arr,arr[0],&arr表示的地址是相同的,但是一个*却行不通,我好绕啊,这个地方我将会用几种思维向大家解答这个问题
首先第一个就是arr
a | b | c | d | e | f |
这个是计算机内部的排列方式,
当然我们也可以理解成
a | b | c |
d | e | f |
但不管是哪种方式表示的都是首元素地址,所以这个地方&arr表示这个二维数组地址,也就是其指向的第一个也就是a(由于指针指向的是数据的最小单位,因此这个地方就用最小单位来排列)
那么arr表示的是首元素地址,也就是arr[0]地址,那么先把arr[0]的图画出来
a | b | c |
同样其指向的第一个也就是a(由于指针指向的是数据的最小单位,因此这个地方就用最小单位来排列)
arr[0]表示的是首元素地址,也就是arr[0][0]的地址那么把arr[0][0]的图画出来
a |
同样其指向的第一个也就是a(由于指针指向的是数据的最小单位,因此这个地方就用最小单位来排列)
从如上角度理解都指向的是a,但是a在其中地位不同,或者理解成这些地址表示的值相同但是他们的类型或者说属性不同
因此arr[0]+1,arr+1,&arr+1指向的位置是不一样的,
由于&arr我们知道他是整个数组arr的地址arr类型位char[2][3],故&arr的类型也就是arr地址的类型也就是char(*) [2][3],
arr表示的是首元素的地址,也就是arr[0]的地址,而arr[0]的类型是char [3],故arr类型也就是arr[0]的地址类型就是char *[3]
同样,arr[0]表示的是arr[0][0]的地址,arr[0][0]类型是char,故arr[0]类型也就是arr[0][0]地址类型就是char*
但是这三者无论怎么运算最后指向的最小数据单位依旧不会变
因此我们arr,&arr,arr[0]的区别在于类型不同
也可以这么理解
比如说我在云南省昆明市官渡区,我的最小数据单位是区,&arr+1可以理解成云南省附近的省,比如贵州省,arr+1可以理解成昆明市附近的市,比如玉溪市,arr[0]+1可以理解成官渡区附近的区,比如盘龙区,但是注意最后指向的也最小数据单位不变,还是区,结果便是贵州省省XX市XX区,云南省玉溪市XX区 和云南省昆明市盘龙区
或者换一种方式理解就是用序列点副作用理解
先回顾一下序列点副作用,比如赋值表达式语句 a = 9;
主要作用是求表达式的值, 副作用是改变 a
的值,那我们指针也可以把他指向的位置和他的类型一个看成主作用一个看成副作用,当你抓住指针指向值和指针类型的规则,你对指针的理解就入门了
因此虽然这三个表示的值是相同的,但是由于类型不同我们需要用不同的符号才能使用这些值,这三个指针指向同样的值,但是c仅靠不同类型以及不同符号就使得指针使用时能精细化同时并没有导致这些不同地址类型混乱,相反井井有条,虽然不得不承认c指针很危险,但同时也不得不承认指针是c的精髓与瑰宝。
本章看完后推荐看数组与指针思考(2)-优快云博客
写的都是博主自身学习感受以及对知识点的理解