动态内存管理

动态内存

int a=0;
char c[20]={0};
//int 在栈帧空间开辟四字节
//char 在栈帧空间开辟二十字节

动态内存函数

栈区:局部变量,函数形式参数

堆区:动态内存管理

malloc

<stdlib.h>

void* malloc (size_t size)

用于申请内存空间,返回一个指针返回指向空间的首地址

如果申请失败将会返回空指针

当开辟的空间过大就会出现失败的情况

如果参数为零是未定义的,结果取决于编译器

开辟失败
在这里插入图片描述

void* malloc(size_t size);
//在堆上开辟size个字节的空间
int main()
{
    //申请40个字节
    int*p=(int*)malloc(40);
    //因为malloc函数的返回值为void*所以要强制转化
    if(p==NULL)
    //开辟失败返回空指针
    {
        printf("%s\n",streeor(errno));
        return 1;
    }
    int n=0;
    for(n=0;n<10;n++)
    {
        //使用malloc开辟的空间来存放1~10
        *(P+1)=n+1;
    }
    //打印
    for(n=0;n<10;n++)
    {
        printf("%d ",*(p+n));
    }
    return 0;
}

free

<stdlib.h>

void free(void*ptr)

释放内存,参数为释放空间的首地址

只能释放动态内存释放的空间,如果传如参数是空指针,函数将无作为

//malloc开辟的空间会在程序结束后销毁
//但是程序内容过多,这片空间用不上的情况下,就是典型的“占着茅坑不拉屎”
//所以可以使用free函数来主动释放掉这块内存
int main()
{
    int* p=(int*)malloc(40);
    //开辟40字节空间
    free(p);
    //释放掉这片空间
    //但是p其实还是指向了这块空间的起始位置的地址
    p=NULL; 
}

calloc

<stdlib.h>

void* calloc(size_t num,size_t size)

num为开辟元素个数

size每个元素大小

开辟空间失败,返回空指针

申请好空间后,会把空间初始化为零,然后返回起始地址

 int main()
 {
     int* p=(int*)calloc(10,sizeof(int));
     if(NULL==p)
     {
         perror("calloc");
         //打印错误信息
         return 1;
     }
  
     return 0;
 }

开辟失败
在这里插入图片描述

calloc和malloc的区别

malloc开辟空间没有初始化直接返回起始位 地址

calloc开辟空间值初始化为零后返回起始位地址

在这里插入图片描述
在这里插入图片描述

realloc

重新调整内存块

realloc

<stdio.h>

void* realloc (void*ptr,size_t size)

ptr指向malloc,calloc,realloc开辟的空间

size开辟空间的大小 (字节)

当relloc的第一个参数为NULL,它的作用就和malloc相当

当ptr指向空间足够扩容,将会直接在当前空间后接上新空间,返回旧空间地址

当ptr指向空间不够扩容,将会开辟一片满足条件的新连续空间,并把原空间的数据拷贝到新扩容空间之前的位置,再把原空间给释放掉后返回新空间的地址

扩容失败返回NULL

所以在接收realloc的返回地址要用新的指针变量,防止使用原来变量接收返回的空指针,导致原指针数据丢失

int main()
{
    int* p = (int*)malloc(5 * sizeof(int));
    if (p == NULL)
    {
        perror("malloc");
        return 1;
    }
    int i = 0;
    for (i = 0; i < 5; i++)
    {
        *(p + i) = i + 1;
    }
    int* ptr = (int*)realloc(p, 5 * sizeof(int));
    //继续使用空间
    if (ptr != NULL)
    {
        p = ptr;
        ptr = NULL;
    }
    for (i = 0; i < 10; i++)
    {
        printf("%d ",*(p+i));
    }
    free(p);
    p = NULL;
    return 0;
}

动态内存错误操作

对空指针解引用

int main()
{
	int* p=(int*)malloc(40);
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = 0;
	}
	return 0;
}

在这里插入图片描述

### 动态空间的连续访问

