关于数组和指针的分析

指明了类型,就指明了操作

特征:

  • 相同类型
  • 连续存储

可以按下标访问,也可以按地址访问。C++是基于实现的
C++中的二维数组是复合类型,没有Array。
数据类型决定范围和取值方式,什么样的类型定义了什么样的访问方式
int len = sizeof(arr)/sizeof(arr[0])

1
2
3
4
5
6
7
8
9
10
int a[6];
f(a) //在参数传递时,发生了变化,变成了表达式,由一个数组变成了相关的指针
// a是数组类型,只不过进行了隐式类型转换
// 所有的指针的sizeof(*p) 都是一样的
void f(int a[]){
for(int i = 0;i<sizeof(a)/sizeof(a[0]);i++){
// 所以此时不能输出a中的每一个元素
}
// 因此,元素个数需要通过参数显式给出
}

C++是允许数组下标越界的,因为越界是有用的前提是空间是合理的

1
2
3
4
void f (char[] a ){
while (a[i+ 1] !='/0'){
}
}

image.png**
所以
输出s2时,会一直输出下去**,直到刚好碰到'\0'
没有初始化的空间全部默认为 0xcc,代表中文的烫
利用malloc时不初始化,空间会默认为0xcd,代表中文的屯。【debug版本中打开/GZ开关,方便找到潜在的错误 = 》现在使用/RTC1】
C++中的变量是不会自己初始化的
mallopt指定自己配置的空间是什么【写在代码中的】
valgrind设置栈、堆里面的填充【不修改代码】

指针

指针必须初始化,防止调用垃圾地址并修改了其中的内容
image.png
image.png

void*

void *v*v是不被运行的。所以**v**可以作为任何类型指针的公共接口,只具有记录地址的作用,是可以被信任的。任何指针都可以赋值给**void ***,但void * 不能赋值给其他指针
清零
int a[100] 全部赋值为0

  1. for循环
  2. memset函数(起始地址,大小) 则起始地址必须为**void ***
    1
    2
    3
    4
    5
    6
    void memset(void *p,int  n){
    char *q = (char *)p; // 进行强制类型转换为char *,一个一个字节的删除即可
    for(int i=0;i<n;i++){
    *(q+i) = 0;
    }
    }

数组与指针

image.png
a 是一个常量指针,数组名是常量指针

  1. 通过数组下标访问
  2. 通过指针访问
  3. 通过数组名访问

动态数组
int *p =(int*) malloc (……)

多维数组

通过一维数组不断复合,依然是一段连续的数据。
参数传递:缺少第一维,因为对应的就是指针,指向后面的维度

1
2
3
typedef int T[2]; // 
using T = int[2];
int a[3][2] <=> T a[3]; 相当于额外定义了基类型

升维操作:动态多维数组需要借助一维数组来实现,利用升维操作

降维操作p[i]

image.png

降维操作q[i][j]

image.png
为了能通过q[i][j]的形式表示,则需要q指针指向的是一个小方块,而不是一个具体从存储单元。在这个小方块中,包含若干个的最小存储单元,从而通过j这一坐标找到最小的存储单元
**p+11**其实是越界了,方便用数组的形式访问多维数组

小结

image.png

数组升维降维

降维

image.png

升维

image.png

ragged array

java 中的二维数组不是规整的,可能是锯齿状的,不对等的
image.png

动态变量

1
int *p = mall

在使用new时,会逐个调用constructor,从而实现强制类型转换。OO使得数据进入时能进行部分操作
new malloc 和inline一样,可能会申请不成功,所以需要有效性判定
image.png

异常处理

  1. 可以预见:new可能会失败
  2. 无法避免

可以由系统处理,也可以自定义处理。为了allocate成功,可以自己选择释放一些特定内存,要么停掉,要么交给系统处理,要么自主修改环境

归还

防止内存泄漏

  • 操作符 newdelete
  • 函数 mallocfree
    1
    2
    3
    4
    int  *p1  =new int (8);
    int *p2 = malloc(sizeof(int));
    int *q = new int[8];
    int *q2 = malloc(sizeof(int)*8);
    int *q = new int[8]
    delete q 只调用一个析构函数
    delete [] q 逐个调用析构函数
    free(q)
    如何知道有8个?
  1. 符号表:耗时+会导致表的大小未定,空间不确定
  2. 用空间换取时间:在分配内存时,额外用一个空间**cookie**cookie中存储块的大小

申请的指针不要随意改变,否则容易归还失败。因此使用时要用int *p1 = p;

RAII

compiler会自动调用destructor,确保对象被释放。生命周期结束的时候会自动调用delete,利用析构函数的自动调用防止内存泄漏,确保资源的初始化。
image.png
unique_ptr shared _ptr 解决资源共享或者独享问题

1
2
3
4
5
6
7
8
9
class A{
int i;
int *p;
public :
A(){
i = 1;
p = new int (8);
}
}

A a;
A b =a;
会导致悬挂指针idle point,a 和 b 的生命周期结束不一致。

其他

Sturct

定义数据的顺序会影响到内存的占用,会数据对齐
image.png

Union

image.png
B的存储空间是最大占有的内存,所有的域代表一个公共的空间,里面的内容共享一块存储空间
对于struct

matrix

表示方法1:
image.png
表示方法2:
image.png
两种访问方式:
image.png

数组 — 多态性

image.png
image.png