零基础学C语言内存知识总结:realloc函数和free函数

Posted 一起学编程

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了零基础学C语言内存知识总结:realloc函数和free函数相关的知识,希望对你有一定的参考价值。

realloc函数

realloc()函数可以重用或扩展以前用malloc()、calloc()及realloc()函数自身分配的内存。

函数原型:

extern void *realloc(void *mem_address, unsigned int newsize);
//指针名 = (数据类型*) realloc (要改变内存大小的指针名,新的大小)。
//新的大小一定要大于原来的大小,不然的话会导致数据丢失!
//如果newsize大小为0,那么释放mem_address指向的内存,并返回NULL。

        先判断当前的指针是否有足够的连续空间,如果有,扩大mem_address指向的地址,并且将 mem_address返回,如果空间不够,先按照 newsize 指定的大小分配空间,将原有数据从头到尾拷贝到新分配的内存区域,而后释放原来 mem_address 所指内存区域(注意:原来指针是自动释放,不需要使用free),同时返回新分配的内存区域的首地址。即重新分配存储器块的地址。

1、 realloc()函数需两个参数:一个是包含地址的指针(该地址由之前的malloc()、calloc()或realloc()函数返回),另一个是要新分配的内存字节数。

2、 realloc()函数分配第二个参数指定的内存量,并把第一个参数指针指向的之前分配的内容复制到新配的内存中,且复制的内容长度等于新旧内存区域中较小的那一个。即新内存大于原内存,则原内存所有内容复制到新内存,如果新内存小于原内存,只复制长度等于新内存空间的内容。

3、realloc()函数的第一个参数若为空指针,相当于分配第二个参数指定的新内存空间,此时等价于malloc()、calloc()或realloc()函数。

4、如果是将分配的内存扩大,则有以下3种情况:

    1)  如果当前内存段后面有需要的内存空间,则直接扩展这段内存空间,realloc()将返回原指针。

    2)  如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据块释放掉,返回新的内存块地址位置。

    3)  如果申请失败,将返回NULL,此时,原来的指针仍然有效。

注意事项:

1、第一个参数要么是空指针,要么是指向以前分配的内存。如果不指向以前分配的内存或指向已释放的内存,结果就是不确定的。

2、 如果调用成功,不管当前内存段后面的空闲空间是否满足要求,都会释放掉原来的指针,重新返回一个指针,虽然返回的指针有可能和原来的指针一样,即不能再次释放掉原来的指针。

返回值:如果重新分配成功则返回指向被分配内存的指针,否则返回空指针NULL。

注意:这里原始内存中的数据还是保持不变的。当内存不再使用时,应使用free()等函数将内存块释放

#include<stdio.h>
#include<stdlib.h>
int main()

	int i;
	int *t;

	int*pn = (int*)malloc(10 * sizeof(int));//这里只是申请10个int的空间
	t = pn;

	for (i = 0; i < 10; i++)   //赋值
		pn[i] = i;
	

					//如果将这里的数值改大就将有可能出现空闲空间不足,从而申请一块新内存
	pn = (int*)realloc(pn, 20 * sizeof(int)); //多扩充10个int空间加上之前的就是一共20个int

	for (i = 10; i < 20; i++) //再赋值  注意从第10个开始的
		pn[i] = i;
	

	for (i = 0; i < 20; i++) //输出
		printf("%3d", pn[i]);
	

	printf("\\n");
	printf("p=%p \\nt=%p\\n", pn, t);//输出地址


	free(pn);//释放空间
	pn = NULL;//指针指空

	return 0;




如果申请空间的数值较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容
并返回原动态空间基地址;如果申请空间的数值较大,原来申请的空间后面没有足够大的空间扩容,
系统将重新申请一块新的内存,并把原来空间的内容拷贝过去,原来空间OS自动free;如果申请空间的数值非常大,
系统内存申请失败,返回NULL,原来的内存不会释放。注意:如果扩容后的内存空间较原空间小,将会出现数据丢失,
如果直接realloc(p, 0);相当于free(p).

使用总结:

(1)realloc失败的时候,返回NULL

(2)realloc失败的时候,原来的内存不改变,不会释放也不会移动

(3)假如原来的内存后面还有足够多剩余内存的话,realloc的内存=原来的内存+剩余内存,realloc还是返回原来内存的地址; 假如原来的内存后面没有足够多剩余内存的话,realloc将申请新的内存,然后把原来的内存数据拷贝到新内存里,原来的内存将被free掉,realloc返回新内存的地址

(4)如果size为0,效果等同于free()。这里需要注意的是只对指针本身进行释放,例如对二维指针**a,对a调用realloc时只会释放一维,使用时谨防内存泄露。

(5)传递给realloc的指针必须是先前通过malloc(),calloc(), 或realloc()分配的

(6)传递给realloc的指针可以为空,等同于malloc。

malloc与free函数

malloc中文叫动态内存分配,用于申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存,且分配的大小就是程序要求的大小。

函数原型:

void * malloc(size_t size);

在以前 malloc返回的是char型指针,新的ANSIC标准规定,该函数返回为void型指针,因此必要时要进行类型转换。
它能向系统申请分配一个长度为num_bytes(或size)个字节的内存块。

其作用是在内存的动态存储区中分配一个长度为size的连续空间。当函数申请内存分配成功时,
此函数的返回值是分配区域的起始地址,或者说,此函数是一个指针型函数,返回的指针指向该分配域的开头位置。
(它返回的是分配得到的内存的首字节地址),如果无法获得符合要求的内存块,malloc函数会返回空指针

