动态内存分配 - 在堆上开辟空间

关于动态内存分配的函数大概有三个,接下来一一介绍

malooc

头文件 - stdlib.h

函数原型 - void *malloc(size_t size) size_t size 无符号整型的大小,单位是字节

函数功能 - malloc 返回指向已分配空间的 void 指针,如果可用内存不足,则返回 NULL。若要返回指向 void 以外的类型的指针,请在返回值上使用强制转换的类型。保证返回值指向的存储空间适合存储任何类型的对象。如果 size 为 0,malloc 将在堆中分配一个长度为零的项目,并返回指向该项目的有效指针。始终检查来自 malloc 的返回,即使请求的内存量很小。malloc只是简单地在堆上开辟空间,并不会对开辟后的空间进行给初始化

函数用法,如图所示:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
    //void* malloc(size_t size)
    int* p = (int *)malloc(40);
    //开辟40个字节的空间,若果malloc开辟空间失败就会返回一个NULL,malloc本来的返回类型应该是void*,所以一般情况下我是需要进行强制类型转换的
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
        //如果程序执行过程中发生了错误,会将错误码赋给errno,然后通过strerror函数会找到错误码对应的错误信息,然后我就可以打印出来,该过程完全可以用perror来代替
    }
    else
    {
        int i = 0;
        for (i = 0; i < 10; i++)//注意不要越界访问,开辟多少空间就用多少空间
        {
            *(p + i) = i;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
    }
    //每当动态申请的空间不再使用的时候,就应该用free还给操作系统,
    //但是单单用一个free只能将申请到的空间归还,可是指针所指向的位置依旧没有发生改变,于是,归还之后应当给指针赋成NULL
    free(p);
    //这里释放的应该是动态空间开辟的内存空间,也就是堆区内部的内存空间
    //当p为NULL时,free(NULL)时不进行任何操作的
    p = NULL;
    return 0;
}

运行结果,如图所示:

动态内存开辟空间的时候,一定要注意的是,要及时的用free释放掉开辟并使用后不再使用的内存空间,未了防止内存泄漏,同时还应该注意,free单纯的只是归还了指针指向的空间,并未改变指针的值,于是free之后还应该将指针置空。

calloc

头文件 - stdlib.h

函数原型 - void*calloc(size_t num , size_t size)

函数功能- 为对象的数组分配内存,并将分配的存储中的所有字节初始化为零。numsize如果分配成功,则返回一个指针,指向分配的内存块中的最低(第一个)字节,该指针对于具有基本对齐的任何对象类型都适合对齐。如果为零,则行为是实现定义的(可能返回空指针,或者可能返回一些可能不用于访问存储的非空指针)

函数用法,如下所示:

#define  _CRT_SECURE_NO_WARNINGS 1

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
    //void*calloc(size_t num , size_t size)
    //size_t num - 元素的个数
    //size_t size - 每个元素的字节大小
    //free会用来释放动态开辟的空间的
    //calloc功能是为num个大小为size的元素开辟一块空间,并且把每一字节初始化为0
    //calloc与malloc的区别在于calloc再返回地址之前会把申请的空间的每个字节初始化为0
    int* p = (int*)calloc(10, sizeof(int));
    if (p == NULL)
    {
        printf("%s\n", strerror(errno));
    }
    else
    {
        int i = 0;
        for (i = 0; i < 10; i++)//注意不要越界访问,开辟多少空间就用多少空间
        {
            printf("%d ", *(p + i));
        }
        printf("\n");
        for (i = 0; i < 10; i++)
        {
            *(p + i) = i;
        }
        for (i = 0; i < 10; i++)
        {
            printf("%d ", *(p + i));
        }
        printf("\n");
    }
    free(p);//这里释放的应该是动态空间开辟的内存空间,也就是堆区内部的内存空间
    p = NULL;
    return 0;
}

所有需要注意的点我都在代码中的相应位置给予了注释,运行结果如下:

