C进阶—动态内存管理

这里写目录标题

动态内存分配的原因

常见的内存开辟方式:

c 复制代码
int a = 10;//在栈空间上开辟4个字节
char arr[10] = {0};//在栈空间上开辟连续的10个字节

上述开辟的空间问题:

1.空间开辟大小是固定的。

  1. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配

但有时需要程序运行时才知道空间大小,所以需要动态内存开辟

动态内存函数

malloc

void* malloc (size_t size);

该函数向内存申请一块连续可用的空间,并返回指向这块空间的指针

  • 如果开辟成功,则返回一个指向开辟好空间的指针
  • 如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查
  • 返回值的类型是 void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时使用者自己来决定
  • 如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器

free

void free (void* ptr);

free函数用来释放动态开辟的内存

  • 如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的
  • 如果参数 ptr是NULL指针,则函数什么事都不做

calloc

void* calloc (size_t num, size_t size);

  • 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0
  • 与函数 malloc的区别只在于 calloc会在返回地址之前把申请的空间的每个字节初始化为全0

realloc

void* realloc (void* ptr, size_t size);

realloc函数就可以做到对动态开辟内存大小的调整,size的大小是总的大小,比如已经用malloc开辟了40个字节的空间,size=60,就是开辟40+20个字节的空间

  • ptr是要调整的内存地址
  • size 调整之后新大小
  • 返回值为调整之后的内存起始位置
  • 函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间
  • realloc在调整内存空间的是存在两种情况:
    • 情况1:原有空间之后有足够大的空间
    • 情况2:原有空间之后没有足够大的空间


情况1:

当是情况1 的时候,要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化
情况2:

当是情况2 的时候,原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址

C/C++内存开辟

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

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

柔性数组

柔性数组(flexible array):C99 中,结构中的最后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员

c 复制代码
typedef struct st_type
{
int i;
int a[0];//柔性数组成员
}type_a;

柔性数组特点

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

柔性数组好处

  • 方便内存释放
  • 有利于访问提升速度
c 复制代码
#include <stdio.h>
#include <stdlib.h>

struct S
{
	int n;
	int arr[0];//柔性数组
};

int main()
{
	printf("%d\n", sizeof(struct S));//4
	struct S* s = (struct S*)malloc(sizeof(struct S) + 40);//4+40
	if (s == NULL)
	{
		perror("s");
		return 1;
	}
	s->n = 100;
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		s->arr[i] = i;
	}
	//扩容
	struct S* ptr = (struct S*)realloc(s, sizeof(struct S) + 40 + 20);
	if (ptr == NULL)
	{
		perror("ptr");
		return 1;
	}
	s = ptr;
	s->n = 15;
	printf("%d\n", s->n);
	for (i = 0; i < 15; i++)
	{
		printf("%d ", s->arr[i]);
	}
	//释放
	free(s);
	s = NULL;
	return 0;
}
相关推荐
史不了1 天前
静态交叉编译rust程序
开发语言·后端·rust
ad钙奶长高高1 天前
【C语言】扫雷游戏详解
c语言
读研的武1 天前
DashGo零基础入门 纯Python的管理系统搭建
开发语言·python
Andy1 天前
Python基础语法4
开发语言·python
但要及时清醒1 天前
ArrayList和LinkedList
java·开发语言
孚亭1 天前
Swift添加字体到项目中
开发语言·ios·swift
hweiyu001 天前
Go、DevOps运维开发实战(视频教程)
开发语言·golang·运维开发
mm-q29152227291 天前
Python+Requests零基础系统掌握接口自动化测试
开发语言·python
星星火柴9361 天前
笔记 | C++面向对象高级开发
开发语言·c++·笔记·学习