C杂讲 动态内存分配

这篇博客介绍了C语言中动态内存管理的基础知识,包括malloc函数用于分配内存,free函数用于释放内存,calloc函数在分配内存时自动清零,以及realloc函数用于动态调整已分配内存的大小。文中通过多个实例展示了如何使用这些函数,并强调了堆区空间使用时的注意事项,如避免多次释放同一块内存。
摘要由CSDN通过智能技术生成

目录

知识点1【malloc函数 和 free函数】

malloc函数

free函数

 知识点2【calloc函数】

知识点4【realloc动态追加或减少空间】

 知识点5【堆区空间使用的注意事项】

知识点6【防止多次释放】


知识点1【malloc函数 和 free函数】

malloc函数

#include<stdlib.h>
void *malloc(unsigned int num_size);
形参:num_size需要申请空间大小的字节数。
返回值:
    成功:返回空间的起始地址
    失败:NULL
特点:
    1、对于malloc的返回值 一般要强制类型转换
    2、malloc申请的空间 内容不确定  一般使用memset进行清空
   3、多次调用malloc 第1次malloc 和 第2次malloc的地址不一定连续     

free函数

void free(void *addr);
释放堆区空间

案例1:从堆区申请 一个int空间

void test02()
{
	int *addr = NULL;

	addr = (int *)malloc(sizeof(int));
	if(addr == NULL)//申请失败了
	{
		printf("malloc err\n");
		return;
	}

	printf("*addr=%d\n", *addr);//不确定的值
	
	//对堆区空间 清0
	memset(addr, 0, sizeof(int));
	printf("*addr=%d\n", *addr);//0

	//对addr的空间 就行写 或 读
	*addr = 1000;//写

	printf("*addr=%d\n", *addr);//1000 读


	//释放堆区空间 空间使用权限的回收 是否对空间内容清0 这是不确定的
	free(addr);
}
int main(int argc,char *argv[])
{
	test02();
	return 0;
}

运行结果:

 案例2:从堆区申请一个数组 数组的大小 由用户决定

1、从键盘获取 用户要申请的数组大小
2、根据大小 从堆区申请空间
3、对空间的读写操作
4、释放该空间

void test03()
{
	int n = 0;
	int i=0;
	int *arr=NULL;
	
	//1、获取用户大小
	printf("请输入元素的个数:");
	scanf("%d", &n);
	
	//2、根据大小从堆区申请空间
	arr = (int *)malloc(n*sizeof(int));
	if(NULL == arr)
	{
		//perror 错误输出
		perror("mallac");
		return;
	}

	//对arr的读写操作
	printf("请输入%d个int数据\n",n);
	for(i=0;i<n; i++)
	{
		scanf("%d", arr+i);
	}

	//遍历数组
	for(i=0;i<n;i++)
	{
		printf("%d ", arr[i]);
	}
	//释放空间
	free(arr);
}
int main(int argc,char *argv[])
{
	test03();
	return 0;
}

案例3:从堆区申请一个数组 数组的大小 由用户决定(函数版本)

