本章概述
- 柔性数组
- 总结C/C++中程序内存划分
- 彩蛋时刻!!!!
柔性数组
数组这个东西,我想大家应该都不陌生了吧。但是,柔性数组这个东西可能你是第一次听说。
- 柔性数组概念:在C99之前是没这个东西的,在C99之后就有这个东西了。在C99中规定,结构体中的最后一个成员是大小未知的数组,那么这个数组就叫做柔性数组。进行结构展示:
struct st_type
{
int i;
int a[0]; //柔性数组成员 ,0就代表没有元素
};
// 有些编译器还可以这样写
struct st_type
{
int i;
int a[]; //柔性数组成员
};
-
柔性数组的特点:
- 1 .结构体是有大小的,由于我们的柔性数组大小是未知的。所以,在柔性数组之前,必须至少有一个知道大小的成员。
- 2.我们计算含有柔性数组的结构体的大小时,所计算的大小不包含柔性数组,因为它大小未知。进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int i;
int arr[];
};
int main()
{
printf("%d\n",sizeof(struct stu));
return 0;
}
结果运行图:
-
柔性数组的使用:柔性数组的使用要和动态内存函数一起使用。我们一般用
malloc
进行空间的开辟。我们为这个含有柔性数组的结构体,开辟空间的大小至少为其它成员的大小。 进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int i;
int arr[];
};
int main()
{
struct stu* p = (struct stu*)malloc(8*sizeof(int)); //前4个字节给inti,
//后4个字节给int arr[]
if (p == NULL)
return 1;
p->i = 100;
printf("%d\n",p->i);
int i = 0;
for (i = 0; i < 4; i++)
{
p->arr[i] = i;
}
for (i = 0; i < 4; i++)
{
printf("%d ",p->arr[i]);
}
free(p);
p = NULL;
return 0;
}
结果运行图:
我们还可以模拟柔性数组,达到同样的效果,进行代码展示:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
struct stu
{
int i;
int*p;
};
int main()
{
struct stu* pp = (struct stu*)malloc(sizeof(struct stu));
pp->p = malloc(4*sizeof(int));
int i = 0;
for (i = 0; i < 4; i++)
{
*((pp->p)+i) = i;
}
for (i = 0; i < 4; i++)
{
printf("%d ", *((pp->p) + i));
}
free(pp->p);
free(pp);
pp->p = NULL;
pp = NULL;
return 0;
}
结果运行图:
这个模拟的代码要注意,我们最后释放两次空间,第一次是p的空间,第二次是pp的空间,一定要先释放p,再释放pp。因为p是在pp之后才创建的空间,pp是p的爸爸,你要是把pp释放了,p就没有了,就无法释放p的空间了。如图所示:
-
柔性数组的优点:
- 1.方便我们释放内存,我们直接开辟好空间后,就会返回这个空间的地址,我们释放空间的时候,就可以直接通过这个地址直接释放。但是,如果按照我们的模拟代码的话,就需要释放两次,而且还要考虑释放顺序,这就很不方便。
- 2.能够提升一定的运行效率。我们直接用柔性数组开辟出来的空间是连续的。但是,我们模拟的代码开辟的空间,里面存在内存碎片。我们为结构体开辟了一块空间,里面还为int i 和int*p都各自开辟了一块空间,而在它们之间还有空白的(多余)内存空间没用到,就出现了内存碎片。如图所示:
我们在这个结构体里面创建的成员比较少,内存碎片显示的不是很明显。但是,当我们创建的较多时,内存碎片就会显示的比较明显。
总结C/C++中程序内存划分
关于内存的划分以及各个部分存储什么数据,我们都已经讲过了。今天就给大家展示一下它们的对应关系,如图:
对于内核空间,是操作系统操作的,我们程序员是无法进行访问的。为什么栈区和堆区会有向下和向上的箭头呢?其实,栈区和堆区的空间大小是灵活调整的。栈区多一点,堆区就少一点。反过来,堆区多一点,栈区就少一点。无论怎么变化,栈区和堆区的总和不变。 咱们以前讲过,静态区里面存放的是全局变量和常量。其实,划分细点就是分为数据段和代码段。数据段存放的全局变量和静态数据(static
修饰的数据),代码段存放的是常量和编译后可执行的二进制代码。
彩蛋时刻!!!!
PLAY歌曲:《Shots》
每章一句:一鸣从此始,相望青云端。
感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!