C/C++中内存开辟与柔性数组

C/C++中内存的开辟

在C中,我们都知道有三个区:

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

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

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

但是其实要更加细分,区域可以分为:

C/C++程序内存分配的几个区域:

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

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

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

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

实际上普通的局部变量是在栈区分配空间的,栈区的特点是在上面创建的变量出了作用域就销毁。

但是被static修饰的变量存放在数据段(静态区),数据段的特点是在上面创建的变量,直到程序 结束才销毁 所以生命周期变长。

柔性数组:

柔性数组大家可能都没听说过,但是它是真实存在的,前面介绍过结构体的大小应该怎么去计算,这里涉及到大小的计算:

例如:

cpp 复制代码
#include<stdio.h>
typedef struct pc
{
	char a;
	int b;
	int arr[];
}pc;
int main()
{
	printf("%d", sizeof(pc));
	return 0;
}

这组代码的结果应该是什么?

前面介绍了结构体大小的计算:

例如:

cpp 复制代码
#include<stdio.h>
typedef struct pc
{
	char a;
	int b;
}pc;
int main()
{
	printf("%d", sizeof(pc));
	return 0;
}

他的大小是:

大小是8个字节。

这两组代码答案都是8,第一组代码加上了一个大小未知的整型数组,结果和没有加是一样的!!!

此时在结构体中大小未知的数组就被称之为柔性数组!!

那么柔性数组的大小究竟是多少呢?

柔性数组的特点:

结构中的柔性数组成员前面必须至少一个其他成员。

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

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

假设我要开辟20个字节,这20个字节有8个字节是除去数组arr结构体的大小

剩下的12个字节都会留给arr数组,所以arr数组的大小为12个字节!

综上arr数组的大小可以自己改变。

代码如下:

cpp 复制代码
#include<stdio.h>
#include<stdlib.h>
typedef struct pc
{
	char a;
	int b;
	int arr[];
}pc;

int main()
{
	pc* ptr = ( pc*)malloc(sizeof(pc) + 12);
	if (ptr == NULL)
	{
		perror("malloc");
		return 1;
	}
	return 0;
}

当然结构体我们也可以这样写(不用柔性数组):

cpp 复制代码
int main()
{
	pc* ptr = (pc*)malloc(sizeof(pc) + 12);
	if (ptr == NULL)
	{
		perror("malloc1");
		return 1;
	}
	ptr->arr = malloc(12);
	if (ptr->arr == NULL)
	{
		perror("malloc2");
		return 1;
	}
	int* pr = (int*)realloc(ptr->arr, 8);
	if (pr != NULL)
	{
		ptr->arr = pr;;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	free(ptr);
	ptr = NULL;
	free(pr);
	pr = NULL;
	return 0;
}

这个效果和柔性数组的效果是一样的!!

那么柔性数组的好处在哪?

第一个好处是: 方便内存释放 如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给 用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你 不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好 了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。

**第二个好处是:**这样有利于访问速度. 连续的内存有益于提高访问速度,也有益于减少内存碎片。(其实,我个人觉得也没多高了,反正 你跑不了要用做偏移量的加法来寻址)

相关推荐
言之。1 分钟前
【面试】Java 记录一次面试过程 三年工作经验
java·面试·职场和发展
MiyamiKK575 分钟前
leetcode_字符串 409. 最长回文串
数据结构·算法·leetcode
Biomamba生信基地6 分钟前
R语言基础| 回归分析
开发语言·回归·r语言
黑客-雨20 分钟前
从零开始:如何用Python训练一个AI模型(超详细教程)非常详细收藏我这一篇就够了!
开发语言·人工智能·python·大模型·ai产品经理·大模型学习·大模型入门
Pandaconda24 分钟前
【Golang 面试题】每日 3 题(三十九)
开发语言·经验分享·笔记·后端·面试·golang·go
半盏茶香26 分钟前
扬帆数据结构算法之雅舟航程,漫步C++幽谷——LeetCode刷题之移除链表元素、反转链表、找中间节点、合并有序链表、链表的回文结构
数据结构·c++·算法
是梦终空27 分钟前
JAVA毕业设计210—基于Java+Springboot+vue3的中国历史文化街区管理系统(源代码+数据库)
java·spring boot·vue·毕业设计·课程设计·历史文化街区管理·景区管理
加油,旭杏28 分钟前
【go语言】变量和常量
服务器·开发语言·golang
行路见知29 分钟前
3.3 Go 返回值详解
开发语言·golang
xcLeigh32 分钟前
WPF实战案例 | C# WPF实现大学选课系统
开发语言·c#·wpf