说明
主要参考以下博客:
内存示意图
示意图1:
示意图2:
alloc()
参考博客:https://blog.csdn.net/wula_heixiu/article/details/79410595**
该函数是在栈上分配内存!
这是一个不完善的存储分配程序,由两个函数组成。alloc(n)返回一个指向连续字符存储单元的指针,alloc函数的调用者可利用该指针存储字符序列。afree§释放已分配的存储空间,以便以后重用。
之所以说“不完善”,是因为对afree函数的调用次序必须与alloc函数的次序相反。换句话说,alloc与afree以栈的方式(即后进先出的列表)进行存储空间的管理。标准库中提供了具有类似功能的函数malloc和free,它们没有上述限制。
最容易的实现方法是让alloc函数对一个大字符数组allcbuf中的空间进行分配。该数组是alloc和afree两个函数的私有数组。由于函数alloc和afree处理的对象是指针而不是数组下标,因此,其他函数无需知道该数组的名字,将其声明为static类型。
实际实现时,该数组甚至没有名字,它可以通过malloc函数或像操作系统申请一个指向无名存储块的指针获得。(不懂)
alloc函数具体实现:我们使用指针allocp指向allocbuf中的下一个空闲单元。当调用alloc申请n个字符的存储空间时,alloc检查allocbuf中有没有足够的剩余空间。如果有,则返回allocp的当前值(即空闲块开始的位置),然后将allocp加n以使它指向下一个空闲区域。如果没有,则返回0。
afree函数具体实现:如果p在allocbuf的边界之内,则afree§仅仅只是将allocp的值设置为p。
#define ALLOCSIZE 1000 /* 可用空间大小 */
static char allocbuf[ALLOCSIZE]; /* alloc使用的存储区 */
static char *allocp; /* 下一个空闲位置 */
char *alloc(int n) /* 返回指向n个字符的指针 */
{
if(allocbuf + ALLOCSIZE - allocp >= n){ /* 有足够的空间 */
allocp += n;
return allocp - n; /* 分配前的指针 */
}
else /* 空闲空间不够 */
return 0;
}
void afree(char *p) /* 释放p指向的存储区 */
{
if(p >= allocbuf && p < allocbuf + ALLOCSIZE)
allocp = p;
}
malloc()
头文件:#include “malloc.h”
函数原型:void *malloc(size_t size)
功能: 从空闲内存池中分配连续内存,但不初始化
参数: 申请变量字节数的整数倍
返回: 若分配成功则返回一个指向该内存块的指针,在使用时可根据需要做强制类型转换,否则返回NULL(空指针)//需要判空,最后要 free,释放内存空间给系统,
注意: free 函数与 malloc 函数是成对出现的,申请malloc的时候尽量去给它进行一下初始化,防止后面出现一些不确定性的东西;
生命周期: 只要没有调用 free 这个函数,进程没有结束,那么此时,这个函数的生命周期就会一直存在在内存中;它是存放在堆空间中的,它不会因为你去函数调用的结束自动去释放(堆当中的内存是全局的)
扩展博客:memset()函数及其作用
calloc()
头文件: #include “stdlib.h ”
函数原型: void *colloc(size_t num_elements,size_t element_size);
功能: 从空闲内存池中分配连续内存,但初始化
参数: :num_elements 是所需的元素的数量,element_size 是每个元素的字节数
其他同上
realloc()
头文件:#include “malloc.h”
函数原型: void *realloc(void *ptr,size_t new_size);
功能: 在指针 ptr 指向的内存基础上扩大或者缩小内存
注意:
- 参数 ptr 是指向先前通过 malloc, calloc 和 realloc 函数后分配的内存块的指针,new_size 是内存块的新尺寸,可能大于或者小于原有内存尺寸;因此,realloc在 C语言中也被称为动态数组
- 当扩展内存的时候,不会对添加进内存块的字节进行初始化
- 若不能调整内存则返回NULL,但原有内存中的数据是不会发生改变的
- 若第一个参数为NULL那么功能 等同与 malloc 函数,若第二个参数为 0 ,那么会释放调用内存块
free()
- free之后如果还有这块内存地址的话,此时这块内存归还给了系统(可能这块内存还处于一个空闲状态,里面的值短暂的会保留),但是还是可以对其进行操作。
- 因此 free 之后,申请内存的那个指针就会变成野指针
- 所以尽量在操作之后:将指针置为NULL
常见错误代码实例
参考博客:经典笔试题:动态内存分配,详解
- 情景一
void fun(char *p)
{
p = (char *)malloc(100);
}
int main()
{
char *str = NULL;
fun(str);
strcpy(str,"hello world");
system("pause");
return 0;
}
错误原因:错在这里的传参发生了拷贝行为,并不是传的地址
- 情景二
char *fun(void)
{
char p[] = "hello world";
return p;
}
int main()
{
char *str = NULL;
str = fun();
printf("%s\n",str);
system("pause");
return 0;
}
错误原因:不会打印出Hello world,也不会造成内存泄漏,而是会打印出随机值。因为申请在内存在栈上而不是在堆上
- 情景三
void fun(char **p,int num)
{
*p = (char *)malloc(num);
}
int main()
{
char *str = NULL;
fun(&str,100);
strcpy(str, "hello");;
printf("%s\n",str);
system("pause");
return 0;
}
错误原因:内存泄漏
- 情景四
int main()
{
char *str = (char *)malloc(100);
strcpy(str,"hello");
free(str);
if (str!=NULL)
{
strcpy(str,"world");
printf("%s\n",str);
}
return 0;
}
错误原因:free 后变成野指针,此时的访问是一种 undefined behavior,程序会 crash