int main()
{
	int* p=(int*)malloc(10);
	if (p == NULL)
	{
		return 1;
	}
	//越界访问
	int i = 0;
	for (i = 0; i <=100; i++)
	{
		p[i] = 0;
	}
	free(p);
	p = NULL;
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-vT9HpMeY-1675828940067)(C:\Users\小八\AppData\Roaming\Typora\typora-user-images\image-20230206223631498.png)]

对非动态内存使用free释放

int main()
{
	int a = 10;
	int* p = &a;
	free(p);
	p = NULL;
	return 0;
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-OdP0QnN8-1675828940067)(C:\Users\小八\AppData\Roaming\Typora\typora-user-images\image-20230206224256837.png)]

使用free释放动态内存的一部分

int main()
{
	int* p = (int*)malloc(10);
	if (p == NULL)
	{
		return 1;
	}
	int i = 0;
	for (i = 0; i < 5; i++)
	{
		*(p) = i;
		p++;
	}
	//此时p指向循环结束的位置
	free(p);
	p = NULL;
	return 0;
}

在这里插入图片描述

对动态内存多次释放

int main()
{
    int* p=(int*)malloc(100);
    if(p=NULL)
    {
        return 1;
    }
    free(p);
    //释放后p还是指向原空间地址
    free(p);
    return 0;
}

在这里插入图片描述

动态内存忘记释放(内存泄露)

动态内存开辟不释放就会一直浪费内存

void test()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return;
	}
	//函数结束内存没有释放,主函数内也无法释放
	//所以在使用后要直觉使用
	//free(p);
	//p=NULL;
	//如果返回指针,在主函数内释放
    //if(1)
    //{
    //   return;
    //}
    //来不及释放
    //free(p);
   // p=NULL;
}
int main()
{
	/*int* b =*/ test();
	//free(b);
	//b=NULL;
	return 0;
}

柔性数组

C99中,结构中的最后一个元素允许是位置大小的数组,这就叫做柔性数组成员

结构体中的柔性数组成员之前必须至少有一个其他成员

计算结构体的大小时不包含柔性数组大小

包含柔性数组的结构体用malloc函数开辟动态内存时,开辟的空间应该大于结构体的大小,以适应柔性数组的预期大小

typedef struct S
{
  	int a;
    char b;
    char c[0];//柔性数组,表示数组大小是未知的
    //cahr c[];意义是一样的    
}typ_s;
int main()
{						//多开辟了十个字节
    typ_s* ptr=malloc(sizeof(typ_s)+10*sizeof(char));
    if(ptr==NULL)
    {
        perror("malloc");
        return;
    }
    int sz=sizeof(typ_s);
    ptr->n=100;
    int i=0;
    for(i;i<10;i++)
    {
       ptr->c[i]='1'; 
        printf("%c\n",c[i]);
    }
    typ_s*ptt=(typ_s*)realloc(ptr,sizeof(typ_s)+20*sizeof(char));
    if(ptt!=NULL)
    {
        ptr=ptt;
        printf("增容\n");
    }
    else
    {
        perror("perror");
        return 1;
    }
    free(ptr);
    ptr=NULL;
    return 0;
}

在这里插入图片描述

这片空间是连续的

方便内存释放,访问速度更快
在这里插入图片描述

typedef struct S
{
	int i;
	char* c;
}typ_s;
int main()
{
	typ_s* ptr = (typ_s*)malloc(sizeof(typ_s));
	if (ptr == NULL)
	{
		perror("malloc");
		return 1;
	}

	ptr->c = (char*)malloc(sizeof(char) * 10);
	if (ptr->c == NULL)
	{
		perror("malloc->c");
		return 1;
	}
	ptr->i = 100;
	int i = 0;
	for (i; i < 10; i++)
	{
		ptr->c[i] = 'A';
		printf("%c\n", ptr->c[i]);
	}
	char* ptt = (char*)realloc(ptr->c, sizeof(char) * 20);
	if (ptt != NULL)
	{
		ptr->c = ptt;
	}
	else
	{
		perror("realloc::ptt");
		return 1;
	}

	free(ptr->c);
	ptr->c = NULL;
	free(ptr);
	ptr = NULL;
	return 0;
}

用指针也可以实现,但是内存不连续,浪费内存

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值