C语言 day11
动态内存申请
- 动态内存申请的相关概念
- 静态分配和动态分配
- 动态内存申请相关函数
- 内存泄漏
动态内存申请的相关概念
- 在数组一章中,介绍过数组的长度是预先定义好的,在整个程序中固定不变
- 但是在实际的编程中,往往会发生这种情况,即所需的内存空间取决于实际输入的数据,而无法预先确定
- 为了解决上诉问题,C语言提供了一些内存管理函数,这些内存管理函数可以按需要动态的分配内存空间,也可以把不在使用的空间回收再次利用
静态分配和动态分配
静态分配
- 在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式
- 必须事先知道所需空间的大小
- 分配在栈区或全局变量区,一般以数组形式
- 按计划分配
动态分配
- 在程序运行过程中,根据需要大小自由分配所需空间
- 按需分配
- 分配在堆区,一般使用特定的函数进行分配
动态内存申请相关函数
1、分配内存空间的函数 malloc
头文件:
#include<stdlib.h>
函数原型:void *malloc(unsigned int num_bytes); ——> (返回值void *)
调用形式:(类型说明符) malloc (size); ——> (类型说明符)进行强制类型转换
功能说明:
- 在内存的动态储存区(堆区)中分配一块长度为size字节的连续区域用来存放类型说明符指定的类型
- 函数原型返回
void*
指针,使用时必须做相应的强制类型转换 - 分配的内存空间内容不确定,一般使用
menset
初始化
返回值:
- 分配空间的起始地址(分配成功)
- NULL(分配失败)
注意:
- 在调用malloc之后,一定要判断一下,是否申请内存成功
- 如果多次malloc申请内存,每次申请的内存之间不一定是连续的,但是每个内存内部肯定是连续的
2、free函数(释放内存函数)
- 头文件:
#include<stdlib.h>
- 函数定义:
void free(void *ptr);
- 函数说明:
free
函数释放ptr
指向的内存 - 注意:ptr指向的内存必须是
malloc calloc relloc
动态申请的内存,只能释放堆区空间
案例1:申请一个int变量的空间
1 |
|
运行结果:
案例2:从堆区申请一个int数组,数组大小由用户决定
1 |
|
运行结果:
3、calloc函数
- 头文件:
#include<stdlib.h>
- 函数原型:
void * calloc(size_t nmenb,size_t size);
- 功能说明:在内存的堆中,申请
nmemb
块。每块大小为size
个字节的连续区域 - 函数参数:
size_t
实际是无符号整型,它是在头文件中,用typedef
定义出来的 - 返回值:
- 成功:返回申请的内存的首地址
- 失败 返回
NULL
- 例如:char *p = (char *)calloc(3,100)
- 特点:calloc函数申请的内存中的内容为0,自动清零;而malloc申请的内存中的内容随机的,不确定的
案例3:案例2改造
1 |
|
运行结果:
4、realloc函数
动态追加或减少空间
- 头文件:
#include<stdlib.h>
- 函数原型:
void * realloc(void *s,unsigned int newsize);
- 功能说明:在原先s指向的内存基础上重新申请内存,新的内存大小为new_sizeof个字节(包含原先的内存大小!!),如果原先内存后面有足够大的空间,就追加,返回的内存地址还是跟原先的一样的;如果后面的内存不够用,则realloc函数会在堆区找一个new_size个字节的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新的内存地址
- 函数参数:
size_t
实际是无符号整型,它是在头文件中,用typedef
定义出来的 - 返回值:新申请的内存的首地址
案例4:改造案例3
1 |
|
运行结果:
- 增加元素
- 减少元素
堆区空间使用的注意事项
指向堆区空间的指向变量,不要随意的更改指向,会造成堆区空间无法释放,造成内存泄漏
不要操作已经释放了的空间,内容是不确定的
不要对堆区空间重复释放.运行时,程序会直接终止
防止多次释放的方法(坚持使用这种方式)
1 | int *p = (int *)calloc(1,sizeof(int)); |
内存泄漏
内存泄漏(Memory Leak)是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果。