首页 > 系统相关 >柔性数组+总结C/C++中程序内存区域划分

柔性数组+总结C/C++中程序内存区域划分

时间:2024-06-08 19:59:55浏览次数:22  
标签:ps arr struct int C++ 内存 数组 柔性

柔性数组

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

一.柔性数组

1.柔性数组的定义

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

代码如下:

//在VS中以下两种都支持(其它编译器可以尝试都试试看)
//第一种
struct S
{
	int n;
	char c;
	int arr[];//未知大小的数组 - arr就是柔性数组
};
//第二种
struct S
{
	int n;
	char c;
	int arr[0];//未知大小的数组 - arr就是柔性数组
};

2.柔性数组的特点

  1. 结构中的柔性数组成员前面必须至少有一个其他成员
  2. sizeof返回的这种结构大小不包括柔性数组的内存
  3. 包含柔性数组成员的结构体变量用malloc()函数进行内存的动态分配,并且分配的内存应该大于结构体的大小,以适应柔性数组的预期大小。

包含柔性数组成员的结构体大小:

#include<stdio.h>
struct S
{
	int n;
	int arr[];
};
int main()
{
	printf("%zd\n", sizeof(struct S));//4个字节
	return 0;
}

在这里插入图片描述

3.柔性数组的使用

#include<stdio.h>
#include<stdlib.h>
struct S
{
	int n;
	int arr[];
};
int main()
{
	//开辟空间
	struct S* ps = (struct S*)malloc(sizeof(struct S) + 20 * sizeof(int));
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}

	//使用这块空间
	ps->n = 100;
	printf("n=%d\n", ps->n);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}
	printf("调整前的数组arr的元素值:\n");
	for (i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	//调整ps指向空间的大小空间
	struct S* ptr = (struct S*)realloc(ps, sizeof(struct S) + 40 * sizeof(int));
	if (ptr != NULL)
	{
		ps = ptr;
		ptr = NULL;
	}
	else
	{
		return 1;
	}

	//使用调整后的这块空间
	for (i = 0; i < 40; i++)
	{
		ps->arr[i] = i + 21;
	}
	printf("调整后的数组arr的元素值:\n");
	for (i = 0; i < 40; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	//释放空间
	free(ps);
	ps = NULL;
	return 0;
}

在这里插入图片描述

4.柔性数组的优势

如果要达到柔性数组的效果,也可以使用以下的代码:

#include<stdio.h>
#include<stdlib.h>
struct S
{
	int n;
	int* arr;
};
int main()
{
	//在堆区开辟空间
	struct S* ps = (struct S*)malloc(sizeof(struct S));
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}

	//开辟指针arr指向的空间
	int* temp = (int*)malloc(20 * sizeof(int));
	if (temp != NULL)
	{
		ps->arr = temp;
	}
	else
	{
		return 1;
	}

	//使用空间
	ps->n = 100;
	printf("n=%d\n", ps->n);
	int i = 0;
	for (i = 0; i < 20; i++)
	{
		ps->arr[i] = i + 1;
	}
	printf("调整前的数组arr的元素值:\n");
	for (i = 0; i < 20; i++)
	{
		printf("%d ", ps->arr[i]);
	}
	printf("\n");

	//调整空间
	temp = (int*)realloc(ps->arr, 40 * sizeof(int));
	if (temp != NULL)
	{
		ps->arr = temp;
	}
	else
	{
		perror("realloc");
		return 1;
	}

	//使用调整后的这块空间
	for (i = 0; i < 40; i++)
	{
		ps->arr[i] = i + 21;
	}
	printf("调整后的数组arr的元素值:\n");
	for (i = 0; i < 40; i++)
	{
		printf("%d ", ps->arr[i]);
	}

	//释放空间(先释放ps->arr再释放ps)
	free(ps->arr);
	ps->arr = NULL;
	free(ps);
	ps = NULL;
	return 0;
}

柔性数组有两个好处:

  1. 方便内存释放:如果我们的代码是在一个给别人用的函数中,你在里面做了⼆次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
  2. 有利于访问速度:连续的内存有益于提高访问速度,也有益于减少内存碎片。

在这里插入图片描述

二.总结C/C++中程序内存区域划分

在这里插入图片描述

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

  1. 栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。栈区主要存放运行函数和分配的局部变量、函数参数、返回数据、返回地址等。《函数栈帧的创建和销毁》
  2. 堆区(heap):一般由程序员分配释放,若程序员不释放,程序结束时可能由操作系统( Operating System)回收。分配方式类似于链表。
  3. 数据段(静态区):存放全局变量、静态数据(static)。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的二进制代码。程序结束后由系统回收。

