欢迎光临
我们一直在努力

动态内存管理(1)

1.为什么要有动态内存分配

我们已经掌握的内存开辟方式有:

但是上述的开辟空间的方式有两个特点:

 ·  空间开辟大小是固定的

 ·  数组空间一旦确定了大小不能调整

但是有时候我们需要的空间大小在程序运行的时候才能知道,那么上述两种方式便不能满足我们的需求了。

而动态内存开辟让我们可以自己申请和释放空间,就比较灵活了

2.malloc和free

malloc和free都声明在stdlib.h头文件中。

2.1malloc

函数原型:void* malloc(size_t size);

功能:向内存的堆区申请一块连续可用的空间,并且返回这块空间的起始地址。

参数:

size :要分配的内存块的字节数

返回值:

 · 如果开辟成功,则返回这块空间的起始地址。

 · 开辟失败,返回NULL,因此malloc的返回值一定要做检查。

 · 返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候由使用者自己来决定。

 · 如果参数size为0,malloc的行为标准是未定义的,取决于编译器。

2.2free

函数原型:void* free(void*ptr)

功能:释放之前通过动态内存分配函数申请的空间

参数:

ptr:指向要释放的内存块的指针

 · 如果参数ptr指向的内存不是动态开辟的,那free函数的行为是未定义的

 · 如果ptr是NULL指针,则函数什么事都不做

但是注意:

free只是把使用权限还给操作系统,但p中还保存着这个地址,所以必须要置空,避免后续变成野指针。

3.calloc和realloc

3.1calloc

函数原型:void* calloc(size_t num,size_t size)

功能:为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。

与malloc的区别:calloc会在返回地址之前把申请的空间的每个字节初始化为全0。

3.2realloc

函数原型:void* realloc(void* ptr,size_t size)

功能:可以调整动态开辟内存的大小。

参数:

ptr:要调整的内存地址

 size :调整之后的新大小,单位是字节

返回值:

 · 成功:返回一个重新分配内存块的void*类型的指针,这个指针可能跟原来的指针不同。

 · 失败:返回NULL,并且原来的内存块保持不变

注意:

 · 返回值为调整之后的内存起始位置

 · 这个函数会在调整原内存空间大小的基础上,将原来内存中的数据移动到新的空间。

 · realloc在调整内存空间时存在两种情况:

情况1:原有空间之后有足够大的空间,最终返回的地址还是旧地址

情况2:原有空间之后没有足够大的空间,会在内存堆区寻找新的满足要求的空间,返回新空间的起始地址,在这个过程中会发生:

 · 寻找新的满足要求的空间

 · 将旧空间的数据拷贝到新空间,保证数据不会丢失

 · 释放旧空间,返回新空间的起始地址

情况3:分配失败,返回NULL。

所以注意下面的写法中用p去接收realloc的返回值就是有问题的,万一分配失败,p被置空,前面二十个字节的数据也就丢失了

4.常见的动态内存的错误

4.1对NULL指针的解引用操作

  不做判断直接使用,malloc如果返回失败,那么就会出现对NULL的解引用操作。

4.2对动态开辟空间的越界访问

动态开辟的空间,也是有自己的内存边界的,不能越界访问。

4.3对非动态开辟的内存使用free释放

如下图,如果错误的对arr这个静态内存释放会报错

4.4使用free释放一块动态开辟内存的一部分

上述代码中的p++会使p不再指向动态内存的起始位置,所以最后的free只是释放了一部分的p,运行时也会报错。

4.5对同一块动态内存多次释放

4.6动态开辟内存忘记释放(内存泄漏)

赞(0)
未经允许不得转载:171主机测评 » 动态内存管理(1)
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址