首先我们知道,在c/c++中内存区域的划分
(画的真丑)
一般定义的变量在栈中,动态内存分配(malloc,calloc,realloc)在堆中,static修饰的变量存放在静态库中。
接下来先简单看一下柔性数组:
1.结构中的柔性数组成员前面必须至少一个其他成员
2.sizeof返回的这种结构大小不包括柔性数组内存
3.包含柔性数组成员的结构用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
三句话看起来有点长但其实举个例子很好理解,话不多说,先定义:
#include<stdio.h>
#include<stdlib.h>struct stu {int n; //结构中的柔性数组成员前面必须至少一个其他成员int a[]; //柔性数组a[]
};int main()
{printf("%d\n", sizeof(struct stu));//输出结果为:4 sizeof返回的这种结构大小不包括柔性数组内存 struct stu* p = (struct stu*)malloc(sizeof(struct stu) + sizeof(int) * 10);//假设我们希望a[]可以存储十个整形数据 //包含柔性数组成员的结构用malloc()函数进行内存的动态分配,//并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小if (p == NULL){return 1;}free(p);p = NULL;return 0;
}
简单画个图,应该是这样子的:
既然空间都是malloc出来的,那就可以调整了,这就体现柔性的特点
于是:
别急别急,我们先看看内存中的效果
p->n = 10;int i = 0;for (i = 0; i < 10; i++) {p->a[i] = i;}
要是内存不够,我们只需要:
struct stu* ps=(struct stu*)realloc((struct stu*)sizeof(struct stu)+sizeof(int)*20)
//增加20个int
if(ps!=NULL)
{P=PS;
}
是不是跟用指针一样?简单一看确实一样。
别急,我们先说说realloc
我们知道realloc申请内存是这样子的:
1.当后面内存足够大时,直接申请到。
2.当后面内存不够时,另找一段区域,将原本的内存区拷贝过去,再加上新申请的内存,并且释放原来的内存。
3.实在没内存给你用了,返回空指针。
我们再看看用指针的效果
#include<stdio.h>
#include<stdlib.h>struct stu {int n; int *a;
};int main()
{struct stu *p=(struct stu*)malloc(sizeof(struct stu));if (p == NULL){return 1;}return 0;
简单画个图,应该是这样子的:
a指针要指向一个空间,我们又要开辟一个:
p->a =(int *)malloc(sizeof(int));if(p->a==NULL){return 1;}
我们看看内存中的效果
(为了区别上一张,n没有赋值。)
看上去一摸一样,但是当我们要增加内存时:
int *ps= (int*)realloc(p->a,sizeof(int)*10);if (ps != NULL){p->a = ps;}
又多出一个指针,有点晕了,这还没完,当我们使用完,释放内存时,还需要先把新增内存段释放,再释放原本的内存段,要是先回收了原本的空间,那么新增的空间指针都找不到了,当场就是内存泄漏,所以我们不得不:
free(p->a);p->a = NULL;free(p);p = NULL;
麻烦是麻烦点,可毕竟也达到柔性数组的效果了,那大佬们就喜欢指针咋办。
其实虽然达到了效果,但回想一下,我们用指针两次开辟空间,再想想上面所说的realloc开辟空间的方法,是不是想到了什么。没错,要是全部都是原本的空间后面有足够的内存给你开辟还好说,可是哪能这么好,毕竟在操作系统眼里你就是个要饭的,就怕哪次后面没有足够的内存,随便在堆区找一块连续的满足要求的开辟,在内存空间中造成大量内存碎片,这些内存碎片不大不小的,再次被利用的可能性比较低,使内存使用效率变低,更增大开辟失败几率(可能有这么多内存,但都是碎片化不连续的,用不了嘛),而柔性数组就解决了这个问题,所以说柔性数组的使用还是有必要的。
本人浅显的一些理解,有不到位或者错误的地方欢迎大家指出。