目录
一.为什么要用动态内存分配
二.malloc和free
二.1.malloc
二.2free
三.calloc和realloc
三.1calloc
三.2realloc
四.常见的动态内存错误
四.1对NULL指针的解引用操作
四.2对动态开辟空间越界访问
四.3对非动态开辟内存使用free释放
四.4使用free释放一块动态开辟内存的一部分
四.5对同一块动态内存多次释放
四.6动态开辟内存忘记释放
一.为什么要用动态内存分配
在我们需要存放数据的时候,我们往往是通过创建变量来向内存申请空间,比如:
int a;
char ch;
int arr[10];
局部变量在内存栈区申请一块空间,但程序运行起来申请的空间不能灵活改变,比如有些时候我们需要的空间是只有程序运行起来的时候才能确定,而创建变量来申请空间的方式显然不能满足我们的需求,于是C语言就规定了一些函数,能让程序员自己自由像内存申请空间的函数,下面让我们一一介绍。
二.malloc和free
二.1.malloc
malloc函数是向内存申请一定空间的函数,函数会返回这块空间的起始地址,看看C标准中hi如何定义的。
void* malloc(size_t size);
函数参数为需要申请内存的字节数,开辟的空间为内存中的堆区,如果申请成功,函数会返回这块空间的起始地址,如果申请失败,函数会返回一个空指针,因此我们在使用malloc需要注意一些事项。
注意事项:
1.使用之前需判断是否开辟成功,再使用这块内存。
int *p=(int *)malloc(sizeof(int));
if (p == NULL)
{
return 1;
}
如上,申请失败,则返回非正常结束
2.要用对应的数据类型指针去接收这个无类型的指针。
二.2free
free函数主要用于收回程序员开辟的内存空间,变量可以在程序结束时操作系统自动收回,但程序员申请的空间如果不自己收回,则会在程序结束时自动收回,但如果这是一个大工程,这块空间不需要的时候,没有自己收回,那么可能会导致内存泄漏,十分危险。
void free(void *ptr);
把申请的内存地址传给函数即可释放空间,如果传的是空指针,free函数不做任何操作。
如果不是指向函数分配的内存快,则为引起未定义行为。
三.calloc和realloc
三.1calloc
calloc函数和malloc函数很相似,只是calloc函数会将申请的空间都初始化为0.
void * calloc(size_t num,size_t size);
num为要分配的元素数,size为每个元素的字节大小,并将该字节内存快初始化为0,如果申请失败,返回空指针,和malloc函数一样,申请完之后需要判断是否申请成功,并在不需要这个内存块的时候及时free收回。
三.2realloc
realloc用于改变申请的内存块大小,如果程序员需要改变原来申请的内存块大小,那么realloc可以来实现。
注意:
1.函数可能会将内存块移到新地址,在接收时可以用中间指针变量接收,否则申请失败的时候,原指针会丢失这块内存。如:
int *p=(int *)malloc(sizeof(int));
int *s=(int *)realloc(sizeof(int)*5);
{
if(s!=NULL)
p=s;
}
2.申请新的内存空间会保留旧的内存空间的数据。
3.申请失败会返回空指针。
四.常见的动态内存错误
四.1对NULL指针的解引用操作
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
函数可能会申请不成功,使用之前应该判断是否为空。
四.2对动态开辟空间越界访问
void test()
{
int i = 0;
int *p = (int *)malloc(10*sizeof(int));
if(NULL == p)
{
exit(EXIT_FAILURE);
}
for(i=0; i<=10; i++)
{
*(p+i) = i;//当i是10的时候越界访问
}
free(p);
}
申请了多大的内存空间,就只能访问这块内存,不能越界访问其他内存空间
四.3对非动态开辟内存使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}
不能对非动态开辟内存使用free释放
四.4使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
使用动态内存开辟的时候,要将内存起始地址传给free释放
四.5对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
重复释放编译器会报错,动态内存开辟只需释放一次
四.6动态开辟内存忘记释放
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
test();
while(1);
}
动态内存开辟后忘记释放,会造成内存泄露,非常危险
总结
动态内存管理提高了程序员对内存使用的灵活性,同时也带来了一些风险,使用时需要十分注意。