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

「零基础学C语言」内存知识总结:realloc函数和free函数,本文转载自C语言编程头条作者。

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头文件中。

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

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注