动态内存函数的介绍
内存的几个区域
malloc和free
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
malloc
void* malloc(szie_t size);
函数的返回值一定要做检查,查看是否申请成功。
动态内存的回收一般有两种,一种是程序结束后自动回收,另一种是手动回收。
free
void free(void* ptr);
free函数是专门用来做动态内存的释放和回收的。
malloc和·free都可声明在"stdlib.h"中,下面是我们来举一个例子
#include<stdlib.h>
int main()
{
int arr[10] = { 0 };//在栈上申请40个字节的空间
//动态内存开辟 堆区上
int* p = malloc(40);//希望把40个字节当成10个整形的数组
if (p == NULL)
{
printf("内存开辟失败\n");
return 1;
}
else//开辟成功
{
int i;
for (i = 0;i < 10;i++)
{
*(p + i) = 0;
}
for (i = 0;i < 10;i++)
{
printf("%d ", p[i]);
}
//手动释放内存
free(p);
p = NULL;
}
return 0;
}
calloc
calloc也用来动态内存的分配
void* calloc(size_t num,size_t size)
函数的功能是为num个大小为size的元素开辟一块空间,并且把空间的每个字节都初始化为0。
calloc会在返还地址之前把申请的空间的每个字节初始化全为0。
realloc
void* realloc(void*ptr ,size_t size);
ptr是要调整的内存大小地址
size调整之后新大小
realloc在调整内存空间时存在两种情况:
我们举个例子来看看malloc和realloc的使用
#include<string.h>
#include<errno.h>
int main()
{
//int arr[10];
//开辟一个连续的空间
//malloc开辟的空间不初始化
//malloc参数只有1个
//calloc开辟的空间是初始化的
//calloc参数有2个
int* p = (int*)calloc(10, sizeof(int));
if (p == NULL)
{
printf("%s/n", strerror(errno));
}
else
{
int i = 0;
for (i - 0;i < 10;i++)
{
printf("%d ", *(p + i));
}
//增加空间
int* ptr = (int*)realloc(p, 80);//调整空间大小
if (ptr != NULL)
{
p = ptr;
}
for(i = 0;i < 20;i++)
{
printf("%d ", *(p + i));
}
//释放
free(p);
p = NULL;
}
return 0;
}
常见的动态内存错误
1、对NULL指针的解引用操作
避免出现对malloc / calloc/ realloc函数的返回值做检测
int main()
{
int* p = (int*)malloc(INT_MAX);
//p是有可能为NULL指针的,当为NULL的时候,*p是非法访问内存
*p = 0;
}
2、对动态空间开辟的越界访问
int main()
{
int *p = (int*)malloc(10 * sizeof(int));
if (p = NULL)
{
return 1;
}
else
{
int i = 0;//越界
for (i = 0;i <= 10;i++)
{
*(p + i) = 0;
}
free(p);
p = NULL;
}
return 0;
}
3、对非动态开辟使用free释放
int main()
{
int a = 10;
int* p = &a;
free(p);
p = NULL;
return 0;
}
4、使用free释放一块动态开辟内存的一部分
int main()
{
int *p = (int*)malloc(10 * sizeof(int));
if (p = NULL)
{
return 1;
}
else
{
int i = 0;
//err
for (i = 0;i <= 10;i++)
{
*p++ = 0;
}
//释放
free(p);
p = NULL;
}
return 0;
}
5、对同一块动态内存多次释放
int main()
{
int *p = (int*)malloc(10 * sizeof(int));
if (p = NULL)
{
return 1;
}
else
{
int i = 0;
//err
for (i = 0;i <= 10;i++)
{
*(p+i) = 0;
}
//多次释放
free(p);
free(p);
p = NULL;
}
return 0;
}
6、忘记释放
忘记释放会存在内存泄漏的问题。
动态开辟的空间一定要释放,并且要正确释放。
c/c++程序内存的开辟
程序内存分配的几个区域
- 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些
存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有
限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。 - 堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似
于链表。 - 数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。
- 代码段:存放函数体(类成员函数和全局函数)的二进制代码