C 语言动态内存

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_34719188/article/details/83903398

说明

主要参考以下博客:

内存示意图


示意图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

常见错误代码实例


参考博客:经典笔试题:动态内存分配,详解

  1. 情景一
void fun(char *p)
{
    p = (char *)malloc(100);
}

int main()
{
    char *str = NULL;
    fun(str);
    strcpy(str,"hello world");

    system("pause");
    return 0;
}

错误原因:错在这里的传参发生了拷贝行为,并不是传的地址

  1. 情景二
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,也不会造成内存泄漏,而是会打印出随机值。因为申请在内存在栈上而不是在堆上

  1. 情景三
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;
}

错误原因:内存泄漏

  1. 情景四
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

猜你喜欢

转载自blog.csdn.net/qq_34719188/article/details/83903398