size为要申请的空间大小,需要我们手动的去计算,如int *p = (int  * )malloc(20*sizeof(int)),如果编译器默认int为4字节存储的话,那么计算结果是80 Byte,一次申请一个80 Byte的连续空间,并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。

malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓 空闲链表的功能。

调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。

调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。

于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。如果无法获得符合要求的内存块,malloc函数会返回NULL指针(空指针),因此在调用malloc动态申请内存块时,一定要进行返回值的判断。

#include<stdio.h>
#include <stdlib.h> 

int main(void)

	int count, *array; /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/

	if ((array=(int *) malloc(10 * sizeof(int))) == NULL)//把类型强制转换为int 申请内存空间 10个int的空间 
							     //一个int大小是sizeof(int)
	
		printf("不能成功分配存储空间。");
		exit(1); //强制结束程序
	

	for (count = 0; count < 10; count++)  /*给数组赋值*/
		array[count] = count;
	

	for (count = 0; count < 10; count++)  /*打印数组元素*/
		printf("%2d", array[count]);
	
	return 0;

free函数:

free()是C语言中释放内存空间的函数,通常与申请内存空间的函数malloc()结合使用,可以释放由 malloc()、calloc()、realloc() 等函数申请的内存空间。

函数原型:

void free(void *ptr);
ptr-- 指针指向一个要释放内存的内存块,该内存块之前是通过调用 
malloc、calloc 或 realloc 进行分配内存的。如果传递的参数是一个空指针,则不会执行任何动作。
该函数不返回任何值。

上面的例子:

#include<stdio.h>
#include <stdlib.h> 

int main(void)

	int count, *array; /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/

	if ((array=(int *) malloc(10 * sizeof(int))) == NULL)//把类型强制转换为int 申请内存空间 10个int的空间 
															//一个int大小是sizeof(int)
	
		printf("不能成功分配存储空间。");
		exit(1); //强制结束程序
	

	for (count = 0; count < 10; count++)  /*给数组赋值*/
		array[count] = count;
	

	for (count = 0; count < 10; count++)  /*打印数组元素*/
		printf("%2d", array[count]);
	
	
	free(array);  //刚刚没有进行释放内存

	return 0;



******free的重要性:*******

静态内存的数量在编译时是固定的,在运行期间也不会改变,
自动变量使用的内存数量在程序执行期间自动增加或减少,但是动态内存分配内存的数量只会增加,除非使用free函数进行释放

它创建了指针array,并调用了malloc函数进行内存分配了(10* 4(int) )40个字节的内存,假设,如代码注释所示,
遗漏了free,当函数结束时,作为自动变量的指针array也会消失,但是它所指向的40个字节的内存却仍然存在,
由于array指针已被销毁,所以无法访问这块内存,它也不能被重复使用,因为代码中没有调用free函数释放这块内存,
如果是一个函数,当第二次调用它时,它又创建了array指针,并调用malloc分配40个字节的内存,第一次调用的40个字节的内存已不可用,
所以malloc函数分配了另外的内存,当函数结束时该内存也无法被访问和再使用,如果循环要进行1000次,那么每一次的调用都会分配内存,
持续增加,实际上,等不到程序结束,内存早已被耗尽,这类问题被称为内存泄漏,所以 为防止这类问题的发生,
必须要在动态内存分配函数后加上free函数释放内存。

总结:

malloc 必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。另外有一点不能直接看出的区别是,malloc 只管分配内存,并不能对所得的内存进行初始化,所以得到的一片新内存中,其值将是随机的

一般使用后要使用free(起始地址的指针) 对内存进行释放,不然内存申请过多会导致内存泄漏会影响计算机的性能,以至于得重启电脑。如果使用过后不清零,还可以使用该指针对该块内存进行访问。

通常,malloc函数要和free函数一起配对使用,free函数的参数是之前mallloc函数返回的地址(指针),该函数释放之前malloc函数分配的内存,因此,动态内存分配的存储期是从动态内存分配函数malloc(或其他)到f调用ree函数释放内存为止,涉嫌malloc和free函数管理着一个内存池。

每次调用malloc分配内存给程序使用,每次调用free函数把内存空间归还给内存池中,这样便可以重复使用这些内存,free函数的参数应该是一个指针,指向由malloc函数分配的一块内存,不能用free函数释放通过其他方式(如 :声明一个数组),分配的内存,malloc函数和free函数的原型都在stdio.h头文件中。

作者:Mr_Li_

另外的话为了帮助大家,轻松,高效学习C语言/C++,我给大家分享我收集的资源,从最零基础开始的教程到C语言项目案例,帮助大家在学习C语言的道路上披荆斩棘!可以来我粉丝群领取哦~

C语言/C++编程学习视频分享:

 C语言/C++编程学习书籍分享:

 整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)

(↓↓↓↓↓)

以上是关于零基础学C语言内存知识总结:realloc函数和free函数的主要内容,如果未能解决你的问题,请参考以下文章

零基础学C语言知识总结十一:C语言的内存四区

零基础学C语言知识总结十一:动态内存分配!

零基础学C语言知识总结七:函数知识总结

零基础学C语言知识总结七:函数知识总结

零基础学C语言知识总结十:指针及其相关知识

零基础学C语言知识总结十:二级指针指针数组和指向函数的指针