C语言高阶【2】--动态内存管理【2】--柔性数组(这是个全新的知识点,不想了解一下吗?)

本章概述

  • 柔性数组
  • 总结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》在这里插入图片描述
每章一句一鸣从此始,相望青云端。感谢你能看到这里,点赞+关注+收藏+转发是对我最大的鼓励,咱们下期见!!!

上一篇:[Redis][集群][下]详细讲解


下一篇:工业物联网的伦理和社会影响