第一行结果是开辟空间之后由函数自己初始化的内容,第二行结果是是由代码进行改变的。该函数和malloc相同的地方(也是动态内存开辟都应具有的相同点)是必须都要用free释放掉使用完的空间,并将指向这片空间的指针置空;不同点是malloc不初始化,但calloc会初始化开辟的空间。

realloc

头文件 - stdlib.h

函数原型- void* realloc(void* memblock,size_t size)

void* memblock - 之前开辟的内存的地址(需要改变的内存块的地址)

size_t size - 新开辟之后的字节大小

函数功能 -

重新分配给定的内存区域。如果不是 NULL,则必须事先由 malloc()、calloc() 分配,或者尚未通过调用 free的空间。重新分配由以下任一方式完成:

a)如果可能,扩大或收缩 所指的现有区域。该区域的内容保持不变,直到达到新旧大小中的较小者。如果该区域展开,则数组新部分的内容是未初始化的。

b)分配大小为给定字节的新内存块,复制大小等于新旧大小中较小者的内存区域,并释放旧块。new_size如果没有足够的内存,则不会释放旧内存块并返回空指针。

如果为 NULL,则行为与调用malloc的行为是一样的。

函数用法如下所示:

#define  _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
    //void* realloc(void* memblock,size_t size)
    //void* memblock - 之前开辟的内存的地址(需要改变的内存块的地址)
    //size_t size - 新开辟之后的字节大小
    int* p = (int *)malloc(20);
    if (p == NULL)//这里很重要,一定要判断一下开辟是否成功
    {
        printf("%s\n", strerror(errno));
    }
    else
    {
        int i = 0;
        for (i = 0; i < 5; i++)//注意不要越界访问,开辟多少空间就用多少空间
        {
            *(p + i) = i;
            printf("%d ", *(p + i));
        }
    }
    printf("\n");
    //使用malloc开辟了一个20个字节大小的空间,假设这里20个字节的空间不够用,希望能开辟40个字节大小的空间
    //这里就可以用realloc来调整动态内存分配
    //realloc函数的使用注意事项:
    //1.如果p指向的空间后有足够的内存空间可以追加,则直接追加,完成之后返回p
    //2.如果p指向的空间后没有足够的内存空间可以追加,则realloc会重新开辟一个新的满足代码要求的内存区域
    //  并且把原来内存空间内的数据拷贝放到这个新的内存空间,然后把旧的空间地址释放掉,最后返回这个新的内存空间的起始地址
    //3.得用一个新的指针变量来接收realloc函数的返回值
    int* pos = (int *)realloc(p, 40);
    if (pos != NULL)
    {
        p = pos;
        int i = 0;
        for (i = 5; i < 10; i++)//注意不要越界访问,开辟多少空间就用多少空间
        {
            *(p + i) = i;
            printf("%d ", *(p + i));
        }
    }
    free(p);//这里释放的应该是动态空间开辟的内存空间,也就是堆区内部的内存空间
    p = NULL;
    return 0;
}
//当给realloc传的指针为空指针的时候也可以当做malloc
//int*p=realloc(NULL,10); == int* p=malloc(10);

需要注意的点以及realloc是如何重新开辟空间的我都用注释放在了代码中合适的位置。运行结果如下:

在这里注意看代码中的注释:

realloc函数的使用注意事项:

1.如果p指向的空间后有足够的内存空间可以追加,则直接追加,完成之后返回p

2.如果p指向的空间后没有足够的内存空间可以追加,则realloc会重新开辟一个新的满足代码要求的内存区域并且把原来内存空间内的数据拷贝放到这个新的内存空间,然后把旧的空间地址释放掉,最后返回这个新的内存空间的起始地址

3.得用一个新的指针变量来接收realloc函数的返回值(这个点好好思考一下,当空间足够时,realloc在旧空间上进行改变的话,最终返回的地址的值依旧是p的值,只不过变量的名字和旧地址的名字不一样罢了;但如果空间不够的时候,realloc会重新开辟的空间,同时返回的新的地址pos我就应该将这个新的地址赋给原来的p,再加上旧空间里的数据也已经拷贝进了新的空间,所以不会有任何影响)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值