00:00
好,同学们,我们接着看数组的下面的细节,好,数组的下标,记住是从零开始的。这点请大家一定要注意,就是对于我们一些初学者呢,很容易忘掉这个东西。我把这整理到这啊,数组的下标是从零开始的,我举个例子。还是以这个为例。大家看。大家看,比如说我这里定义了一个数组零,四。来一个三。OK,来一个字串,那么我要说的是,他能够访问的下标其实是从零到二。没有山。没有三,因为它只有三个元素,所以说它的元素是012,那你一定要用到三,你会有什么,有什么问题呢,它会报一个越界,大家看我直接给大家这样用。二位零四。我直接访问三号直接访问三,大家看这个效果,那有些同学老师你这不是已经访问不了了吗?我骗他一下,大家看我这直接编译。
01:01
他肯定会报错。对吧,这次我骗他一下。我来一个index。我拉一个index in,我给一个三,我把这个index传到这里面去,大家看到这时呢,他就从编译器上面就就把他骗过去了。你说一下这个编译器还是挺傻啊,因为他他没有办法去这样给你检测,他发现是个变量,他就不检测了,如果你直接写个三他他他会编系检测出来,但是你这个在运行的时候呢,它就会报越界,注意这里会越界。因为因为下标。它的下标。下标。诶诶这写错了,下下标是是零到二,所以访问到这个时候会报错,因此这个R。204到这个位置的时候,这个这个位置是。这个30就报错了,就越界,我们看报一个什么样的错误,就是越界的错误,以后同学们在编程的时候,你如果发现有这种越界错误,那你应该马上反应过来,肯定是咱们程序里边哪一个变量的值超过了它能够访问的下标范围,能理解吗?
02:17
当然你你也不能是负一啊,说老师我这个小一点行不行也不行,它只能是012,因为你的大小就是三嘛,而它的下标呢,是从零开始的,注意听好朋友们,我们运行一把。我们可以看到这地方会报一个错误在哪一行。可以看到在我们的这方会报一个运行时错误是一个panicle panicle就是我们叫做恐慌,恐慌就错了,报的错误呢,信息是这样子的,Index out of range,就是越界以后大家再看到这种index out of range的话,不用不用怀疑,一定是咱们的数组的下标超过了它的范围。啊,不在它范围以内,而且他告诉我们是三十五行。
03:03
要学会看错误,那三十五行是哪一行呢?就是刚才老师写的这一行。对吧,说注意这个细节好吗?注意这个细节好,我把这个给同学们放到笔记里面来。因为它的空间没有这么大。好,我把它整理到这里来。我们每一个人都要说清楚,因为数组在我们开发中用的非常的多。好朋友们,我们看下一个细节,数组下标必须在指定范围内使用,否则报一个panicle数组越界,好,这个呢,刚才已经说过了。这就不再多说。第七个刚才讲过了,好吧,这就不再多说了,整理一下第八个细节,同学们看,第八个细节构的数组是属于直类型的。在默认情况下是值传递,因此会进行只拷贝,数组间不会相互影响。也就是说,我们在传递一个数组给一个函数时,那么它其实是把整个数组进行了只拷贝。
04:04
那子拷贝就意味着我们的这个函数在函数里边,它的改变并不会影响到外边。大家想一想,我们在前面讲基本数据类型的时候是怎么说的,当我们传一个数组的时候,他也进行只拷贝。也就是说你传一个数组过去,那个函数接收到的那个数组跟你传过去的数组不是同一个了,它会只拷贝。那我们来看看这个特点,这点很重要。为什么说这点很重要呢?因为在很多的编程语言里边,数组其实是引用,引用类型,但是在构构语言里边,数组非常非常有意思,它是直类型。它是指类型,这点请大家一定要高度重视。好吧,我举个例子。来朋友们看案例。看案例好这块呢,我先把它怎么样先注销了好吗。好,同学们,看下一个案例。OK,那现在呢?为了演示这个效果呢,我先写一个函数。
05:03
写个函数。大家跟上老师思路,Function。TEST01我在这先,我在这儿定一个数组进去,比如说。Alright。二然后呢,这个数组类型我写成是3INT,注意听同学们在go里边这个数组类型,这个长度是类型的一部分,再说一遍,在构里边数组的这个长度是这个数组类型的一部分,因此这个三必须给我写清楚,也就是说,也就是说在构里面他认为这种数组和这种数组。不是同一种数据类型,他认为这个类这个是一种数据类型,而这个呢,又是另外一种数据类型,为什么?因为它长度不一样。能理解吗?就是对于我们学过其他编程语言的人很难理解这个,但是在在go里面他就是这样认为的,他认为长度是数据类型的一部分,所以说我们在这定参数类型的时候,要把这个三写上,如果你不写上各位同学,那这个就不是数组,而是切片,就LA。
06:14
再说一遍,听清楚了啊,后面我们还有案例要证明这个事情。好,同学们要把这个长度给我写写上去,否则这个就不是那么回事了,来我在这怎么怎么做一件什么事情呢,我零,我把它的值给我改了,我给他来一个70。88。也就是说我在这个函数里边,把A数组里边的第一个元素改成了88,没毛病吧?那现在呢,我们来测一下,比如说我在主函数里边,我定义了一个数组。啊,我换一种写法啊,我不停的换换写法。好,三。In。然后呢,在这里边我们给他来几个变量,比如说。
07:01
呃,1122。三三看清楚了,然后我调用test这个函数。写完了,然后呢,我在这里输出一下。我在这里输出一下瑞,我想请问大家,我想请大家思考的问题是,请问这个时候输出的瑞,它是112233还是。这个第一个元素被改成八八了呢。也就是说,也就是说我把这个A传到了test里边过后,这个有这个地方改变了元素值过后,会不会对我们这个二有影响。大家想想,刚才老师也讲过了,它是职类型,因此它不会相互影响,能理解吗?其实你这个如果画一个内存图来说的话,他应该是这样子的。注意听我就画一次啊。我就画一次。那如果是这样子的话呢,我把这个给大家画一次。
08:03
就画一次,以后我们就不再画了。这是我们的一部分代码,我把它先拿到这个。这边因为这个很重要,所以说我画一次图呢也可以。就是以后我就不会再画了啊,同学们注意听讲。这块因为涉及到一些原理性的东西,老师不得不慎重。尽量让同学们听得清楚,听得明白。好,这是两段核心代码对吧。然后呢,这边是我们的内存。我把这个内存占过来。来,代码开始执行。代码开始执行,那因为这块涉及到好多东西,我就偷过懒把这个也粘过来哈,因为这个画一个图很费时间。好,来吧,那第一个动作我们从这里开始执行了。从这里开始执行。那当我们执行到这句话的时候,同学们知道在在内存里边,在内存里边我们就会出现这么一个情况。
09:04
准确的说是在站里边好吧,但是我这不涉及到堆,我就不写那么多了,二位。这有个二这个变量,它指向了。它指向了这个数组。好,地址这些我就不画了,同学们,地址这些我就不画了,我就直接画个示意图,此时此刻你给的是1122,我就改一下。幺幺。二二。姗姗。看清楚了。好,这个呢,是在一个站里面,这个其实大家都知道,它在这个命函数里面,它是一个站,它是一个站啊,这个这个你可以认为它是在一个站里面,你你甚至可以这样理解。你甚至可以这样理解,怎么理解呢?就是刚才我们说的一运行这边会开一个站吗?好,这是个站。啊,这个我还麻烦等一下啊,等一下我先把这个,我先把这个颜色给它来一个别的颜色,这样好看一点,注意听讲。
10:03
渐变色,我也来一个别的颜色吧。灰色好。关闭。那为了好看呢,我把这个直于直接置于这个底下,诶站底站底,哎不行上来把这个把这个蓝色置到最底。好,这样就看出来了啊,就说就说这个AR呢,你可以认为这个arra,这个AR是在这个站里边,就是银色的,这这个灰色的部分。好吧,灰色部分,当它执行到test这个函数时,它会把array传给这个test。函数。诶,这母。让我函数写错了。TEST01。TEXT01。这边是test的零一,这样才匹配上啊,好回到这边来,那这个这个地方应该写成test的零一,我就不去不去换了啊,因为大家能清楚TEST01 test01呢,它会把这个俄瑞进行一个子拷贝,那进行直拷贝就意味着它会有一个新的独立的一个空间。
11:09
我姑且用另外一个颜色来表示好吧,这个呢,我们就认为是在哪里呢,是在这个test。零一就这。好吧,那么这个站会出现一个什么情况呢?进到这里面,他在调用的时候,他会把这个arra,就是老师看到这个AR进行一个只拷贝。进行一个。进行一个磁拷贝。拷贝到这边来。那拷贝到这边来的时候呢,这边就说test的零一这边会有一份跟我们这个命这这个银色的部分,我们就可以认为是M嘛。对吧,是一个命战。以前我在讲函数调用机制的时候提过这个概念,还有印象吧?应该还有印象啊,也不能说什么都忘了。
12:00
再来一个黑色啊,就相当于说以前命战里面有这么一个数组,到了太的零一,因为你传进在进行磁拷贝,这里面呢,也有一个这样的空间。这样一个速度没没问题吧,然后呢,你在这里把201这个元素找到了,改成88,也就是说此时此刻你把这个改成88了。改成88过后,这个test的零一调用完毕,调用完毕过后,他回到这边来,继续往下执行到这这个地方是在哪里,是在哪个站里边,实际上是在这个站里面执行的,是不是,那这个时候执行他打的这个AL,其实是打的哪个呢?是打的这个main站里面的ARL。那这个时候这个站其实没有发生任何变化,因此它仍然是1122和三三,你这边改变的东西跟我没有影响,能理解吗?好,我们来试一下是不是这样子,也就说你这边打印ARL的时候仍然是112233,你这边改了过后对我没有影响,因为它是只拷贝好朋友们我们跑一下。
13:00
这个我讲的稍微慢了一点啊,就是因为我知道这块同学们,呃,就是容易容易搞糊涂,尤其是以前学过别的编程语言同学更容易糊涂了。好了,我们来试一下,看看这边输出到底是什么,那为了好看呢,我重新写一下二。我这样写啊妹。M里面的二等于。好,同学们请看执行效果,根据刚才老师的分析,我们发现它输出的结果的确是1122和三三。并没有出现八八这个东西。理解。好,我把这一块给同学们整理到笔记里边去,这这块是非常重要的。好,我把代码呢,把这个核心代码和这个分析一并放到我们的代码中,这个图非常有说明说服力。好了,同学们。好,这边有一个地方稍微改一下啊,就这。这个地方,这地方要把它改成这个零一啊,这个地方我改成零啊,这这这句话改一下啊,这地方因为我我在粘贴的时候,这个粘错了啊,他是零一调用啊。
14:09
改一下,改成这个。呃,我这边我这边就不说了,好吧。放到我们的笔记里边去。咱们做什么东西要严谨。好,这是第八,那有些同学就说了,说老师,那我有一个问题你能给我解决吗?就说如果我就想在其他函数中去修改原来的数组,就说我在TEST01里面,我想改变主主站或者主函数里面的可不可以,当然可以,就可以使用指针传递。因为它默认虽然是值传递,但是呢,如果我们通过引用传,就是通过指针方式传递,那也可以成功。那也可以成功,也就是说我们第九个给他专门讨论是怎么去让我们数组改变默认传递方式,那同学们看,老师再写一个案例。我不去改这个地方好不好,我不改它,我新写一个文件啊,新写一个函数叫TEST02。
15:06
那么我把这条怎么改一下呢?各位朋友请看加个星号。加一个星号,那加个星号这边就变成什么,这个这个AL就变成了什么呀,变成了指向数组的一个指针。那这个时候咱们怎么去处理它呢?诶这个地方,这时我们就可以完成对它的一个处理。对他的一个处理,OK。那这个时候我们在里边各位同学,这里边我们怎么去访问到第一个元素,你肯定不能这样访问了吧。你不能这样访问呢?为什么不能这样访问呢?因为你你这个AL已经不是数组了,是指向数组一个指针,那同样你得先用我们的取值符抱起来。疼重要。也就是说我先把这个二的取值符取到,然后再取第一个元素,这个就相当于取到这个数组了,能理解吗?因为你二位本身是个指针吗?我用一个取值符就找到这个数组了,然后取零,好,这样就OK。
16:08
这样就能访问到我们第一个元素,注意这个很重要,这块大家注意看怎么访问到,就是通过数组指针怎么访问到我们数组的元素,OK,好这块呢,我们再来修改一下把这块。我们复制一下。好吧,我们复制一下,然后呢,把这块注销了。来,朋友们。看效果。还是这样传递,然后这地方我们传的是。数组的一个地址,那就是零,二。怎么传地址过去还记得吗?爱的符号,把我们的数组的首地址传给这个。Array的这个指针没没问题吧,然后呢,我们再去打印的时候,请请请思考这个时候会发生什么变化。这时就会发生变化,这个幺幺就会被修改,就会被修改,那么我们现在执行一下,看看是不是被修改了,我们再来画一个示意图。
17:02
好朋友们,我们执行一把。好,我们可以看到,此时此刻输出的内容就发生了一个变化。输出的内容就发生了一个变化,变成哪里了?882233,那为什么这个又发生变化了呢?好朋友们给大家来做一个说明,它是这样子的。他这样子,听我给大家再画一个图啊,还是老规矩,还是以这个为例,我们再画一个图。嗯,老规矩,我们来把这个东西给他做一个深度的剖析,它是怎么回事呢?注意听。这块涉及到一些原理性的东西,因此老师只能不厌其烦的再画一次。好,这是我们的一段代码,对不对。好,哪一个是我们的函数?这块。这块是不是我们的一段调用的函数啊。Ready。
18:00
OK,我也把它放到这里来。好,那么我们的内存仍然是它。放这来好,然后当我们的代码又开始执行了。我们代码从这里开始执行。好的,这个没有没有什么问题,它执行完O这个类型,推导一个1122过后,他在这个主站里面生成的东西仍然是这个。好,我把这个整体。复制一下。拿过来啊,为我所用,因为时间的关系,我就不去再画了,就说你第一句话执行完毕过后,瑞类型推导一个数组给他,过后呢,他在命战里边仍然是有这么一个情况。出现对不对,然后你调用了这个东西,注意听test式的零二,那T式的零二过后呢,同学们注意听泰式的零二。他又会开辟一个独立空间。独立一个空间,好,我换一个颜色,好吧,独立空间进到哪里了?进到这那进到这的时候,同学们看这时你传的是一个什么。
19:05
你在这里面传的是不是是是不是一个地址啊,那么在这个我们我们姑且把它称之为叫做太史的零二这个站里面,它会出现一个什么情况呢?他会这样子,听我说他会有个,这是肯定的。他也会有个二维。但是此时此刻他不是进行一个指拷贝,他把谁拿到了呢?他把这个宿主的首地址拿到了,那你这个宿主的首地址是多少?数值的首地址是多少,是多少就是多少,我们可以把这个首地址打出来给大家看一下。嗯。我们我们把这个数字的手地址给他看一下啊,注意听我们用前面刚才前面讲过的一个知识点format。这个我们讲的比较深度一点。Print。PRTF,大家还记不记得怎么拿,拿到手地址?D值是等于,是不是用百分号P啊,然后这个值还记得吗?
20:03
好,我们把这个地址拿过来,我再运行一下。我再运行一下,把这个地址拿到没有,拿到了就他。比较长哈,比较长,然后拿到这个地址过后,相当于说什么感觉呢,就是你这个R。它指向的是这块空间。有一个空间,注意听这个空间里面。放了一个这样的纸。这样一个值,当然你这个值你这个。还换别的颜色吧,这个颜色。这个颜色不好看。这样就就更更明确了,就瑞它有一个,它它有一它存放,它指向的是一个,指向的是这么一个东西,这个里面放了一个地址,这个地址指向哪里呢?各位同学这个地址。它指向的就是。我们。这个站里边的。
21:02
数据。他指向他。这个当然大家一看这个图就看得很清晰了,它指向他了。对不对,他执行它。哦,换个这样的意思,它指向它,那意味着就是A呢,其实它指向的就是这个数组。因为他两个地址是一样的嘛,当然我我再说一下啊,这个A瑞本身它也这个存放地址的,存放A瑞这个首地址的这个空间,它本身还有一个地址,我就不不画了,准确的说它它还有一个地址,就是这上面这个地方还有一个地址,如果你想看的话,也可以打印出来,在哪里呢。如果你想打的话,那就那就从这地方打,因为这个指针它本身也有地址,对不对,指针本身它也有地址,你可以你可以试一下打,打印一下。我们要要说就把说的说的透一点。啊,一次性把它解决。F。就是这个二瑞,这个时候它已经是个指针了,它这个指针它也有地址,它的地址是多少呢?我们也可以给大家说出来看一下P。
22:06
对不对。P等于多少呢?那这个时候你就。对不对,它本身地址你你还得这样取一下才行。我们来执行一下,看看效果。跑起来。诶,哪里写错了。我might。OK,好,再跑一个。再跑一个。好,我们可以看到就是AR这个。这个指针的地址是他。对不对,这两个肯定是不一样的,也也就是说,也就是说它本身还是有个地址的。这个没有毛病,我我在以前其实已经分析过了。看到没有,它本身也有一个,也有一个地址,相当于它就是说A瑞是一个A瑞是一个指针,它它它有一个空间存放的是什么呢?指向原先这个二位数组的这个首地址,同时呢,它本身存放这个地址的空间也有一个地址。
23:11
明白,好,这样就说的非常明明确了,这两个是一样,好这个时候做完了这这个进到这里面就做了这么多工作,然后呢,你执行的一个取值AL,那这个新AL会直接取到哪里呢?就取到这个数组了值了,然后零一这个元素就找到它了,找到八八,找到八八,你给呃找找到这个呃找到这个瑞第一个元素。的值,然后呢,你把八八给他,这个时候这句话就是老师画的这个图,这句话就会把这个幺幺改成八八。改成八八过后他就执行完毕了,他执行完毕过后,他就退出去,回到这边来,回到这边来过后呢,他又执行这个format print这个函数,对不对,那这个东西一一打印,大家想这个现在这一部分是在主站,就是在main函数里边,那它打印的就应该是8822和三三,就这么一个道理。
24:06
能理解了吗?显然这种肯定要比上面要麻烦一点,因为你这用了一个指针传递,但是大家想想哪个效率高。大家想想那个效率高,显然我们说的通过这种指针传递肯定效率要高一点,为什么?因为我我只是在拷贝的时候,这拷贝这个变量的副本,它其实只是一个地址吗。他既然是个例子,数据量是很小的。数据小段的效率,效率就高了,而你这地方是进行一个只拷贝,那只拷贝,假设我们这个数组很庞大呢,比如说我们这个数组不是三个元素,而是3000个元素,那你这个其实是非常耗费资源的,对不对?因此在使用数组的时候,如果我们就是想去改变外面数组,那同学们记住,就用指针传递。效率高,而且呢速度快。能理解吗?
25:00
大家再想想,再看看这个图,能理解吗?OK,好,那关于这一块呢的分析,我们就给大家介绍到这里,大家好好的去体会一下。大家好好体会一下,我把这个讲的是比较透彻了啊,如果这块你还没听明白,那你就好好的。把这个图还有老师的这个这块视频再好好的过一过好吗?OK。好,这是我们说的第九一个细节。这块也是非常重要的。那么我们再来看第十个细节,也是最后一个细节。第11个,第十个细节呢,我要阐述的是在构中,注意听,在构中长度是数组类型的一部分,在传递函数参数时需要考虑数值的长度,请大家看下面的三个案例。请看三纲里,你们觉得会怎么样?大家看第一个案例。再看第一个案例。第一个案例是。
26:01
这是一个主函数,这里定义定义定义了一个长,定义了一个数组,这个数组的长度为三。因为为什么123只有三个数据嘛,然后他把这个A传给了moify。他把这个传给了谁传给传给这个,但是大家看到这个接收的时候,他这个框框里面没有写数值。没有写,大家觉得这个会怎么样?告诉大家这会错,编译通不过直接报错。这个是错的。同学们可以去试一下,我不试了,相信老师就行了,肯定是错的,因为我们讲过。数组在传递的时候,长度是类型的一部分,你这样去写,相当于把一个数组给了一个切片,因此这个编译错误。我直接待会儿把这个答案写到这第一题编译直接错误。好。编译出错。编译出编译。编译出为什么错误,因为不能把把什么你不能把一个这样的。
27:07
不能把这个就是说相当于是这这个类型。相当于是这个类型付给。付给谁?传给传递给啊,或者要付给都可以传递。传递给谁给这个。因为这样这两个根本就不是同一种类型。这个是数组。这个是切片。说这个是编译,直接就错了,过不去。好,我你们自己马上去试一下可以第二个。第二个我们来看,同样这个也是一个数组,它这写了一个四也错了。周老师,这个可是这个上面不是一个数组了吗,对不起。长度是数据类型的一部分。也就是说,他认为这两个不是同一个,因此这个仍然是编译错。还是编译错误,你们可以去试一下,相信老师就行了啊,如果你不相信,你就自自己测编译错误,因为不能把这个交给这种类型。
28:09
他认为这是一种数据类型,而这个又是另外一种数据类型,仍然是错的。理解。第三题第三题大家看这个地方是一个。呃,数组,而且是长度为三的一个映射数组,这地方仍然是一个长度为三的映射数组,好,这个编译正确,OK,这个没有错误,正确。这个是正确的。正确通过啊,正确好,同学们大家看到这三个题,我说这三个题的主要目的其实就是想阐述一个重要的观点,或者说很多同学学完别的编程语言不太容易理解的地方,就是在高中,长度是数据类型的一部分,其实我就想阐述这一个观点,但是呢,我举了三个案例,加深大家对他的认识。能理解了吧,就是为了讲清这一个东西,咱们举了三个案例。
29:04
好,理解一下,好,同学们,我把第三个细节给同学们粘贴,拷贝到笔记里边去。没问题吧?好,我把案例也给同学们放到笔记中。同学们可以敲敲这个代码。OK。我把关键的地方再标红一下。编译错误。编译错误正确原因我也给大家做了一个分析。好的。好,同学们,那么到此为止呢,我们就把数组的十个细节全部给大家讲解完毕了,大家可以这样讲哈,就是如果同学们把老师讲解的这十个细节都掌握消化了,那么我们在使用数组的时候几乎就没有什么拦路虎了,就肯定能够非常正确的使用我们数组,好的,那关于数组的细节,老师就给大家介绍到这里。
我来说两句