admin管理员组

文章数量:1487745

动态内存管理学不懂,小代老师带你深入理解动态内存管理(下卷)

柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。 C99 中,结构中的最后⼀个元素允许是未知⼤⼩的数组,这就叫做『柔性数组』成员。 例如:

代码语言:javascript代码运行次数:0运行复制
struct st_type
{
 int i;
 int a[0];//柔性数组成员
};

有些编译器会报错⽆法编译可以改成:

代码语言:javascript代码运行次数:0运行复制
struct st_type
{
 int i;
 int a[];//柔性数组成员
};

6.1 柔性数组的特点:

• 结构中的柔性数组成员前⾯必须⾄少⼀个其他成员。 • sizeof 返回的这种结构⼤⼩不包括柔性数组的内存。 • 包含柔性数组成员的结构⽤malloc ()函数进⾏内存的动态分配,并且分配的内存应该大于结构的大 ,以适应柔性数组的预期⼤⼩。

代码语言:javascript代码运行次数:0运行复制
typedef struct st_type
{
 int i;
 int a[0];//柔性数组成员
}type_a;
int main()
{
 printf("%d\n", sizeof(type_a));//输出的是4
 return 0;
}

6.2 柔性数组的使用

代码语言:javascript代码运行次数:0运行复制
#include<stdio.h>
#include<stdlib.h>
typedef struct un 
{
	int c;
	char a;
	int arr [0];
}sort;
int main()
{
	sort* p = (sort*)malloc(sizeof(sort)+ sizeof(int) * 10);
	if (p == NULL)
	{
		perror(malloc);
		return 1;
	}
	p->a = 'a';
	p->c = 100;
	for (int i = 0; i < 10; i++)
	{
		p->arr[i] = i;
	}
	for (int i = 0; i < 10; i++)
	{
		printf("%d", p->arr[i]);
	}
	sort* s = realloc(p, sizeof(sort) + 40 * sizeof(int));
	if (s != NULL)
	{
		p = s;
		s = NULL;
	}
	else
	{
		return 1;
	}
	for (int i = 0; i < 40; i++)
	{
		printf("%d", p->arr[i]);
	}
	free(p);
	p == NULL;
	return 0;
}
代码语言:javascript代码运行次数:0运行复制
struct s
{
	int a;
	int* arr;
};
int mian()
{
	struct s* ps = (struct s*) malloc (sizeof(struct s));
	if (ps == NULL)
	{
		perror("malloc");
		return 1;
	}
	int* temp = (int*)malloc(10 * sizeof(int));
	if(temp!=NULL)
	{
		ps->arr = temp;
		temp = NULL;
	}
	else
	{
		return 1;
	}
	ps->a = 100;
	for (int i = 0; i < 10; i++)
	{
		ps->arr[i] = i;
	}
	//调整空间
	temp = (int*) realloc (ps->arr ,sizeof(int) * 20);
	if (temp != NULL)
	{
		ps->arr=temp;
		temp = NULL;
	}
	else
	{
		perror("realloc");
		return 1;
	}
	for (int i = 0; i < 40; i++)
	{
		printf("%d", ps->arr[i]);
	}
	free(ps->arr);
	ps = NULL;
	free(ps->a);
	ps->a = NULL;

}

上述 代码1 和 代码2 可以完成同样的功能,但是 ⽅法1 的实现有两个好处: 第⼀个好处是:⽅便内存释放 如果我们的代码是在⼀个给别⼈⽤的函数中,你在⾥⾯做了⼆次内存分配,并把整个结构体返回给⽤ ⼾。⽤⼾调⽤free可以释放结构体,但是⽤⼾并不知道这个结构体内的成员也需要free,所以你不能 指望⽤⼾来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存⼀次性分配好了,并返 回给⽤⼾⼀个结构体指针,⽤⼾做⼀次free就可以把所有的内存也给释放掉。 第⼆个好处是:这样有利于访问速度. 连续的内存有益于提⾼访问速度,也有益于减少内存碎⽚。(其实,我个⼈觉得也没多⾼了,反正你 跑不了要⽤做偏移量的加法来寻址)

扩展阅读: C语言结构体里面的指针和数组

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

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

  1. 栈区(stack):在执⾏函数时,函数内局部变量的存储单元都可以在栈上创建,函数执⾏结束时 这些存储单元⾃动被释放。栈内存分配运算内置于处理器的指令集中,效率很⾼,但是分配的内 存容量有限。 栈区主要存放运⾏函数⽽分配的局部变量、函数参数、返回数据、返回地址等。 《函数栈帧的创建和销毁》
  2. 堆区(heap):⼀般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配⽅ 式类似于链表。
  3. 数据段(静态区):(static)存放全局变量、静态数据。程序结束后由系统释放。
  4. 代码段:存放函数体(类成员函数和全局函数)的⼆进制代码。
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。 原始发表:2024-10-17,如有侵权请联系 cloudcommunity@tencent 删除程序函数内存内存管理数组

本文标签: 动态内存管理学不懂,小代老师带你深入理解动态内存管理(下卷)