动态存储管理
我们常见的静态开辟方式有:
int a = 10;
char arr[20] = {0};
这些是在栈区开辟,空间开辟大小是已知的,且数组在声明时必须指定长度。但对于一些只有在运行时才能知道所需空间的情况,(如输入一个数n后再开辟数组a[n]),则上述开辟方式不能满足,因此,有了动态存储来解决此问题。
malloc
自由存储区:**堆(heap)**开辟
void* malloc (size_t size);
- 申请的为一块连续可用的空间,返回为指针;
- 开辟成功,返回一个指向开辟好的空间的指针;开辟失败,返回一个NULL指针;
- 返回值为void*,根据需求自己决定开辟空间类型。
free
void free (void* ptr);
free函数是用来释放开辟的内存。
//申请空间,判断是否为空
void main()
{
int n;
scanf("%d", &n);
int *arr = (int *)malloc(sizeof(int) * n); //按需分配内存
if (NULL == arr)
{
printf("Out Of Memony.\n");
return;
}
for (int i = 0; i < n; i++)
{
arr[i] = i + 1;
printf("%d\n", arr[i]);
}
free(arr); // free再次访问arr属于非法使用
}
- 释放空间 ! = 释放指针
- free为释放空间,相当于回收了使用权,但指针还指向原先地址,变为野指针
- 释放完毕后(空间)要给指针赋空,p=NULL
- 自己申请的空间只能释放一次,不能对已释放的空间再次执行释放指令
- free只能在mallloc使用
错误案例:
void main()
{
int *p = (int *)malloc(sizeof(int)* 25);
free(p);
for (int i = 0; i < 25; i++)
{
p[i] = i; //非法访问
printf("%d\n", p[i]);
}
}
calloc
void *calloc(size_t num,size_t size) ;
功能:
- 为num个大小为size的元素开辟一块空间,并把每个字节初始化为0;相当于malloc+初始化为0.
realloc
void *realloc(void *memblock,size_t size) ;
功能:
- 对动态开辟的内存大小做灵活的调整。
memblock:要调整的内存地址
size:调整之后的新大小
注意:
- 若扩展的空间后面没有足够大的空间,则在堆上寻找更大的空间,拷贝数据,重新将指针指向新的空间
- 若第一个参数为空NULL时,则相当于malloc
- 若申请失败,则返回空NULL
内存泄漏和柔型数组
内存泄漏:
未释放空间或者没执行释放语句就返回退出。
动态开辟的空间一定要正确释放。
柔型数组:
C99中,结构中最后一个元素允许是未知大小的数组为柔型数组(不能单独存在)。
typedef struct test
{
char a;
int b;
double c;
char arr[0]; //柔性数组成员,不占空间
}test;
void main()
{
printf("size = %d\n", sizeof(test));
char str[] = "hello";
test t;
printf("str = %s\n", t.arr); //可以打打印出,但存在乱码
}
特点:
- 结构中柔型数组成员前面必须至少有一个其他成员;
- sizeof返回这种结构大小不包含柔型数组成员,即不占内存;
- 含有柔性数组成员的结构可以用动态分配,分配时应大于结构体的大小,这样可以适应柔型数组的预期大小。