内存管理
程序是静态的,进程是动态的
进程空间图示
栈内存
一般局部变量,函数会放在保存在栈中
特点:
栈内存分配是从地址大的开始分配
栈内存存储的数据会自动释放
栈的内存大小有限,所以特别注意在使用递归时,栈溢出的问题
堆内存
基本概念
堆内存可以存放任意类型的数据,但是需要自己申请和释放
堆大小,想象中是无限大的,但是实际使用,受限于实际内存大小和内存是否连续
malloc函数
#include
#include
#include
int main()
{
/*
* malloc作用:
* 在堆内存中申请一块我们指定长度的空间
* 格式:
* 接收一个参数,用于指定需要申请空间的长度
* 会返回一个 void * , 这个是万能指针,可以转化为任意类型的指针,会将
* 申请好的内存地址放到void *中返回给我们
* void * malloc(size_t _Size);
*
* 注意点:
* 1.使用malloc函数的时候必须导入头文件 #include
* 2.通过malloc函数申请的空间默认存储的是垃圾数据,系统不会帮我们初始化
* 所以malloc一般都会和memset函数结合使用
* 3.free()函数可以手动释放申请的存储空间,传入的参数是要释放地址
*/
/*
(int*)是强制类型转换,malloc函数返回的是void*,而我们开辟的是4个字节,正好是int类型,所以最好将void*转换为int*,因为只有指针类型是int类型将来操作这块内存的时候,才知道操作多少个字节
*/
// int *num = (int *)malloc(sizeof(int)); //在堆中开辟4个字节的存储空间
// *num = 777;
// printf("%i\n", *num);
int *p = (int *)malloc(3 * sizeof(int)); //开辟12字节的存储空间
p[0] = 1;
p[1] = 3;
p[2] = 5;
memset(p, 0, 3 * sizeof(int)); //初始化p对应的内存空间为0
for(int i = 0; i< 3; i++){
printf("p[%i] = %i\n",i, p[i] );
}
// free函数只传入了存储地址,系统是如何知道应该释放多少个字节的存储空间的
// 在利用malloc分配地址的时候,系统就偷偷保存了该指针对应的内存大小
free(p); //释放存储空间
return 0;
}
memset函数
memset函数作用:
专门用于初始化一块内存空间,使用必须导入头文件 #include
可以传入三个参数
第一个参数: 传入需要初始化内存地址
第二个参数: 传入需要初始化的值
第三个参数: 传入需要初始化长度多少个字节
memset(p, 0, 3 * sizeof(int)); //初始化p对应的内存空间为0
calloc函数
注意: 使用时也需要引用#include
#include
#include
int main()
{
/*
* calloc函数: 就是对malloc函数的封装,一般用于开辟数组的存储空间
*/
// 告诉操作系统,需要开辟3块存储空间,每块占4个字节
int *p = (int *)calloc(3,sizeof(int));
p[0] = 1;
p[1] = 2;
p[2] = 3;
printf("%i\n", p[0]);
printf("%i\n", p[1]);
printf("%i\n", p[2]);
free(p);
return 0;
}
realloc函数
#include
#include
int main()
{
/*
* realloc : 用于给内存扩容和缩容
* 例如: 我们利用malloc分配4个字节的空间, 但是觉得不够用想增加,这时候使用
* relloc函数,或者想减少分配的存储空间
* 传递两个参数: 第一个参数是要扩容地址,第二个参数是扩容后内存的大小
*
* 注意点:
* 利用malloc函数分配存储空间,必须是连续的,也就是在堆内存中分配内存空间
* 必须是连续的,如果利用realloc函数进行扩容时候,后面没有连续的内存,那么系统
* 会分配一块新内存
*/
int *p1 = (int *)malloc(sizeof(int));
// 给存储空间扩容
int *p2 = (int *)realloc(p1, sizeof(int) *2);
return 0;
}