创作不易,如果能帮到你的话能赏个三连吗?感谢啦!!!

标签:ps,arr,struct,int,C++,内存,数组,柔性
From: https://blog.csdn.net/2203_76003626/article/details/139493032

相关文章

  • C++特点,对象的概念,初始化和赋值
    C++是面向对象的变成语言,C++的特点是封装,继承,多态,同时也是面向对象语言的特点。在C++中的对象指一块能存储数据并具有某种类型的内存空间,例如当我们写一句inta时,int是C++的基本类型,a就是一个对象,如果将inta写成的inta=10;那么这句语句的含义是创建了一个int类型的对象,并给......
  • CCF-GESP 等级考试 2023年9月认证C++四级真题解析
    一、单选题(每题2分,共30分)第1题⼈们所使⽤的⼿机上安装的App通常指的是()。A.⼀款操作系统B.⼀款应⽤软件C.⼀种通话设备D.以上都不对正确答案:B.⼀款应⽤软件解析:App是"Application"的缩写,中文意思是"应用",特指安装在智能手机上的第三方应用软件。这些软件通常......
  • 另一个Java基于阻塞的定时消费内存队列(依赖guava)
    本文的代码是对一个Java基于阻塞的定时消费内存队列-Jackie_JK-博客园(cnblogs.com)方法的改进,完善了包装以及部分细节,非jdk21可能需要更换线程池类型。消费类型:@Getter@AllArgsConstructorpublicenumPushType{ELASTIC,SQL,;}队列参数枚举:@Getter@AllAr......
  • C++--移动构造函数/移动赋值运算符
    C++--移动构造函数/移动赋值运算符什么是移动语义?在C++11中,移动语义是一个重要的新特性,它可以使程序在内存管理方面更加高效,同时也提高了程序的性能它允许将一个对象的所有权从一个对象转移到另一个对象,而不需要进行数据的拷贝。通俗理解我有一份材料,A同学找我借,那我把材料......
  • C++ -- noexcept关键字
    C++--noexcept关键字noexcept关键字作用:告诉编译器,函数中不会发生异常,有利于编译器对程序做出更多的优化,比如避免生成处理异常的额外代码,减少程序的大小例子声明了noexcept和没有声明的同一段代码:safeDivide当除数为0时,会直接调用std::terminate()来中止程序而不是throw......
  • C++ 6.8笔记:①判断质数②二分基础算法
    质数试除法判定质数boolprimes(intx){  if(x<2)returnfalse;  for(inti=2;i<=x/i;i++){    if(x%i==0)returnfalse;  }  returntrue;}埃筛1intp[N],k,n;boolf[N];voidprimes(intn){//埃筛,思想:质数的倍数是合数for(inti......
  • C++U7-08-拓扑排序
    拓扑:是指把实体抽象成与其大小形状无关的点,把连接实体的线路抽象成线,研究这些点线之间的相连关系。而表示点和线之间关系的图就被称为拓扑结构图。 拓扑学原本是一个数学概念,描述的是几何图形或空间在连续改变形状后还能保持不变的性质,它只考虑物体间的位置关系而......
  • 二叉排序树--c++
    【相关知识】二叉排序树(也称二叉查找树):或者是一棵空的二叉树,或者是具有下列性质的二叉树:⑴若它的左子树不空,则左子树上所有结点的值均小于根结点的值;⑵若它的右子树不空,则右子树上所有结点的值均大于根结点的值;⑶它的左右子树也都是二叉排序树。【题目描述】①给定......
  • minos 1.1 内存虚拟化——hyp
    首发公号:Rand_csminos1.1内存虚拟化——hyp内存虚拟化,目前理解主要两方面:内存管理,没有虚拟化的情况时,对于Linux内核运行在物理硬件之上,内核需要管理物理内存,需要管理进程的虚拟内存。类似,type1类型的hypervisor/minos运行在物理硬件上,minos需要对物理内存管理,需要对......
  • minos 1.2 内存虚拟化——guest
    首发公号:Rand_csminos1.2内存虚拟化——guest项目来自乐敏大佬:https://github.com/minosproject/minos本文继续讲述minos中的内存虚拟化中关于guest的部分,主要弄清楚一个问题,minos如何管理guestvm的内存。对于虚拟机的内存管理主要是ipa的管理,ipa如何映射到......