C语言学习之动态内存分配的四个函数
前面中我们了解到:
int n;
int arr[n];
这样定义数组是不可取的,不能用此方法给数组分配动态内存,那怎么样才能实现这种可能呢?
接下来我将关于动态内存的知识做以下总结。
有关动态内存的函数有四个,分别是malloc( )、calloc( )、free( )、realloc( )。ansi(美国国家标准协会)标准建议应添加头文件#include ,但许多c编译要求用#include 头文件,在使用时应注意。
ansi标准要求动态分配系统返回void指针。void指针具有一般性,它们可以指向任何类型的数据。所以有时需要用到强制类型转换的方法把void指针转化为所需的类型。
一、动态内存函数
(一)malloc函数
功能:申请动态内存,分配size字节的存储区
所需参数:一个参数size,表示所分配的字节
形如:int *p = (int *)malloc(n*sizeof(int));
返回值:所分配的内存区起始地址,如内存不够,返回0
(二)calloc函数
功能:分配n个数据项的内存连续空间,每个数据项的大小为size
所需参数:两个参数
形如:int *p = (int *)calloc(n,sizeof(int));
用malloc函数表示如下:
int main()
{
int n = 10;
/* int *p = (int *)malloc(n*sizeof(int));
for(int i=0;i<10;i++)
{
p[i] = 0;
} */ //等同calloc
//int *p = (int *)calloc(n,sizeof(int));//0
返回值:分配内存单元的起始地址,如不成功,返回0
malloc函数与calloc函数的区别:
malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0。
(三)free函数
功能:释放p所指的内存区
所需参数:一个参数
形如:free(p); // 释放内存,与malloc配合使用
返回值:无
(四)realloc函数
功能:将p所指出的已分配内存区的大小改为size,size可以比原来分配的空间大,即扩容
所需参数:两个参数,新的大小,以字节为单位
int n = 10;
int *p = (int *)malloc(n*sizeof(int));
int i;
for(i=0;i<10;i++) //模拟p已经被使用
{
p[i] = i*i + i;
}
将以上10 个内存扩大为20个内存,如下:
int n = 20;
int *q = (int *)malloc(20*sizeof(int));
for(i=0;i<10;i++)
{
q[i] = p[i];
}
free(p);
p = q;
q = null; // 把q注销掉,若无此句,则崩溃
//上面的代码等同于realloc
等同于:p = (int *)realloc(p,80);
一般情况下,操作系统会忽略缩小内存的要求,操作系统会缓存刚刚保存的数据,提高代码的利用率和运行速度。
动态内存存储里,不讨论堆中谁的内存大谁的内处小,不能确定地址的大小规律,有存储空间就有可能保存新数据。
二、free( )崩溃的原因
动态里每个块前有个头,每个块后有个尾。(边界标识法)
头:开启
尾:合并(胶水的作用),可以把小块拼成大块
1、越界(修改了尾信息)
2、指针移动(如*p = 0;p++)
3、重复释放(free至少两次)
4、释放栈内存(数组不能释放,堆却可以,栈内存操作系统会自动回收)
四、堆与栈的区别:
栈:一使用就会释放内存,1m
堆:申请的内存大,但不会主动释放,容易发生内存泄漏。
1.栈内存存储的是局部变量而堆内存存储的是实体;
2.栈内存的更新速度要快于堆内存,因为局部变量的生命周期很短;
3.栈内存存放的变量生命周期一旦结束就会被释放,而堆内存存放的实体会被垃圾回收机制不定时的回收。
五、动态内存最严重的问题就是:内存泄漏,还有数组越界。