当前课程知识点:C/C++:从基础语法到优化策略 > Final Exam > Final exam > 5.4 Managing memory for data
返回《C/C++:从基础语法到优化策略》慕课在线视频课程列表
我们这一部分介绍一下 更多的关于指针 关于内存的一些知识
首先我们再讲一下数据是存在哪里的
第一个就是叫automatic variables 或者我们叫他自动存储
这就是说我们一个函数里面的变量
我们这些变量它存在哪里 其实它是存在一个栈里面
这栈是后进先出的规则
然后这些变量在这个函数里面
函数一旦结束 那么这些变量就全部失效了 就全部结束了
这是我们的一般的普通的变量函数的普通变量存储的位置
那么还有一些变量 比如说全局变量 定义在函数体的外面的这些变量
以及定义在函数内部 但是它是satatic类型的变量
那这些变量它们的生命周期就比较长
所以我们有一个静态存储区 专门来存这样的变量
这是首先再强调一下就是函数里面的静态变量 虽然它的生命周期很长
但是它在函数里面 它的有效作用域只是在函数内部
还有第三部分就是动态存储
动态存储也就是我们用new和delete分配的内存 这叫动态存储
它是new和delete的内存是在堆heap这个区域里面
也有的时候是在free store free store是自由存储区
一般来说malloc申请的是在自由存储区
那么这样申请的内存其实它的生命周期就很长
你不去释放它 它就会一直有效
那么在后面我们再来一个稍微复杂一点点的例子
来让大家去理解这个指针
几种类型组合在一起 大家来理解一下
那么这个例子叫mixedtypes
我们来看这个例子首先 我们定义了一个结构体struct
我们叫event event里面有一个变量 有一个成员
那么就是year 是哪一年 我们用一个整数来表示
当然这里面你还可以去放更多的其他的东西
那么在这个例子里面 我们定义好这个结构体之后
我们可以这样event s01 s02 s03这样来定义三个变量
这三个变量就是三个结构体
那么对第一个结构体里面的这个属性year进行赋值操作1998我们可以这样做
那么第二个结构体我们取个地址
赋给这个event指类型的指针
然后我们可以用这个箭头pa->year去读或者写这个结构体里面的这个成员变量
让我们赋一个1999 那么你再看这个里面
我们定义了一个数组 数组里面有三个元素 每一个元素都是event类型的变量
都是一个event类型的结构体 那么在这儿我们有了三个结构体
前面有三个分别三个不同的变量
那么在这个数组里面 我们又有三个
那么数组里面的第零个呢
我们可以这样trui[0].year
这样的话数组里面的第零个编号为零的这个结构体
里面的这个成员year我们赋个2003
那么我们就可以 如果要打印的话 这个地方
这个数组叫trio或者说什么 那么这里面是一个
这是一个数组 如果数组就是指针
我们前面提过
那么用箭头去取这个成员变量 他取的是哪个呢
其实他就取的编号为零的那个
因为他是指针嘛 他取就取第一个元素 那就是编号为零的这个
我们再来看 我们又定义了一个数组
这个数组它的元素的类型是什么
它的元素的类型是event*
是一个event类型的指针 也就是说这个数组
那么他去存的时候 他每一个元素是一个指针也是占八个字节
然后324个字节分别存这三个指针 因为他们是常数指针 你可以加const
那么这是这个数组 那么数组里面的第一号编号为一的这个元素
是个什么 这个数组里面编号为一的这个元素取出来 它是一个指针
也是一个地址 所以说我要后面加箭头
我后面去加箭头才能取到这个成员变量
那么这个地方我打印出来是应该是多少
前面这个打印出来是2003那么这个打印出来是第编号为一的 那就是02这个1999应该是
那我再继续往下看
我们又把这arp数组存着三个指针的arp数组赋给ppa
那么这个pp两个p就表示指针的指针
pp两个指针的指针 那么它就是一个指针的指针
就是这个数组 是一样
同样的在c++11里面 我们定义了auto类型
所以ppb那我就直接赋给arp付给他
其实这个时候ppb的类型会自动变成跟ppa的类型一样的类型
所以在ppb和ppa他们实际上你可以看成完全一样的东西
那他用起来可以是一样的
比如ppa取内容就是一个地址 然后这个地址这个指针来去取它的成员变量
那这个时候a就对应的是1998 就s01这个结构体
那么ppb加一就是第二个元素那就是这个了 对吧
就这个元素 那么把它取出来1999那我们来看一下这个结果是不是这样
这有个警告 你可以加一个std=c++11 把这个警告没了
那么我们把它运行一下
看下这个结果是不是我们前面讲的这个
然后这个结果大家可以回去就课后仔细去运行一下这个例子
然后仔细思考一下为什么会这样
你要把这边的这些为什么要用点 还是要用箭头前面是用点
把这个想明白了 那么你对指针的理解我相信就会相对比较深入了
有时候一般的问题都难不倒你了
那么最后我们再来讲一下数组
前面我们都是说动态数组的数组 这个它带来的问题是非常容易越界
容易产生各种各样的bug
那么在这个std模板类里面
我们有两个类 一个叫vector一个叫array
这两个类可以在很多时候代替数组的使用 这样用它们会更安全
vector和array他们都是数组 他们有什么不同呢
vector是一个动态的数组
它的长度可以动态变化的 当它不够的时候 它可以自动去增长
不停的你可以不停的往里面insert元素 插入元素
这是他的这个特点 那么array实际上是一个静态的数组 他是std namespace的一个类
那么这里面的元素的个数是固定的
你可以认为它是一个长度为固定长度的数组
那么这两个他有什么不同 一个动态一个静态的
如果从效率方面来讲的话 肯定是静态的效率更高
动态会更灵活 这就是让他们的区别
我们来看一下这个 choices这个例子去看一下
ok这里稍微有一点点长 我们来仔细看
第一个我们定义一个数组叫a1
a1这个是个四个就是有四个元素的数据 每一个里面的类型都是double1.2 2.4 3.6 4.8
这四个数值把它存进去
然后我们从c++98开始我们定义了vector
大家看vector是个类
他的定义是classs std:vector
这边尖括号 double 这叫模板类
后面我会讲这个 知识点在这大家可以记住vector的元素是double类型就行了
vector 尖括号double 这个构成一个整体 构成一个类型
那么这个变量叫a2这样一个变量
a2的实际上就是一个类的实例
那么他初始化参数是4 他初始化就可以创建出四个元素来
那么这四个元素我们就可以0123去把它赋值
分别是1/3 1/5 1/7 1/9
这是a1和a2
那么前面的a2我们讲的是vector 那么
我们再来看一看array array是静态数组
在初始化的时候首先我们定义模板类并double他的元素的类型
第二个是元素的个数 就他个数在一开始的时候就确定了
这个时候a3就是这样 我们也可以采用这种初始化的方式
四个元素传进去 3.14 2.72 1.62 1.41这四个数传进去
a4也同样的定义了之后他并没有出始化
没有初始化怎么办 这种初始化方式a3赋给a4在这大家注意
首先a3 a4不是指针 所以这样赋值不是地址的操作
这个赋值实际上是这个vector对这个运算符进行了重载
他这个赋值真正去做的事情是a3和a4是两个不同的这个对象
然后把a3的内容拷贝到a4里面去
这个需要去看这个等号 就是array的等号是怎么定义的 后面会有讲
那么我们把a3的数据拷贝到a4之后
我们可以把a1第二元素a2 a3 a4他们第二元素都打印出来
然后把他们的地址也都打印出来
就是他们的地址 取地址对吧
打印出来我们看有什么区别
最后讲一个危险的地方
就是a1是个数组 我们a1[-2]索引是-2这种做法是可以做的
是可以做的 他就相当于把a1指针往前挪两个整数
两个浮点数 然后再去取它
实际上在这个例子里面 既然a1的前面没内容
你这样做是不可以的 就是相当于数组越界了
但是你执意去运行它会出来的
那么在这最后一个问题
如果我们对a3 array 这样去操作的话
i等于-4 到正4这样
然后a3去这样会怎么样 array会报错吗
你就越界了吗 这个结果我们来看一看
在这我们可以看到一个警告
警告就说在这个地方
a1[-2[这样做已经超出了这个
其实索引是有问题 但他这边只给的是个warning 不是个error
所以说程序依然运行了 他依然会把指针往前跳
然后去去执行 我们来运行一下我们来看
我先看前面的 a1[2] a2[2] a3[2]这些值都是对的 他们的地址各不相同
a3 a4大家看虽然他们的值相同 但他们的地址是不同的
所以他是把值拷贝过去 而不是把地址复制一下
所以a1[-2] 它是个20.2我们赋了20.2
所以打印数也是20.2没问题 他的地址就是这样 大家可以看
a1[-2]它的地址尾数是40 a1的地址
a2的地址是60
大家可以看在这里面就有差距了 就是正好差了几个double的距离
那么我们来看最后一个例子就是
i从-4 到 4 a3是怎么做的
a3的元素我们再来看一看
a3的元素是3.14 2.72 1.62 1.41那么我们来看
从0到3这些数字没问题 从-4 是3.14 2.72 1.62 1.41我们可以看到
这个顺序跟后面的顺序是一样的
在array里面 你如果索引越界了 那他会轮回回来
轮回回来 所以这样来操作
那么还有个问题 如果array这个里面取编号为4的元素 它的返回值是多少
这个留作一个问题 大家课后思考并试一下
好今天这部分就到这里
-Quiz 1
-Quiz 2
-3.3 Relational expressions (> < ==)
-3.5 Branching statements (if else)
-3.8 break and continue statements
-Quiz 3
-4.4 Structures, Unions and Enumerations
-Quiz 4
-5.3 Allocate memory: C++ style
-Quiz 5
-6.3 Recursion and pointer to functions
-Quiz 6
-Quiz 7
-8.1 C/C++ with ARM development board
-Quiz 8
-9.2 Constructors and destructors
-Quiz 9
-10.1 Operators in cv::Mat in OpenCV
-10.4 Automatic conversions and type casts for classes
-Quiz 10
-11.1 Dynamic memory and classes
-11.2 New and improved String class
-11.3 Using pointers to objects
-Quiz 11
-12.2 Static and dynamic binding
-12.3 Access control: protected
-12.4 Inheritance and dynamic memory allocation
-Quiz 12
-13.1 Constructor and assignment
-13.2 Classes with object members
-Quiz 13
-14.1 CNN for image classification
-Quiz 14
-15.3 RTTI and type cast operators
-Quiz 15
-Final exam