Pixiv:Nardack
在C99之前无法使用变量作为数组的参数,比如
int n = 5;
int a[n] = {0};
n = 6;
这种做法是不被允许的。
假如你有一个字符串固定只有4字节,无法在运行过程中改变长度,在使用strcat、strcopy等操作还是挺局限的。
于是动态内存管理这种操作就出现啦~
目的就是让你能在运行过程中也可以对内存进行管理
这里只会涉及到stdlib库中的四个函数:malloc、free、calloc、realloc
作用:申请分配size个字节的内存空间
参数:size size_t类型
返回:指向这块内存空间的void指针;调用失败会返回NULL,如果size设置为0也可能会返回NULL(并不意味着调用失败)
int main(){
int *p = (int*)malloc(sizeof(int));
if(p == NULL)printf("调用失败\n");
scanf("%d",p);
printf("结果为%d\n",*p)
free(p);
return 0;
}
借此我们还可以为数组申请内存空间
#include<stdio.h>
#include<stdlib.h>
int main(){
int *p = NULL;
int n;
printf("定义数组元素:");
scanf("%d",&n);
p = (int*)malloc(n*sizeof(int));
for(int i = 0;i<n;i++){
p[i] = i;
}
for(int i = 0;i<n;i++){
printf("p[%d] = %d\n",i,p[i]);
}
free(p);
return 0;
}
作用:释放malloc、calloc、realloc或aligned_alloc所申请的堆空间。若参数p为NULL,则不执行任何操作。
参数:p void指针
我们已经可以使用malloc分配内存空间了,还差初始化这一步,虽然写代码完成。但其实还存在一种更高效的方法,那就是calloc
作用:申请分配n个长度为size的内存空间。( 相当于malloc(n*size) )然后这些内存空间全部被初始化为0
参数:n size_t类型
? size size_t类型
int *a = (int*)calloc(12,sizeof(int));
for(int i = 0;i<12;i++){
a[i] += i;
printf("a[%d] = %d\n",i,a[i]);
}
free(a);
//可以看出calloc很好地初始化了内存空间,不然肯定都是随机值
这个函数可以重新分配内存。
比如你使用一个长度为10的字符串,突然不够用了;这时候,realloc可以使字符串在程序运行中进行扩展。(也就是可以实现变长数组)
作用:修改p所指向的内存空间的大小。若新分配的大于原来分配的,原来内存空间中的数据不会被改变;若新分配的小于原来分配的,原来内存空间中的数据可能会丢失
参数:
p
void指针(如果不是NULL,必须是malloc、calloc、realloc所调用的)
size
size_t类型
//这一般会根据用户的要求来拓宽内存空间
//下面为实现【变长数组】的代码
int num;
int count = 0;
int*p = NULL;
do{
printf("输入整数(输入负数视为放弃输入):");
scanf("%d",&num);
count++;
p = (int*)realloc(p,count*sizeof(int));
assert(p != NULL);
p[count-1] = num;
}while(num >= 0);
printf("==============\n");
for(int i = 0;i < count-1;i++){
printf("p[%d] = %d\n",i,p[i]);
}
①p设置为NULL,相当于使用malloc( size )
②size设置为0,相当于使用free( p )
尝试用虚拟机
运行一下以下代码体验一下内存泄漏的感觉
#include<stdlib.h>
int main(){
while(1){
malloc(1);
}
}
内存泄漏是指已动态分配的堆内存因为某种原因无法释放,造成内存的浪费。轻则占用内存减慢速度重则系统奔溃(数据丢失)
内存泄漏一般比较难发现,最好在敲一些涉及到内存的代码时考虑这个问题
分类
没有及时地释放内存而导致内存的堆积
内存地址如果无法获取,就意味着无法对这块内存地址无法进行操作,自然也不可能尝试去free掉。
int *p = (int*)malloc(3);
int q = 3;
p = &q;
/*这个时候会丢失malloc申请的内存地址
也无法进行free操作来释放掉
代码段→
数据段→
BSS段→
堆→
未使用的内存空间→
栈→
命令行参数和环境变量
存放程序执行代码的一块内存区域。
这块内存在程序运行前就已经确定,且这块内存通常属于只读
用来存放已初始化的全局变量、局部静态变量
用来存放未初始化的全局变量
这块内存的数据在程序运行前会被自动初始化为0
用来存放进程中被动态分配的内存段。
内存大小不固定,可动态扩展、缩小。
使用malloc就是将新分配内存添加到堆上
使用free就是将堆上的内存移走
函数执行的内存区域,一般和堆共享一个区域。
目前对于堆栈的原理没必要详细地掌握,在数据结构中你将会对堆栈有着更深刻的理解
堆 | 栈 |
---|---|
手动申请手动释放 | 自动申请自动释放 |
速度慢空间大 | 速度快空间较小 |
生存周期是从申请到释放 | 生存周期是从函数调用开始到调用结束 |
不同函数之间可自由访问 | 不同函数的局部变量不能互相访问 |
先进先出 | 先进后出 |
是向高地址扩展的 | 是向低地址扩展的 |
现在你已经可以运用这四个函数来动态管理内存,当然这些基本操作是为后面一些内容作铺垫的。
如果还想实现更多的对内存的操作可以使用
https://www.cnblogs.com/Binhua-Liu/archive/2010/08/24/1803095.html
原文:https://www.cnblogs.com/AlienfronNova/p/14591875.html