- (一)三种方式
- (二)动态内存函数
- 1.malloc和free
- 2.calloc
- 3.realloc
- (三)常见错误
- 1.对空指针进行解引用
- 2.对动态内存开辟的越界访问
- 3.与free有关的错误
- free释放非动态开辟内存
- free释放动态内存空间的一部分
- free对同一块空间多次释放
- 动态开辟内存忘记释放/内存泄漏
内存中存在三种空间,分别是栈区(用来存放局部变量和函数形式的参数),堆区(动态内存分配),静态区(存放全局变量和静态变量)
(二)动态内存函数 1.malloc和free malloc是申请开辟动态内存分配空间函数,头文件为
free是释放内存空间函数,和malloc一起使用。
#include#include int main() { int* p = (int*)malloc(40); //开辟内存空间 if (p == NULL)//开辟失败 { return -1; } for (int i = 0;i < 10;i++) { *(p + i) = i; } free(p); //释放内存空间 return 0; }
在内存中显示如下,
2.calloccalloc也是开辟内存空间函数,MSDN上解释为void *calloc( size_t num, size_t size );,与malloc函数不同,calloc函数在堆区开辟空间后初始化为0,其中,num为元素的个数,size为每个元素的字节长度。
#include3.realloc#include int main() { int* p = (int *)calloc(10,sizeof(int)); //开辟内存空间 if (p == NULL)//开辟失败 { printf("%d", strerror(errno)); return -1; } for (int i = 0;i < 10;i++) { printf("%d ", *(p + i)); //输出为0 0 0 0 0 0 0 0 0 0 } free(p); //释放内存空间 return 0; }
realloc也是内存开辟函数,要在原有开辟的基础上再次开辟,相当于增加空间,在MSDN上解释为void *realloc( void *memblock, size_t size );,头文件为
#include#include #include int main() { int* p = (int *)calloc(10,sizeof(int)); //开辟内存空间 if (p == NULL)//开辟失败 { printf("%d", strerror(errno)); return -1; } int* ch = (int*)realloc(p, 20 * sizeof(int)); if (ch != NULL) { p = ch;//开辟成功 } else { return -1;//开辟失败 } for (int i = 10;i < 20;i++) { *(p + i) = i; } for (int j = 0;j < 20;j++) { printf("%d ", *(p + j) ); } free(p); //释放内存空间 return 0; }
realloc函数在内存中开辟空间的形式如下,如果后续空间足够大,那么就直接开辟;如果后续空间不足,那么将向后寻找直至找到足够开辟空间的位置,如果找不到,那么开辟失败,返回NULL。如图所示,
(三)常见错误 1.对空指针进行解引用#includeint main() { int* p = (int*)malloc(20); *p = 20;//error return 0; }
如果开辟内存空间失败,那么p为空指针,无法进行操作。应该加判断,
if (p == NULL)
{
return -1;
}
else
{
*p = 20;
}
2.对动态内存开辟的越界访问
#includeint main() { int* p = (int*)malloc(5*sizeof(int)); if (p == NULL) { return -1; } for (int i = 0;i < 10;i++)//error { *(p + i) = i;//赋值 } for (int j = 0;j < 10;j++) { printf("%d ", *(p + j));//打印 } free(p); return 0; }
在这里malloc函数开辟的空间为五个整型的大小,在赋值时,却对十个整型进行赋值,导致动态内存开辟的越界访问,运行显示错误。
3.与free有关的错误 free释放非动态开辟内存#includeint main() { int a = 10; int* p = &a; free(p);//error p = NULL; return 0; }
这里的p开辟的地址被放在栈区,而free是对堆区的内存进行操作,运行报错。
free释放动态内存空间的一部分#includeint main() { int* p = (int*)malloc(10 * sizeof(int)); if (p == NULL) { return -1; } for (int i = 0;i < 10;i++) { *p++ = i; } free(p); return 0; }
free指向的应该是释放空间的头地址,p++过后,p已经不再指向起始地址了,运行产生错误。
free对同一块空间多次释放#includeint main() { int* p = (int*)malloc(10 * sizeof(int)); free(p); free(p); return 0; }
两次释放p的空间,error,可以在每次释放之后给p赋值为NULL以避免这种错误。
动态开辟内存忘记释放/内存泄漏动态开辟内存或通过free手动释放或者在程序结束时进行自我回收。如果不进行free释放空间,程序一直运行且不结束的话,则会存在内存泄漏,除非程序重启。