int get_n(void)
{
	int n = 0;
	printf("请输入元素的个数:");
	scanf("%d", &n);
	return n;
}
int* get_addr(int n)
{
	return (int *)malloc(n*sizeof(int));
}
void my_input_array(int *arr, int n)
{
	int i=0;
	//记得将arr指向的空间清0
	memset(arr,0,n*sizeof(int));

	//获取键盘输入
	printf("请输入%d个int数据\n",n);

	for(i=0;i<n; i++)
	{
		scanf("%d", arr+i);
	}
}
void my_print_array(int *arr, int n)
{
	int i=0;
	for(i=0;i<n;i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");
}
void test04()
{
	int *arr=NULL;
	int n = 0;

	//得到用户输入的元素个数
	//1、获取用户大小
	n = get_n();
	
	//定义函数 给arr申请堆区空间
	arr = get_addr(n);
	if(arr == NULL)
	{
		perror("get_addr");
		return;
	}

	//对空间读写操作
	my_input_array(arr, n);


	//对空间数组遍历
	my_print_array(arr, n);

	//释放空间
	free(arr);

}
int main(int argc,char *argv[])
{
	test04();
	return 0;
}

运行结果:

 知识点2【calloc函数】

#include<stdlib.h>
void * calloc(size_t  nmemb,size_t  size);
参数:
    1、nmemb 申请的数据块数
    2、size  每一块大小
    3、所以申请总大小=nmemb * size  
返回值:
    成功:返回空间的起始地址
    失败:返回NULL
特点:申请的空间自动清零    

案例:

void test04()
{
	int n = 0;
	int i=0;
	int *arr=NULL;
	
	//1、获取用户大小
	printf("请输入元素的个数:");
	scanf("%d", &n);
	
	//2、根据大小从堆区申请空间
#if 0
	arr = (int *)malloc(n*sizeof(int));
	if(NULL == arr)
	{
		//perror 错误输出
		perror("mallac");
		return;
	}
	memset(arr,0,n*sizeof(int));//清零
#endif

#if 1
	arr=(int *)calloc(n, sizeof(int));//自动清零  不需要使用memset
	if(NULL == arr)
	{
		//perror 错误输出
		perror("calloc");
		return;
	}
#endif
	//对arr的读写操作
	printf("请输入%d个int数据\n",n);
	for(i=0;i<n; i++)
	{
		scanf("%d", arr+i);
	}

	//遍历数组
	for(i=0;i<n;i++)
	{
		printf("%d ", arr[i]);
	}

	//释放空间
	free(arr);

}

知识点4【realloc动态追加或减少空间】

#include<stdlib.h>
void* realloc(void *s, unsigned int newsize);

功能:

        在原先s指向的内存基础上重新申请内存,新的内存的大小为 new_size 个 字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不 够用,则realloc函数会在堆区找一个newsize个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。

参数:

         s:原先开辟内存的首地址

         newsize:新申请的空间的大小

返回值:

        新申请的内存的首地址

注意:一定要保存 realloc的返回值

void test06()
{
	int *arr = NULL;
	int n = 0;
	int i=0;
	int n_new = 0;

	//1、获取用户大小
	printf("请输入元素的个数:");
	scanf("%d", &n);
	
	arr=(int *)calloc(n, sizeof(int));//自动清零  不需要使用memset
	if(NULL == arr)
	{
		//perror 错误输出
		perror("calloc");
		return;
	}

	printf("请输入%d个int数据\n",n);
	for(i=0;i<n; i++)
	{
		scanf("%d", arr+i);
	}

	//遍历数组
	for(i=0;i<n;i++)
	{
		printf("%d ", arr[i]);
	}

	//再追加5个元素
	printf("请输入新增的元素个数:");
	scanf("%d", &n_new);
	arr = (int *)realloc(arr, (n+n_new)*sizeof(int));

	printf("请输入新增的%d个int数据\n",n_new);
	for(i=n;i<(n+n_new); i++)
	{
		scanf("%d",arr+i);
	}

	for(i=0;i<(n+n_new);i++)
	{
		printf("%d ", arr[i]);
	}
	printf("\n");

	free(arr);
}
int main(int argc,char *argv[])
{
	test06();
	return 0;
}

运行结果:

 知识点5【堆区空间使用的注意事项】

void test08()
{
	int *p2 = NULL;
	int *p3 = NULL;
	//1、指向堆区空间的指针变量 不要随意的更改指向
	int *p=(int *)calloc(1,sizeof(int));
	int num = 10;
	p = &num;//p指向num  导致calloc申请的空间泄露

	//2、不要操作已经释放的空间
	p2 = (int *)calloc(1,sizeof(int));
	*p2 = 1000;
	//释放该空间
	free(p2);
	printf("*p2 = %d\n", *p2);//不确定

	//3、不要对堆区空间重复释放
	p3 = (int *)calloc(1,sizeof(int));
	free(p3);
	free(p3);//多次释放
}

知识点6【防止多次释放】

void test09()
{
	int *p = (int *)calloc(1,sizeof(int));

	if(p != NULL)//防止多次释放
	{
		free(p);
		p=NULL;
	}
	

	if(p != NULL)
	{
		free(p);
		p=NULL;
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值