00:00
大家好,我们接着来为大家讲解结构体的。结构体这个类型的内存分配机制,那前面呢,我们已然给大家讲了一些关于结构体的他在内存里面的布局,对不对,但是呢,还不够深入,还不够深入,因此呢,我们在这里有必要再把。结构体这种类型啊,再内存里面分配的机制呢,再给大家做一个,呃,往深再给他做一个系统和深入的一个讲解,那首先呢,我们先来看一段代码,先看一个思考题。各位,嗯,这里呢,这一段代码大家先思考一下它会输出什么。它会输出什么来?我们一起来看一下这段代码。首先呢,我对不对,定义了一个person结构体变量,然后我给他附了一个age这个字段,给了一个10NAME这个字段,给了一个小名,然后我把P1交给了P2。
01:02
对不对?这一点大家回忆一下,当我们这句话执行的时候,在内存里面会出现一个什么情况。是不是默认会有一个P2。还有一个PEPE会指向一个数据空间,对不对,这个空间里边将会有有名字,就PE1原先指向了一个数据空间,里边有小名。还有一个年龄是多少呀,十岁,当我们把P1交给P2的时候,进行一个只拷贝,因为我们知道结构体这种数据类型呢,默认它是只拷贝的,因此P2呢,也会有一个数据空间,是不是P2指向自己的空间O了,这时它会把小明还有年龄也拷贝过去,在内存里面是不是这样子的,紧接着呢,在这里我输出了p2.h,请问这这时输出什么内容?显然他输出的这个年龄呢,就应该是十。
02:01
没问题吧,紧接着我把这个P,我通过P2这个结构体变量访问到它的属性name,将小名改成汤姆,也就是说我把这个小名改成汤姆了。改成汤姆了,那这里呢,这个地方修改汤姆会不会影响到P。是不是不会,其实这个这个知识点和它的特点呢,在前面我们已然给大家讲过了,是不是,那这个时候他让我们输出p2.name和p1.name分别是多少,同学们想是不是应是不是这个时候这个地方P2的name就应该是汤姆。没问题吧,这是汤姆,而P这个,他的名字呢,仍然是小明。对对不对,所以说最后这个结果就应该是汤姆和小明。这段代码其实没有新鲜的东西,跟前面讲过的一致,因此呢,这里老师把它简单的说一下就可以了,这个这个就过了啊,就是相当于说把前面讲的一个知识点呢,又做了一个回顾是吧?好,我先把这一块呢给大家整理到我们的笔记里边去。
03:16
好来走到这来,那这里呢,仍然是讲的结构体来往下走。对吧,结构体的内容它比较多嘛,OK,来我们又把这个做了一个说明,这叫结构structure类型的内存分布分配机制。给他来一个标题三。给他来一个标题三,OK,那刚才呢,我们已然把这个做了分析,OK,好,我把这块呢,给大家放到笔里边去,没问题吧。诶,没问题。应该还是比较简单哦。我把它放到这儿。好把它放到这里,过后呢,我们把它整理一下。好,这地方我们说先看一个思考题,看。
04:02
一个思考题。对吧,看一个思考题,好把它板述一下。没问题吧,这个很简单,那这里呢,它输出的输出的结果大家大家应该是可以知道的,对吧,就是跟我们刚才分析的,我说一下输出结果。输出的结果。结果是什么呀,汤P2。p2.0。P2点内。等于多少呢?p2.m等于汤姆,而p1.m呢?仍然是原先这个值什么呀,小明。对吧。这是输出结果的一个说明,那这块说完了过后呢,我们接着往下看,接着往下看。那那刚才我们讲过哈,Structure它的基本说明,我们说变量总是在内存中的,这句话没有说错,也就是说我们一段代码,它在运行的过程中,所有的变量都会被加载到内存才能去运行,这个是一个。
05:06
程序运行的基本的原则和规则,这个没什么可说的。那么结构体变量在内存中究竟以怎样怎样的一个形式存在?我在前面是实际上是画了一个图的,因为它是直类型,所以说那个图我们当时在前面已经画过,对吧,但是呢,在这里呢,我们再把它说一下啊,就是说这个图呢,我们也把它重新整理一下,到这来好基本说明整理一下。OK,好。放这儿来,它的一个基本说明。走到这里。嗯,它的它的这个内存图,我们先把这个笔记整理一下它的基本说明。对应的图呢,我这已经给他画好了,把它拿过来就行,好吧,我把它拿过来就行。好,这个位置代码我把它,呃,这个地方的内容我把它放过来。没问题吧,还是比较简单,那它对应的图是什么呢?我们来看一下在这里。
06:05
对,前面这个代码的一个内存图,我们把它拿过来,就这样子的。比如说刚才我们写的两个人,一个是小明,一个是汤姆,他的内存的布局就这样子的。当我们把一个P1交给P2的时候,它会进行一个只拷贝,他们之间的数据空间是完全独立的。这在前面这个知识点已然讲过了,好,我把这里呢,再给大家整理到这里,没问题吧。那有些同学老师,你这些不都是讲过的吗?为什么还要讲一次呢?原因是下面会有新的内容。好,这是示意图啊,就是我们结构体,结构体在内存中的。内存中的示意图。我把它整理到这。欧了。这些其实并不新鲜,下面的内容呢,就是我们新的东西了,来看。我们来看一段新的代码,我们来看新的一段代码,同学们看一下这段代码会输出什么信息。
07:07
看下面代码并分析原因,来跟着老师一起做一做。第一个,首先我创建了一个P这个结构体变量,然后给它附了一个值年龄名字,然后我做了这样一个动作,大家看到。我把P。我把P1这一个变量的地址交给了P2,注意是负的地址了,而这边P2是一个结构体指针,看到没有?是不是这样子的,然后呢,我在这里输出了这个age。我用了一个取值符,把这个H取出来,好,请问这个地方应该输出什么内容?是不是就是这个十没问题吧,肯定是等于十的,然后呢。我把这个P2的年龄也进行一个输出。
08:00
各位,这个P2是一个指针。它指向了原,指向了原先这个P,那所以说这个地方的年龄请问是多少是不是。啊,是不是也是十,因为我们讲过就是这种,上面这种写法和下面这种写法在勾浪里面都支持,因此这个地方也是十没有问题吧。然后呢,我通过P2去修改这个。名字我把它改成了汤姆,好,这个不用说,紧接着我做了一个动作,我要求输出P2NAME和P这个name,请问这个时候会输出什么类,谢谢。注意,这个时候已经是指针了,我既然是指针,所以说P2点内和P一点内它们应该是同一个值,是什么呢?他们都应该是汤姆。波浪号。下面这个也是汤姆布兰号对不对?是这样子的吧,然后呢,我这里又输出。
09:01
这个地方我又做了一个动作,大家看这里,我用心。新点P2,新点P2其实。就等于PPP2点内对不对,然后这有P一点内,其实这个仍然是汤姆对不对,它仍然是汤姆兰号,后面这个呢,也是汤姆波浪号,没问题吧。肯定是这样输出的,好,我们来试一下,是不是跟老师分析的一样,我们把这段代码呢,放到我们的笔记里面来,我们试一下来写一段测试程序。我们写段测试程序,新建一个文件夹,Exercise。CIC。Xer CC,好,我们写一段测试代码,我们来看看跟老师刚才分析的是不是一样的,然后再画出对应的内存图就可以了。好,我把它粘过来了。然后我们这先打一个包包,Package me,没问题吧,然后import。
10:01
我们把format这个包引入。然后新建一个主函数。包起来执行。好在这里。我们刚才已经分析过了啊,同学们,这段代码,尤其是这个地方到底发生什么了,这里是个关键,这里是关键,待会儿呢,我们会发出,我们会画一个示意图,会画出示意图,等会再画,我们先看结果。刚才老师说了,这个地方输出的内容应该是汤姆。一个波浪号,然后呢,后面这个仍然是汤姆波浪号,下面这个一样的道理,只是我这里出这个题的目的呢,就是让大家知道P2点内和新P2括起来,点内其实是一个意思。是不是前面讲过这种写法,然后呢,这也是汤姆布号,然后是汤姆布兰号,OK,好,我们来运行一把。
11:01
我们来运行一把。我们先看看这个效果是什么样子的啊,我听一下。我清一下,然后我们来进入到这边有代码有问题,我们看哪里有问题看这。他说这个person没定义好,没关系,我们加一个结构体就行了,Type。好,Person。对不对,哎,这写错了,写反了。Person。然后给他一个字段叫name是,然后呢有个edge int,好,这样呢他就不会报错了。我们来运行一下。进入到刚才我们写的CHAPTER10。然后CD到刚才的exercise go run main.go跑起来,我们发现呢,的的的确确输出内容跟我们想的是一样的,大家看这里。是不是?汤姆汤姆汤姆汤姆对吧,没问题,好,这个结果确确实实是OK的,但是呢,我想通过这个题来讲解的,主要是讲这个东西它到底在内存里面是怎么存在的。
12:11
好,同学们,跟着老师思路,我们来打开Excel表,我们来画一下内存它是怎么布局的。就是针对这段代码,我们说一下它是内存怎么布局的。来吧。我们把这段核心的代码。先放在我们的Excel表里面去。OK。放好,然后呢,我们画一个内存图。我们画一个内存,内存图来到这里。好,我们一起来动脑筋,看看这个地方应该怎么画啊,走一个。当我们的代码从这里开始执行的时候,首先执行到这里。第一句话。他呢,创建了一个P。创建一个P,因此在我们的内存里边。
13:00
P1这个变量对吧,它就会分配一个空间,所以说在这个时候P有了,那P它会指向一个空间来,把这个空间呢,也给大家画出来。注意听啊,同学们这儿还是比较关键的。这是比较关键的,好PE,那PE里面有几个,有几个这个字段呢?有两个字段,好的,既然有两个字段,我就把它画出来。一个字段。那么这里有一个字段是name,所以说我把这个name呢也写出来。注意听啊,这块还是很关键,这是name。然后呢,还有一个字段是age。这个没问题吧,大家应该能分析出来,还有个是age。Your name your age。Name呢,它这个值会给成一个小名,好我们先写一个小名,然后呢,它这有个年龄对吧,它这有一个年龄,好我把这个年龄呢,诶这个地方还不行,对吧,我拉到下面来,诶这个。
14:03
走到这再复制他的年龄是多少呢?是十岁,这个没有问题,这这都是OK的,然后呢,P1它就指向了这个空间,好,我们把它画一下。诶,我们这段用个用一个曲线画吧,好,曲线画出来好看一点。用个曲线。好让P指向这个位置,这个大家是不是也也能看清楚。好,指向它完了过后呢,下面代码接着走,关键是这句话,这时我们把P的地址交给了一个指针P2,那这时它会在内存里面怎么存在呢?同学们注意听,这是关键啊,他这样走的。这时它会有一个新的一个P2。P2它会指向一个什么呢?它它已经是个指针类型了,它既然是一个指针类型,同学们想哈,既然是一个指针类型,它就会指向一个空间,但这个空间里面存的是什么呢?这个空间里面存的是这个地址,就是P1这个结构体的地址,那P这个结构体的地址是多少呢?我们打出来看一下。
15:11
好,我们来看看form.print f。PTF注意听我们打出PE的地址,是我们把它地址输出来P,大家跟上思路。那么怎么把这个P的地址取出来,就就这样去就可以了,好,我们把它输出来给大家看一眼。看一下PE的地址。P的地址其实就是它。能理解好,那如果我要我要画出这个完整的示意图的话,那就意味着。在他这里面。会有一个地址存进去,这个地址会指向哪里呢?各位同学,这个地址它会指向。这个上面。P1的这个结构体。他这个地址是他。
16:00
那也就是说这时会出现这么一个情况,就是我们的这个结构体里面有个地址啊,我们这个指针它指向了它。好,我我发到上面去吧,好吧,大家看这个这个能看懂吧,这样子。我指向他了。能看懂啊,也也不是很难。对吧,它指向了我,我上面拿一点吧。这个哎呀,换成不同的线吧,这个换成不同的线好吧,它也指向了这个空间。当然了,有同学说有,有同学说老师,那P2它本身有没有地址呢?肯定也有,它是一个指针。它既然是一个指针,所以说它本身也会有一个地址,就P2本身也有一个地址,那P2本身的地址我们是不是也可以看出来呢?我们来看一下,就是我们这个图,老师画的这个图正不正确,我们还可以证明一下。我可以把P2它本身里面的值输出来,并且把P2本身的地址也给大家画写出来,大家看我这为了深深入一点,我们直接这样写print f。
17:07
我们说P2。的地址。他本身是不是也有个地址啊,他的地址呢,我也把它输出来。P2本身地址,那就P2地址,同时P2它有一个值,P2的值是多少呢?好,P2的值是不是也是个指针,说这样也说诶这个地方写错了,P2的值,那我们看看。这两个对不对,就是说这个地方我输出P2地址,同时呢,我把P2的值也输出来了,P2的值是一个是一个指针,那就意味着它输出的这个这个值应该刚好就等于P2的地址才对。能理解这意思吧,我们看看是不是跟老师分析的一模一样,走一个我们看效果。我们可以看到同学们,诶,这个方我们来一个换行,如果不换行的话呢,呃,不太好看。好,我把这两个地方都做一个换行的处理,走一个看效果。
18:03
那注意看这里,我们发现。P1的地址是他。没问题吧。同时我们发现。P2的值,哎,你们有没有发现P2的值刚好就等于这个东西。是不是证明了P2这个指针,它存放的地址的的确确就指向P1,当然P2本身也有个地址。那P2本身这个地址实际上是指的哪里呢?同学们动脑筋,P2本身的地址其实就是这个位置。这个地方要看懂了。这样子理解就比较透彻了,我把它放到这里来。那也就是说我们P2它是一个指针,大家看这个关系已经出来了。P2,四的指针,它指向了这个空间。对吧,这个空间里面存放了一个地址。这个粒子指向谁呢?指向P这个结构体。
19:02
数据空间。没问题吧?你看这样形成这么一种引用关系,也就说P2它的这个地址指向了P1这个结构体的数据空间。那既然这个关系一旦成立好,下面的代码就特别的好理解了,那这两句话不说了,通过取出这个新P2,这个就是相当于说通过这个地址。去去找到了他这个数据空间。这这就前面讲过是吧,再找到这个age。打印出小名,同样p2.age这个这句话之所以可以这么用,前面老师讲过,这是go的设计者做了一个简化处理,其实标准的写法应该是上面这个写法,对吧?但是呢,Go设计者为了大家使用方便,他也支持P2这个指针,直接去访问它的字段。好,紧接着呢,他做了一个P2点,Name等于汤姆,好,同学们想一想,P2点内其实是通过这个指针,它通过这个地址找到了它指向的数据空间,然后找到这里面有个字段叫name,找到一个name过后呢,他把这里面的这个值改成了汤姆。
20:13
大家想一想,你通过P2去改变这个东西,显然P1也就发生变化了,这个从数据空间可以看出,因为他们是共享一份数据空间,所以说当下面你用P2点内或者p1.m去访问名字的时候,其实都是汤姆。同样的道理,你用新P2括起来的内去访问这个,这个名字和P点内也是汤姆,所以说这个最后这个结果就生不出来的。这个图特别重要,好吧,一定要把这个图理解到位,这个图理解到位了,当然下面怎么输出,为什么输出这些大家就非常清晰了,是吧?好,同学们,那么我把这个图的分析就给大家说到这里,好,我把代码呢给大家整理到这里哈,整理到这里。
21:04
这里我们讲的是看下面一段代码,并分析原因,原因就是刚才画的那个图,那个图是非常有指导意义的。好,我把这段代码呢,先给同学们整理过来。是吧?OK。把这段代码给同学们整理到我们的笔记里边去。最后输出的内容。走一个。好输出的结果啊,输出输出的这个结果是。什么,我把它放放过来。啊,我把它放过来,干脆这样子啊,为了让让大家把把这块,因为我这个代码里面还有输出地址的,那干脆我就截上面这段代码比较好一点,对吧,这个我就先要不要就先去掉了,我把这一段代码。把这段代码给大家整理到我们的笔记里边去更好一点。对吧,更好一点,OK。好,最后这边输出的内容是这两个。
22:02
汤姆。汤姆。波浪号对不对,好把它整理一下。好,放好。没问题吧,这个。那么在这个地方输出的结果是什么呢?输出的结果是这个内容。我也把它挤过来。我们输出的结果是这一部分。对吧,然后我们。我们画出了内存图,对下对它进行的分析,好上面代码。上面代码对应的这个内存图的分析。也做了一个分析,我把这个内存图呢给大家拿到笔记里边去哪一块,是不是就这一块啊。就这一块,OK。就这一块,好,我先把它整理到这里来,没问题吧,好,同学们,那关于就是当我们需要需要去通过一个变量去修改另外一个结构体的。
23:03
内容的时候呢,咱们可以通过传地址的方式来达到这个效果,原因刚才老师也说了,好,我们接着呢再来看下面两个题。再看一个题,大家看这里,同学们看这里啊,看下面的代码,并分析原因,大家看这,他说有一个。有一个结构体变量是P1,并且呢,给他两个字段赋了值了,然后我把P1这个地址交给了谁,交给了P2这个指针。然后呢,他就问他说能不能这样用。这是一个指针,他说新七二.h能能这样用吗?大家问。问,你能不能这样用?大家想一想,这样用行不行?啊,它跟原先我们写法唯一的区别就是没有用括号,大家看原先的写法是把它包起来的。翅膀,心。
24:00
这星期二是包起来的,用一个括号包起来,现在呢他没有包,请问这样用能行吗?这样用我我先跟大家说啊,这样用肯定是不对的。为什么说不对呢?因为大家知道点的运算集。点的这个运算级要高。对吧,所以他先会执行p2.h,这个是没问题的,但是你做完了过后,你又取了一个新取值符,所以说这个就错了。为什么这么讲,大家看打开我们的笔记,我们笔记呢,在第几章专门讲过这个事啊,我们在讲运算符的时候,提到了一个运算符的优先级,打开大家看这里,我们这讲到点儿的运算级别是非常高的,它比这个星。就是比这个取值运算符要高,因此在进行这个代码执行的时候,他先取他先执行这个点的操作,然后再执行这个新的操作,那这样子的话,代码肯定是有是有问题的,对吧,为什么有问题,你想他先点了,然后再新,它本身这方已经取出来一个具体的值了,结果对一个具体的值再去做一个信号处理,肯定是要报错的。
25:12
所以说不能这样写结果是错的,我们把这个结论说出来啊,不能这样写代码会报错。不能这样写。啊,汇报错误,汇报错误。那么原因是为什么呢?我把这个也说说明一下,原因是。原因是什么呢?点的运算级优先级,点的运算符优先级优先。优先级比什么呢?比这个星高,星号高,取值符高。好好,所以说这样子就会错,但如果说真的真的是这个新的运算符级别高,那你这样写就没问题,因为他先把这个P2指针进行一个取值,再点H,这个是可以的,但但问题是人家这个点的点的这个运算级,运算符的优先级要比新高,所以说你就不能这么去写明白吧,一定要用括号包起。
26:09
一定要用括号包起来才行。好,那关于这段代码的分析呢,老师也把它整理到笔记里面进行一个板书。好,这里我们说到这儿啊。我把这段代码整理到咱们的笔记里边去。结论已经有了,不能这么写,原因我也做了分析。就这这句话。对吧,我在这做了一个梳理。以后以后在这个面试的时候,如果有人这么问你,或者说你在写代码的时候,千万不要这么去写好不好,一定要括起来,你括起来就行,要么你就直接把这个信号拿掉也可以。好,我把这块放到这里欧了。好了同学们,那关于我们这个结构体类型在内存分配的机制呢,我们就讲解到这里,相当于说在原先基础上呢,做了一个系统和一个深深入的一个再分析,希望同学们把这块内存分配机制把它搞清楚,搞明白好吧,OK,那这块我们就先给大家介绍到这里。
我来说两句