版权声明:本文为博主原创文章,未经博主允许不得转载 https://blog.csdn.net/qq_42719751/article/details/89295186
为什么要进行动态内存管理?
普通的内存开辟方式有下面两种:
int val = 1;//在栈空间上开辟4个字节的空间
char array[10] = {0};//在栈空间上开辟10个字节的空间
但是,上面开辟空间的方式有缺陷:
- 开辟出来的空间大小是固定的;
- 数组在声明时,必须指定数组的长度,它所需要的内存在编译时分配;
所以,如果我想要灵活的申请空间,上面的方法显然不能满足,这是就需要利用动态内存开辟的方式来申请空间了。
进行动态内存管理的几个函数
开辟空间的函数
1.malloc()函数
函数原型:
void* malloc ( size_t size );
malloc函数的作用就是在堆上申请一块连续可用的空间,并返回指向这片空间地址的指针。
在使用malloc函数时需要注意的地方:
- 如果开辟成功,则返回一个指向开辟好空间的指针。
- 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
- 返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
- 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
2.calloc()函数
函数原型:
void* calloc ( size_t num, size_t size );
- num:要分配的元素个数;
- size:每个元素的大小;
calloc函数的功能与malloc函数的功能相同,都是用来在堆上申请空间的。不同的地方是:
calloc函数申请出来的空间会初始化为0 ;
除此之外,和malloc一样。
3.realloc()函数
函数原型:
void* realloc ( void * ptr, size_t size );
- ptr是要调整的内存的地址;
- size是调整之后内存的大小;
- 返回值为调整之后的内存的起始空间位置;
realloc函数的也是用来在堆上申请空间的,但是realloc函数使动态内存管理更加的灵活。
realloc函数可以在已经申请好的内存空间上在追加内存空间。
在realloc函数申请内存空间时有两种情况:
- 原有空间后有足够大的空间;
此时直接在原空间的后边追加空间,返回原有空间的首地址; - 原有空间后的空间不够所要追加的空间大小;
在对空间上重新找一块大小合适的连续空间,将原空间的内容拷贝一份,保存到这块大小合适的连续空间中,返回这块大小合适的空间的首地址;
上面三个申请空间的函数有个必须要注意的地方:
- 使用时,返回值要强转;
- 使用这三个函数时,要包含stdlib,h头文件;
释放内存空间的函数
4.free()函数
函数原型:
void* free ( void* ptr ) ;
free函数的作用是:释放由malloc函数,calloc函数,realloc函数动态开辟的内存空间;
需要注意:
动态申请的内存空间,必须释放,如果不释放,会产生内存泄漏;
常见的动态内存错误
- 对空指针的解引用;
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
- 对动态开辟空间的越界访问;
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);
}
- 对非动态开辟内存使用free释放;
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}
- 使用free函数释放动态开辟内存的一部分;
void test()
{
int * p = (int*) malloc (100);
p++;
free(p);//p不再指向动态内存的起始位置
}
- 对同一块动态内存多次释放;
void test()
{
int *p = (int*) malloc(100);
free(p);
free(p);//重复释放
}
- 动态开辟内存忘记释放(内存泄漏);
void test()
{
int* p = (int*) malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main ()
{
test():
return 0;
}
keep Running