一.动态内存管理函数简介
1.malloc()函数
malloc()函数使用形式如下:
void* malloc (size_t size)
其作用是在内存的堆区中申请size个字节的空间(该空间的每一个bit位的值是随机的),并返回一个指向该空间起始位置的指针,如果申请失败则返回NULL指针。
例如:
int* p = (int*)malloc(10*sizeof(int));
指向内存申请40个字节空间,并返回一个被强制类型转换成int型的该空间起始位置的地址赋给int型的指针变量p。
2.calloc()函数
calloc()函数使用形式如下:
void* calloc (size_t num, size_t size)
其作用是在内存中的堆区为一个有num个元素的数组,每个元素是size个字节大小的数组申请空间(该空间的每一个bit位的值都被初始化为0),并返回一个指向该空间起始位置的指针,如果申请失败则返回NULL指针。
例如:
int* p = (int*)calloc(10, sizeof(int))
指向内存申请40个字节空间并把这块空间的所有内容全部初始化为0,然后返回一个被强制类型转换成int型的该空间起始位置的地址赋给int型的指针变量p。
因此calloc==malloc+初始化为0.
3.realloc()函数
realloc()函数的使用形式如下:
void* realloc (void* ptr, size_t size)
其作用是改变由ptr所指向的在内存中堆区的空间为size个字节大小
如果后面的空间足够大就扩容并返回原地址;
如果后面的空间不够大就新开辟一块空间,把旧空间的数据拷贝过来,再把旧空间释放,最后返回新开辟空间的起始地址;
如果realloc()开辟失败则返回NULL指针。
例如:
int* p = (int*)malloc(40);
int* ptr = (int*)realloc(p, 80);
这里realloc()函数的作用是通过指针p找到原来malloc()函数开辟的40个字节大小的空间,并将这块空间的大小调整为80个字节。然后返回被强制类型转换成int*型的该80个字节空间起始位置的地址并赋给指针ptr。
4.free()函数
free()函数的使用形式如下:
void free (void* ptr)
其作用是是释放之前由ptr指向的malloc(),calloc(),realloc()等函数在堆区申请的空间。无返回值。
例如:
int* p = (int*)malloc(10*sizeof(int));
free(p);
p = NULL;
这里free()函数释放了由指针p指向的malloc()函数申请的空间;注意此时p仍然指向那块空间,p也就成了野指针,所以需要将p置为NULL指针防止越界访问。
二.动态内存开辟常见的错误
1.对NULL指针使用解引用操作符
例如:
执行这段代码
void test()
{
int *p = (int *)malloc(INT_MAX/4);
*p = 20;//如果p的值是NULL,就会有问题
free(p);
}
会出现如下错误
此时malloc()函数申请空间失败返回NULL指针,没用对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);
}
执行这段代码,由于malloc()函数只申请了40个字节空间,当i为10时,会访问帝41个字节的内容造成越界访问。
3. 对非动态开辟内存使用free释放
void test()
{
int a = 10;
int *p = &a;
free(p);//ok?
}
由于a是再栈区开辟,指针变量p也是在栈区开辟;而free()函数只能释放在堆区开辟的空间,这样就会造成错误。
4.使用free释放一块动态开辟内存的一部分
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
由于p指向的是动态开辟内存的起始位置而p++后,p的值发生改变,此时free()函数释放的不是整个动态开辟内存,而是其的一部分,这就会造成程序错误。
5.对同一块动态内存多次释放
void test()
{
int *p = (int *)malloc(100);
free(p);
free(p);//重复释放
}
这里第一个free()函数已经将malloc()函数所申请的空间释放了,第二个free()函数再通过指针p去释放就会造成错误
6.动态开辟内存忘记释放(内存泄漏)
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
int main()
{
while(1)
{
test();
}
}
这段从代码中malloc()函数申请完空间后没有再释放,这就会造成内存泄漏,而在while()循环中随着malloc()函数申请空间的不断累积,内存会不断减小,最后会造成程序崩溃。