我们目前学过的主要的两种内存开辟方式
一种是直接声明变量 比如 int a=0;
另一种是声明数组 比如 char arr[5]={0};
但是这两种方式都有缺点,
1.空间开辟大小是固定的。
2.数组在申明的时候,必须指定数组的长度,数组空间一旦确定了大小不能调整
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知
道,那数组的编译时开辟空间的方式就不能满足了。
C语言引入了动态内存开辟,让程序员自己可以申请和释放空间,就比较灵活了。
我们先来看第一个函数malloc
1,malloc
malloc
void* malloc (size_t size);
1.这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针,申请空间的大小单位是字节。
2.如果开辟成功,则返回一个指向开辟好空间的指针。
3.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
4.返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自
己来决定。
5.如果参数size为0,malloc的行为是标准是未定义的,取决于编译器。
6.malloc返回的指针是void*类型的,因此我们再使用之前要强制类型转换成我们要用的类型
7.malloc的头文件是#include<stdlib.h>
8.malloc开辟的空间是位于堆区的
栈区:用于存放局部变量,局部数组,和形式参数 |
堆区:动态内存;malloc,realloc等等 |
静态区:全局变量和static修饰的静态变量 |
9.我们使用malloc申请的空间需要释放那就涉及到另外一共函数了,也就是free, 当然如果你没释放,当程序跑完,系统也会将其回收。
free
void free (void* ptr);
1.free函数用来释放动态开辟的内存。
2.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
3.如果参数ptr是NULL指针,则函数什么事都不做。
4.malloc和free都声明在stdlib.h头文件中。
5一旦free后的指针是无法使用的,是野指针,非常危险,所以野指针我们要将其至成空指针
6.free无法对同一块空间进行多次释放,第二次释放的就是野指针了。
7.malloc,calloc等函数的申请一定要进行free释放
8.free无法释放部分空间,申请多少空间就得释放多少空间
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int* arr[10] = { 0 };
int a = 1;
int* add = (int*)malloc(10 * sizeof(int));
if (add ==NULL)
{
perror("malloc");
}
for (int i = 0; i < 10; i++)
{
*(add+i) = i+1;
a++;
}
for (int i = 9;i >= 0; i--)
{
printf("%d\n", *(add + i));
}
free(add);//正确用法
free(arr);//指向的空间不是动态开辟的,那free函数的行为是未定义的.
add=NULL;//防止野指针被使用
return 0;
}
malloc和free的还有一给好处就是可以手动选择变量的作用域,不用了就直接free.
2.calloc
calloc
void* calloc (size_t num, size_t size);
函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节初始化为0。
与函数malloc的区别只在于calloc会在返回地址之前把申请的空间的每个字节初始化为全0.
malloc和calloc的区别主要在于以下几个方面:
函数原型和参数
malloc : void *malloc(size_t size) 123
calloc : void *calloc(size_t numElements, size_t sizeOfElement)
参数差异 :
malloc 只接受一个参数,即需要分配的内存空间的大小(以字节为单位)。
calloc 需要两个参数,第一个参数是需要分配的元素的个数,第二个参数是每个元素的大小。
内存初始化
malloc : 分配的内存空间中的内容是随机的垃圾数据。
calloc : 分配的内存空间会被初始化为0。
返回值差异
malloc : 返回一个指向分配内存区域的指针,该区域的内容不可预知(通常包含垃圾数据)。
calloc : 返回一个指向分配内存区域第一个元素的指针,该区域的内容为0。
性能
calloc : 由于需要额外的初始化步骤,在分配大块内存时比 malloc 慢一些。
malloc : 适合用于一次性分配较小的内存块,而 calloc 更适合用于分配大量元素的数组,并且需要所有元素初始化为0。
3.realloc
realloc
void* realloc (void* ptr, size_t size); realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的使用内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小的调整。 ptr是要调整的内存地址 size 调整之后新大小 返回值为调整之后的内存起始位置。 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。 realloc在调整内存空间的是存在两种情况: 情况1:原有空间之后有足够大的空间 情况2:原有空间之后没有足够大的空间
情况1
当是情况1的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
也称原地扩容
情况2
当是情况2的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合大小的连续空间来使用。这样函数返回的是一个新的内存地址。
也称异地扩容
情况三:开辟失败,返回空指针
1.因为有上面三种情况所以我们在接受realloc的返回指针时,要用一共新的变量去接受,如果用malloc或者calloc的返回值接收会导致新的没开辟好,还把原来的那块空间搞丢了!
2.realloc只能作用于动态开辟的空间块,不是随便一块空间就行。
3.realloc并不会将初始化成0,和malloc一样是随机值。
4.如果realloc是异地扩容,realloc会将接手原来那块内存的释放,不需要你再进行free释放了,只用对realloc异地扩容的那段新内存进行free了,即对realloc的返回值进行free
5.realloc也可以开辟空间
int*ptr=(int*)reallloc(NULL,10*sizeof(int));
int*ptr=(int*)mallloc(10*sizeof(int));
是等价的
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int*add = (int*)malloc(10 * sizeof(int));
if (add==NULL)
{
perror("malloc");
}
int*sta = (int*)realloc(add, 20*sizeof(int));
//先将realloc返回值放到sta中,不为NULL再放到add中
if (sta!= NULL)
{
add= sta;
}
for (int i = 0; i < 20; i++)
{
{
if (add != NULL)
{
*(add + i) = i + 1;
}
}
}
for (int i = 0; i < 20; i++)
{
{
if (add!= NULL)
printf("%d\n", *(add+ i));
}
}
free(add);
add = NULL;
return 0;
}
标签:malloc,管理,int,realloc,free,add,动态内存,空间
From: https://blog.csdn.net/Starry_tsx/article/details/142315017