一维数组、指针的指针、RAII、union、函数指针

# Lecture08 - 数组和指针

image-20221011193356316

# 数组

# 特征

相同类型,连续存储

# 一维数组

<img src="https://quasdo.oss-cn-hangzhou.aliyuncs.com/img/image-20221011193622164.png" alt="image-20221011193622164" style="zoom:25%;" />

函数接口中,数组的长度需要显式的表达。即需要 f (int A [], int n); 其中,n 表示数组的长度。

int a[6];

a 是数组类型。

f (a) 中的 a 是地址,因为在函数中,a 变成了右值,进行了隐式的类型转换。

image-20221011194120299

第二种写法是错误的
栈中未初始化填充 0xCC,对应中文的烫(在 vscode 中)
堆中未初始化填充 0xCSD,对应中文的屯(在 vscode 中)

image-20221011194633177

工具
/ RTC1
mallopt
valgrind ——Valgrind 基于仿真方式对程序进行调试,它先于应用程序获取实际处理器的控制权,并在实际处理器的基础上仿真一个虚拟处理器,并使应用程序运行于这个虚拟处理器之上,从而对应用程序的运行进行监视。

debug 文件中有符号表,release 中没有。

# 指针

image-20221011194756090

pointer literal
指针定义为 null,保护内存。
(void *)0 —— 未定义的 datatype,无法对其做解地址操作。
(void *)可作为任何类型的接口。
double * q;
Int * p;
Void * v;
V = q;
V = p;
但是 q 和 p 不能赋值为 v。

image-20221011194829940

例如:

void memset(void *p, int n){
// 内存清空
char * q = (char )p;
For(int I = 0; i < n; i++)
{
(q+i) = 0;
}
}
Int a[100];
A b;
memset(&a[0], 100
4);
Memset(&b, );
可以传递进 int
类型,也可以传入 A 类型。

# 指针与数组

image-20221011195335516

a 是一个 const,不能用 a++ 的方式改变访问

image-20221011195419924

P [i] 用指针实现动态数组

image-20221011195822103

image-20221011195702881

多维数组

关注不同的定义方式

using T = int [2];

ragged array——java 中并非整齐排列,可以锯齿排列。cpp 中可以自己实现。

image-20221011195308401

image-20221012000657463

关于如何理解取 a00 的地址和取 a0 的地址一样,并且取 q+1 的地址仍然是它自身,我的理解是,编译器识别的它的类型不一样,因此解一个指针的指针仍然是一个指针,也不存在另外存储了一个指针数组来表示。

image-20221011195953872

image-20221011200024133

cpp 是允许数组越界的

image-20221011200038340

在传入参数的时候,先进行升维的操作,在打印地址时,再进行降维的操作。

// 思考为什么地址是这样的
cout << *(a+i)+j << " :" << a[i][j] << "  ";
cout << *(*(a+i)+j)+k << " :"  << a[i][j][k] << "  ";
// 思考如何不另外计数完成每隔四个就打印一次 endl
if ((i*2+j+1)%4 == 0)
      cout << endl;
      
if ((i*6+j*3+k+1)%4 == 0)
      cout << endl;

image-20221011200055610

C
int *p = (int ) malloc(sizeof(int) * 8);
因为 malloc 为 void
,需要定义 int * 来使用。

Cpp
Int *p1= new int;
Int *q1 = new int[8];

用 new 的时候,会强制类型转换,并一个一个调用构造函数进行构造。因为 new 知道新建的类型,但是 malloc 不知道新建的类型,无法进行调用。

image-20221018140518525

delete [] 另外存储 4byte 记录空间的大小(如果是 32 位存储)

int *p = new int[10];
for(int i = 0; i < 10; i++){
	*(p++) = 0;
}
//delete 的时候,无法删除且会造成归还的错误
int * p1 = p;
// 解决方案是另外开一个指针进行遍历

RAII

Resource Acquisition Is Initialization

RAII,也称为 “资源获取就是初始化”,是 c++ 等编程语言常用的管理资源、避免内存泄露的方法。它保证在任何情况下,使用对象时先构造对象,最后析构对象。

compiler 帮助程序员管理资源,防止资源泄露。~auto_ptr ()

类中能够同时使用 operator * 和 operato ->

shared_ptr 的表示方式

image-20221018142936362

image-20221018142519655

struct B sizeof 不是 7,需要对齐

也许是 12,一一对齐

也许是 8【char b; short c; int a】变量的顺序也会影响内存的存放方式

image-20221018143235958

Union 和 Struct 的区别是可以共享存储空间。

对于 Struct,三个赋值都有效;对于 Union 来说,只有最后一个语句有效【共享空间】

image-20221018143001639

image-20221018143334428

原本各开 100 个空间,耗费资源,正好时候 union 的定义【只需要 Line\Rectangle\Ellipse 中的一种】。

但是值存储 Line 或 Rectangle 或 Ellipse 不能知道是哪种,需要 tag,且每个类型都需要 tag,不然 tag 会覆盖掉别的数据。

image-20221018143902650

不止 OO 中存在多态性,cpp 也可以通过 union 实现多态。

image-20221018143952177

image-20221018144156718

Struct Programming 也可以去实现 OO 的功能

OO 实际上是编译器帮助做了一些工作。