柔性数组的详解及C/C++内存分配区域的划分解析

目录

 一、C/C++内存分配区域的划分

        C/C++中程序内存区域划分图解

二、柔性数组

        1.柔性数组的定义

        2.柔性数组的特点

        3.柔性数组的使用

        4.柔性数组的替代实现

        5.柔性数组的优势


 一、C/C++内存分配区域的划分

        我们知道在我们代码编译和执行时会占用系统空间,那系统是怎么样划分并处理这些数据的呢?

        C/C++中程序内存区域划分图解

                在系统编译运行代码时将系统内存区域划分为下面几个区域:

                1.栈区 (stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

                2.堆区 (heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。分配方式类似于链表。

                3.数据段(静态区)(static):存放全局变量、静态数据。程序结束后由系统释放。

                4.代码段:存放函数体(类成员函数和全局函数)的二进制代码。

                5.内核空间:系统运行空间,用户不能进行读写。

                6.内存映射段:存放文件映射、动态库、匿名映射的空间。

        我们相对要关注的是栈区、堆区、静态区和代码段这四个划分空间。

我们下面拿一段代码划分一下它们所储存的区域:

         可以看到这段代码的全局变量(GlobalVariable)和静态变量(staGlobalV、StaticL)都储存在静态区(数据段)中,局部变量(a、h、arr、p、ptr、ptr1、ptr2)都存放在栈区中,而arr、p存放的字符串都放在代码段上,最后malloc等管理开辟动态内存的函数开辟的空间都存放在堆区中。

二、柔性数组

        也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。

        1.柔性数组的定义

                >C99中,结构体中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员。

        如:

struct B
{
	int k;
	double L;
	int arr[];//柔性数组
};

           或者:

struct B
{
	int k;
	double L;
	int arr[0];//柔性数组
};

        注:因为编译器的不同,创建柔性数组时有的是在【】中给0值,有的则是不给值。

        2.柔性数组的特点

                >结构中的柔性数组成员前面必须至少一个其他成员(一个结构体不可以只含一个柔性数组)。

                >sizeof返回的这种结构大小不包括柔性数组的内存。

                        例:

                >包含柔性数组成员的结构体用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。

如果我们直接创建一个含柔性数组的结构体实际上它的内存是不包含该柔性数组的:

                        如该结构体a只有一个int类型a成员的空间(这时arr柔性数组是放不下任何数据的):

        3.柔性数组的使用

                当我们要使用柔性数组时要手动用malloc(calloc当然也可以)函数给结构体分配空间,分配的空间不仅仅是柔性数组的大小还要加上前面成员的空间:

                 当然柔性数组嘛,最重要的还是体现在一个“柔”字,我们还可以在释放其内存之前将其扩容:

struct B
{
	int k;
	int arr[0];//柔性数组
};
int main()
{
	struct B* p = (struct B*)malloc(sizeof(struct B) + sizeof(int) * 4);
	if (p == NULL)
		return 1;
	/*
	省略一些对该结构体的使用.......
	*/


	//扩容
	struct B* ptr = (struct B*)realloc(p, sizeof(struct B) + sizeof(int) * 10);
	if (ptr != NULL)
		p = ptr;
	else
		return 1;
	/*
	省略一些对该结构体扩容后的使用.......
	*/

	free(p);
	return 0;
}

        4.柔性数组的替代实现

                当然我们也可以用指针来替代柔性数组的实现:

struct B
{
	int k;
	int *ptr;
};
int main()
{
	struct B* p = (struct B*)malloc(sizeof(struct B));
	if (p == NULL)
		return 1;
	p->ptr = (int*)malloc(sizeof(int) * 5);
	/*
	省略一些对该结构体的使用.......
	*/


	//扩容
	int *pp = (int*)realloc(p->ptr,sizeof(int) * 10);
	if (pp != NULL)
		p->ptr = pp;
	else
		return 1;
	/*
	省略一些对该结构体扩容后的使用.......
	*/

	free(p->ptr);
	p->ptr = NULL;
	free(p);
	p = NULL;
	return 0;
}

                但是要注意的是用int*类型指针开辟空间和结构体所开辟的空间不是同一空间,所以要使用两次free函数来进行释放。

        5.柔性数组的优势

                <1>减少内存碎片的产生,提高内存利用率。

        在上述指针替代柔性数组实现和直接使用柔性数组相比,指针替代实现开辟两块不同的空间,会让内存之间有间隙,不利于内存的利用。

                <2>方便动态内存释放。

        指针替代的实现要两次分别释放不同的空间,而柔性数组只需要一次,显然更加方便。

                <3>有利于访问速度

        访问连续的空间可以比访问不连续的空间速度快(虽然效果微乎其微)。


        今天又要和各位看客说再见啦,欢迎各位在评论区留言。如果本博客解决了您的一些问题,可以点一个赞哦,博主持续更新中~

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

1e-12

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值