【C】动态内存管理

本文详细介绍了C语言中的动态内存管理函数malloc、calloc、realloc和free的使用方法,包括它们的功能、用法及注意事项。同时,通过实例分析了动态内存管理可能导致的内存泄漏问题及其后果。此外,还提及了结构体中的柔性数组概念,强调了其在内存分配中的特殊性质。
摘要由CSDN通过智能技术生成

目录

动态内存函数

        malloc

        calloc

        realloc

        free

练习

柔性数组


动态内存函数

动态内存开辟的空间存放在堆区中,需要程序员手动开辟、释放。

所有动态内存函数需包含头文件 <stdlib.h>

        malloc

 全称:memory allocation

向内存申请一块连续可用的空间(不初始化),返回指向该空间的指针(void* 类型),若申请失败,则返回空指针。

由于可能会申请失败,所以在申请后须判断是否申请成功。

由于返回的指针为 void* 类型,所以须将该指针转换为对应类型再进行接收。

用法:

int* a = NULL;//接收申请空间的指针
a = (int*)malloc(40);向内存申请40字节空间并转换成对应类型
if (a == NULL)//判断是否申请失败
{
	printf("%s\n", strerror(errno));//打印错误信息
	return;//结束该函数
}

        calloc

 全称:clear allocation

向内存申请一块连续可用的空间(并初始化),返回指向该空间的指针(void* 类型),若申请失败,则返回空指针。

用法:

int* a = NULL;//接收申请空间的指针
a = (int*)calloc(4,10);向内存申请4个元素的空间,每个元素10字节,共40字节
if (a == NULL)//判断是否申请失败
{
	printf("%s\n", strerror(errno));//打印错误信息
	return;//结束该函数
}

        realloc

全称:reset allocation

对申请的空间调整大小(不初始化),若调整成功,则返回指向调整后空间的指针(void* 类型),若调整失败,则返回空指针。

由于可能会调整失败,所以在调整时须创建中间变量来接收并判断。

用法:

int* a = NULL;
a = (int*)malloc(40);
if (!a)
{
	printf("%s\n", strerror(errno));
	return;
}

int* p = realloc(a, 10);//将a指向的空间调整为10字节并赋给p
if (p != NULL)
    a = p;//如果p不为空指针则才赋给a

对空间进行增容分为两种情况:

(1)原空间后有足够增容空间,则直接在原空间后进行增容,并返回指向原空间的指针。

(2)原空间后无足够增容空间,则开辟新空间,将原有数据进行拷贝,并返回指向新空间的指针。

对空间进行减容则返回指向原空间的指针。  

调整空间时可能会出现少量空间无法利用到的情况,产生内存碎片

        free

 对申请的空间进行释放

当动态内存使用完毕后,须对该空间进行释放还给系统,否则会发生内存泄漏。

内存泄漏:动态开辟的空间使用完毕后,由于某种原因未释放或无法释放,导致程序运行变慢或崩溃。

由于释放空间后指针还是指向该空间位置,为了避免非法访问,须将指向该空间的指针置空。

用法:

int* p = (int*)malloc(40);
free(p);//释放p指向的空间
p = NULL;//将p置空

练习(判断下列代码运行结果)

(1)

void GetMemory(char *p)
{
    p = (char *)malloc(100);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(str);
    strcpy(str, "hello world");
    printf(str);
}
int main()
{
    Test();   
    return 0;
}

答案:内存泄漏;程序崩溃

未释放内存导致内存泄漏;指针传参时,传递的时自己指向的地址,因为 str 指向 NULL,所以传给 p 后,p 也指向了 NULL,不会改变 str 的指向,当对 str 进行 strcpy 时,由于 str 为空指针,不可进行修改,导致程序崩溃。

(2)

char *GetMemory(void)
{
    char p[] = "hello world";
    return p;
}
void Test(void)
{
    char *str = NULL;
    str = GetMemory();
    printf(str);
}
int main()
{
    Test();   
    return 0;
}

答案:内存泄漏;打印正常或随机值

未释放内存导致内存泄漏;局部变量 p 出了函数后被回收,但函数返回了 p 的地址,根据地址可以找到该空间,由于空间回收后不会被初始化,还保留原有值,若该空间还未被使用,则正常打印,若被使用,则打印随机值。

(3)

void GetMemory(char **p, int num)
{
    *p = (char *)malloc(num);
}
void Test(void)
{
    char *str = NULL;
    GetMemory(&str, 100);
    strcpy(str, "hello");
    printf(str);
}
int main()
{
    Test();   
    return 0;
}

答案:内存泄漏;正常打印

未释放内存导致内存泄漏;str 为指针,所以传入 &str 须用二级指针接收,解引用后找到 str 并将它指向申请的空间,最后进行 strcpy 并打印。

(4)

void Test(void)
{
    char *str = (char *) malloc(100);
    strcpy(str, "hello");
    free(str);
    if(str != NULL)
    {
        strcpy(str, "world");
        printf(str);
    }
}
int main()
{
    Test();   
    return 0;
}

答案:非法访问;正常打印

free(str)后,str 还指向原来的空间,这时对 str 进行 strcpy,就改变了已经被回收的空间。

柔性数组

 结构体内未指定元素个数的数组,且必须是最后一个成员,初始状态下不占用结构体空间。

例:

struct S
{
	int a;
	int arr[];//柔性数组
}s;
int main()
{
	sizeof(s);
	return 0;
}

结果:4

用法 :

struct S
{
	int a;
	int arr[];//柔性数组
}*s;
int main()
{
	s = (struct S*)malloc(44);//前4字节为a的空间,剩下为arr的空间
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值