1.静态内存与动态内存的区别
1.1静态内存
- 在栈区开辟
- 出作用域时释放
- 可管理的内存大小固定
1.2动态内存
- 在堆区开辟
- 释放由free函数执行:不主动释放会造成内存泄漏
- 可管理内存的大小可变
2.创建动态内存的方式
2.1malloc创建动态内存
2.1.1函数原型
void* malloc(size_t size);
2.1.2函数功能
- 在堆区开辟一块连续的size字节的空间,如果开辟成功,返回首地址;开辟失败,返回NULL指针;
2.1.3注意事项
- 返回值为void*,因此需要使用者强制类型转换为指定类型
- 如果size = 0,行为标准未定义,由编译器决定
- malloc函数不初始化
2.2calloc创建动态内存
2.2.1函数原型
void* calloc(size_t num, size_t size);
- num:开辟的元素个数
- size:每个元素的字节大小
2.2.2函数功能
- 在堆区创建一块大小为num*size字节的连续的内存空间
2.2.3注意事项
- 返回值为void*, 因此需要使用者强制类型转换为指定类型
- 如果参数为0,则标准未定义,由编译器决定
- calloc函数会初始化指定空间为0
2.2.4malloc与calloc的区别
- 函数参数
- calloc函数会初始化
2.2.5总结
- 什么时候用malloc与calloc函数,决定空间是否初始化
2.3realloc创建动态内存
2.3.1函数原型
void_ realloc(void_* ptr, size_t size);
- ptr:要调整的内存地址
- size:调整后的大小
2.3.2函数功能
- 扩大或者缩小动态内存的大小
2.3.3注意事项
- realloc函数开辟空间可能会改变原地址的位置
- 开辟失败返回NULL,
- 开辟成功两种:
- 原地址有足够的空间:返回地址为原地址
- 原地址没有足够的空间:返回地址不是原地址,
2.3.4realloc与malloc的关系
- 当realloc的参数ptr为NULL时,与malloc的功能相同
2.4free释放动态内存
2.4.1函数原型
void free(void* ptr);
2.4.2函数功能
- 释放动态内存
2.4.3注意事项
- 如果参数为NULL,则free什么都不做
- 如果ptr指向的空间是在栈区,则行为未定义
3.使用动态内存的常见错误
3.1对NULL指针解引用
int main(void)
{
int *ptr = (int*)malloc(40);
*ptr = a; //此时malloc有可能创建失败,返回NULL,不可解引用
free(ptr);
ptr = NULL;
return 0;
}
//正确版本
int main(void)
{
int *ptr = (int*)malloc(40);
if (p == NULL) //p=NULL时,不执行解引用操作
{
return 0;
}
else
*ptr = a;
free(ptr);
ptr = NULL;
return 0;
}
3.2对动态内存的越界访问
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
int i = 0;
for (i=0; i<10; i++)
{
*p = i+1; //开辟20个字节,访问了40个字节,越界访问
}
free(p);
p = NULL;
return 0;
}
3.3多次释放动态空间
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
free(p);
free(p); // ----连续两次释放错误
return 0;
}
//-----------解决办法
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
free(p);
p = NULL; //由于参数未NULL时,free什么都不做,所以释放后应该加p=NULL,防止重复释放
free(p);
return 0;
}
3.4释放非动态内存
int main(void)
{
int a = 0;
free(&a); //错误,不可释放非动态内存
return 0;
}
3.5内存泄漏
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
//不释放,会导致内存泄漏
return 0;
}
3.6释放部分动态内存
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
int i = 0;
for (i=0; i<5; i++)
{
*p = i;
p++; //由于此时p已经改变,故只free一部分空间
}
free(p);
p = NULL;
return 0;
}
//改正
int main(void)
{
int* p = (int*)malloc(20);
if (p = NULL)
return 0;
int i = 0;
int* ptr = p; //保存动态空间的起始地址
for (i=0; i<5; i++)
{
*p = i;
p++;
}
free(ptr);
ptr = NULL;
return 0;
}