指针和动态储存->malloc calloc realloc free

本文详细介绍了C语言中动态内存管理的几个关键函数——malloc、calloc、realloc和free。通过实例展示了它们的使用方法,包括void指针的作用、动态内存分配与释放的过程,以及realloc的内存扩展与收缩。注意,未初始化的内存块赋值可能出现不确定的值,而free用于释放不再使用的内存。
摘要由CSDN通过智能技术生成

指针和动态储存->malloc calloc realloc free

内容为自学笔记,如有错误还望指正

在了解这几个函数之前,先了解一下void类型指针:
它是一种通用指针类型,它不针对某个特定的数据类型

```c
int main() {
int A[5] = { 1,2,3,4,5 };
int* p1 = &A[0];
char* p2 = p1;
void* p3 = p1;
} 在这里插入图片描述
为什么说它是通用指针类型?如图,当char类型指针p2指向int类型指针p1编译器会报错,但void类型指针p3指向int型指针p1并没有发生报错
p3=p1并不需要指针类型的转换,p3=p1是合法的,并不会有编译错误。

int main() {
	int A[5] = { 1,2,3,4,5 };
	int* p1 = &A[0];
	void* p2 = &A[0];
	printf("指针p1所指地址:%d\n", p1);
	printf("指针p2所指地址:%d\n", p2);
}

运行结果如下:
在这里插入图片描述

int main() {
	int A[5] = { 1,2,3,4,5 };
	int* p1 = &A[0];
	void* p2 = &A[0];
	printf("指针p1所指地址:%d,所指地址存储值:%d\n", p1,*p1);
	printf("指针p2所指地址:%d,所指地址存储值:%d\n", p2,*p2);//*p2会报错
}

printf(“指针p2所指地址:%d,所指地址存储值:%d\n”, p2,*p2 );

但是当我们解引用指针p1,p2指向地址所存储的值,会发现,代码中*p2会报错,提示表达式必须是指向完整对象类型的指针

在这里插入图片描述
这是因为void这种类型指针没有映射到任何特定类型,如int类型,不能直接对它解引用。

printf(“address of A[1]:%d”,p2+1 )

同时也不能进行指针算数运算

堆上分配内存的函数

在之前已经了解到,void* 是一个通用指针,所以malloc、calloc、realloc函数都是通用函数,只在堆上分配内存,并不在乎存储的内容是什么数据类型(int,char…),它只是简单的返回指向这个内存块首地址的void指针。
所以为了能过使用这三个函数,必须首进行指针类型转换。
在这里插入图片描述
返回首地址201

malloc函数
函数定义:

void* malloc(size_t size)

参数是内存块的字节数大小,比如int型是4字节内存块
我们注意到参数的数据类型是size_t,我们可以把它想象成类型unsigned int,只能是0和正整数,不能是负数
(size_t这个特定类型的目的就是保证参数只能是0或正整数)
使用:

int* A = (int*)malloc(sizeof(int));
int* B = (int*)malloc(4 * sizeof(int));

将void* malloc数据类型转换为int*型
创建一个int型大小的内存块并将首地址返回个int型指针A
创建四个int型大小的内存块并将首地址返回个int型指针B

int main() {
	int* A = (int*)malloc(sizeof(int));
	int* B = (int*)malloc(4 * sizeof(int));
	*A = 1;
	*B = 1;
	*(B + 1) = 2;
	* (B + 2) = 3;
	printf("value of A:%d\n", *A);
	printf("value of arrB:%d ,%d ,%d", *B, *(B + 1), *(B + 2));
	printf("\n\n\n\n\n\n");
}

在这里插入图片描述
*A = 1;
*B = 1;
*(B + 1) = 2;
* (B + 2) = 3;
等价于
A[0] = 1;
B[0] = 1;
B[1] = 2;
B[2] = 3;

这里要注意的是,如果没有为开创的内存块赋值,则会产生不确定的值。

calloc函数
与malloc函数类似。
函数定义:

void* calloc(size_t num,size_t size)

size_t num 参数是想要创建某一数据类型的个数
size_t size 参数是内存块的字节数大小,比如int型是4字节内存块

	int* A = (int*)malloc(5 * sizeof(int));
	int* B = (int*)calloc(5, sizeof(int));

这两句实现的内容是一样的,都是创建5个int型大小的内存块

其中要注意的是calloc创建的内存块会自动赋初始值。

int main() {
	int* A = (int*)malloc(5 * sizeof(int));
	int* B = (int*)calloc(5, sizeof(int));
	for (int i = 0; i < 5; i++)
		printf("%d\n",A[i]);
	for (int i = 0; i < 5; i++)
		printf("%d\n", B[i]);
}

运行结果:
在这里插入图片描述

realloc函数

函数定义:

void* realloc(void* pointer,size_t size)

第一个参数是指向已分配内存的起始地址的指针
第二个参数是新的内存块的大小

使用场景:

如果有一块内存存放n个元素,我们想让它能够存储的元素数增加或减少
(比如一开始分配了能够存放5个元素的内存块,如果我们想要它能够存储10个元素,或只能存储2个元素可以使用realloc,内存块大小会发生改变。)

工作方式:

请求的新内存块大于之前的块,如果可以扩展之前的块(能够在之前的块的基础上找到连续的内存),那么拓展之前的块,否则就分配新的内存,被之前的块中的内容拷贝过去,然后释放之前内存块。

int main() {
	int* A = (int*)malloc(5 * sizeof(int));
	for (int i = 0; i < 5; i++)
		A[i] = i + 1;
	A = (int*)realloc(A, 10 * sizeof(int));//从可存放5个元素内存扩展到可存放10个元素内存
	for (int i = 0; i < 10; i++)
		printf("%d ", A[i]);
	printf("\n");
	A = (int*)realloc(A, 3 * sizeof(int));//再从可存放10个元素内存减少到可存放3个元素内存
	for (int i = 0; i < 3; i++)
		printf("%d ", A[i]);
}

运行结果:
在这里插入图片描述
同时realloc有时也可以用free和malloc替代:

int main() {
	int* A = (int*)malloc(5 * sizeof(int));
	A = (int*)realloc(A, 0);//等同于free(A)
	int* B = (int*)realloc(NULL, 5 * sizeof(int));//等同于int* B=malloc(5*sizeof(int))
}

堆上释放内存的函数

free
任何分配了的动态内存在程序结束之前会一直存在(在堆中一直占据着内存,不会像栈一样自动释放内存) ,除非自己来释放这部分内存。
malloc、calloc、realloc分配的内存,要使用free函数来释放

free的参数是内存块的起始地址

int main() {
	int* A = (int*)malloc(5 * sizeof(int));
	for (int i = 0; i < 5; i++)
	{
		A[i] = i + 1;
		printf("%d ", A[i]);
	}
	printf("\n");
	free(A);
	for (int i = 0; i < 5; i++)
		printf("%d ", A[i]);
}

运行结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值