提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
前言
这是动态内存管理的第二部分,会将剩下的常见动态内存错误和柔性数组讲完。
一、常见动态内存错误
1.对空指针的解引用操作
int* p = (int*)calloc(5,sizeof(int));
*p = 20;//如果p是NULL空指针就会有问题
free(p);
也就是开辟空间失败会返回空指针,但是我们没注意此时p为空指针,把p解引用了,就会出现错误。
所以我们使用动态内存函数时,开辟空间后一定要判断返回的是不是空指针,否则很容易出错。
正确代码如下:
int* p = (int*)calloc(5,sizeof(int));
if (p == NULL)
{
printf("%s\n", strerror(errno));
return 1;
}
*p = 20;
//释放
free(p);
p = NULL;
2.对动态开辟空间的越界访问
比如我们开辟了4个整形的空间,但是却访问了5个。
此情况一般出现在数组中,只要稍加注意即可。
3.对非动态开辟内存进行释放
void test()
{
int a = 10;
int *p = &a;
free(p);
}
如以上情况,p并不是动态开辟来的,但是却释放了它,自然就会出错了。
4.释放动态内存开辟的一部分
free函数在使用时一定要传动态开辟内存的起始地址,否则就会出错。
void test()
{
int *p = (int *)malloc(100);
p++;
free(p);//p不再指向动态内存的起始位置
}
上面代码显然就会出现问题,所以要注意。
5.对同一块内存进行多次释放

如果我们释放过这块内存了,但是我们没注意,又释放了一次,此时就会出现错误。
但是,如果我们第一次释放的时候将内存置空了,那就不会出错了,因为free函数里如果是空指针,那函数什么也不做,相当于没有。
下面就不会出错
6.动态开辟的内存忘记释放(内存泄漏)
mallc、calloc、realloc所申请的空间,如果不再使用,需要free释放。
如果不用free释放,程序结束后操作系统回收。
但是,如果既不用free释放,程序又不结束,就会浪费一块空间,即内存泄漏。
void test()
{
int *p = (int *)malloc(100);
if(NULL != p)
{
*p = 20;
}
}
上面的这个程序一直不结束,它申请的空间就一直不被释放就会出现内存泄漏,所以我们在使用时一定要释放内存,防止上面情况的出现。
二、柔性数组
1.柔性数组的概念
C99中,结构体的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。
2.柔性数组特点
1、结构中的柔性数组成员前面至少一个其他成员。
2、sizeof返回的结构体大小不包括柔性数组的内存。
3、包含柔性数组成员的结构用malloc函数进行内存的动态分配,并且分配的大小应该大于结构的大小,以适应柔性数组的预期大小。
分配内存如下:
struct S
{
int n;
char c;
int arr[];
};
int main()
{
struct S* ps =struct S* str=(struct S*) malloc(sizeof(struct S) + 10 * sizeof(int));
return 0;
}
扩建空间的方法:
struct S* str=(struct S*)realloc(ps, sizeof(struct S) + 20 * sizeof(int));
还有一种就是结构体指针扩建空间,代码如下:
struct S
{
int n;
char c;
int *arr;
};
int main()
{
struct S* ps =(struct S*) malloc(sizeof(struct S) );
if (ps == NULL)
{
perror("malloc");
return 1;
}
int* ptr =(int*) malloc(10 * sizeof(int));
if (ptr == NULL)
{
perror("malloc2");
return 1;
}
else
{
ps->arr = ptr;
}
//使用
ps->c = 'w';
ps->n = 100;
int i = 0;
for (i = 0; i < 10; i++)
{
ps->arr[i] = i;
}
//打印
for (i = 0; i < 10; i++)
{
printf("%d ", ps->arr[i]);
}
//扩容——调整arr的大小
int *ptr = (int*)realloc(ps->arr, 20 * sizeof(int));
if (ptr == NULL)
{
perror("realloc");
return 1;
}
else
{
ps->arr = ptr;
}
//释放
free(ps->arr);
ps->arr = NULL;
free(ps);
ps = NULL;
return 0;
}
使用柔性数组第一个好处:
方案1:malloc一次,free一次,容易维护空间,不易出错。
malloc次数少,内存碎片就少,内存的使用率就较高一些
方案2:
malloc两次,free两次,内存碎片就会增多,内存使用率会下降,维护难度加大,容易出错。
第二个好处:
有利于提高访问速度,连续的内存有利于提高访问速度,也减少内存碎片。