动态内存管理

简介: 动态内存管理

0.关于动态分配内存的必要性:空间开辟的大小是固定的,而数组在声明时,需要指明数组的大小,意味着数组在编译时必须确定数组的大小,而当我们面对在运行时才能确定开辟内存大小的需求,明显无法满足,所以存在需要动态开辟内存空间的需求。

1.三个动态内存的函数

1.01(malloc)

描述

C 库函数 void *malloc(size_t size) 分配所需的内存空间,并返回一个指向它的指针。

声明

下面是 malloc() 函数的声明。

void *malloc(size_t size)

参数

  • size -- 内存块的大小,以字节为单位。

返回值

该函数返回一个指针 ,指向已分配大小的内存。如果请求失败,则返回 NULL。

实例

下面的实例演示了 malloc() 函数的用法。

实例

#include <stdio.h> #include <string.h> #include <stdlib.h>


int main()


{ char *str; /* 最初的内存分配 */


str = (char *) malloc(15);


strcpy(str, "runoob");


printf("String = %s, Address = %u\n", str, str); /* 重新分配内存 */


str = (char *) realloc(str, 25);


strcat(str, ".com");


printf("String = %s, Address = %u\n", str, str);


free(str);


return(0);


}


让我们编译并运行上面的程序,这将产生以下结果:


String = runoob,  Address = 3662685808

String = runoob.com,  Address = 3662685808

1.02(calloc)

描述

C 库函数 void *calloc(size_t nitems, size_t size) 分配所需的内存空间,并返回一个指向它的指针。malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。


声明

下面是 calloc() 函数的声明。


void *calloc(size_t nitems, size_t size)

参数

  • nitems -- 要被分配的元素个数。
  • size -- 元素的大小。

返回值

该函数返回一个指针,指向已分配的内存。如果请求失败,则返回 NULL。

实例

下面的实例演示了 calloc() 函数的用法。

实例

#include <stdio.h> #include <stdlib.h>


int main()


{


int i, n; int *a; printf("要输入的元素个数:");


scanf("%d",&n);


a = (int*)calloc(n, sizeof(int));


printf("输入 %d 个数字:\n",n);


for( i=0 ; i < n ; i++ )


{


scanf("%d",&a[i]);


}


printf("输入的数字为:");


for( i=0 ; i < n ; i++ )


{ printf("%d ",a[i]); }


free (a); // 释放内存


return(0);


}


让我们编译并运行上面的程序,这将产生以下结果:

要输入的元素个数:3

输入 3 个数字:

22

55

14

输入的数字为:22 55 14

(相对于malloc而言calloc会将所开辟空间的每个字节都初始化为0)

1.03(relloc)

描述

C 库函数 void *realloc(void *ptr, size_t size) 尝试重新调整之前调用 malloc 或 calloc 所分配的 ptr 所指向的内存块的大小。


声明

下面是 realloc() 函数的声明。

void *realloc(void *ptr, size_t size)

参数

ptr -- 指针指向一个要重新分配内存的内存块,该内存块之前是通过调用 malloc、calloc 或 realloc 进行分配内存的。如果为空指针,则会分配一个新的内存块,且函数返回一个指向它的指针。

size -- 内存块的新的大小,以字节为单位。如果大小为 0,且 ptr 指向一个已存在的内存块,则 ptr 所指向的内存块会被释放,并返回一个空指针。

返回值

该函数返回一个指针 ,指向重新分配大小的内存。如果请求失败,则返回 NULL。

实例

下面的实例演示了 realloc() 函数的用法。

实例

#include <stdio.h> #include <stdlib.h> #include <string.h>


int main()


{


char *str; /* 最初的内存分配 */


str = (char *) malloc(15);


strcpy(str, "runoob");


printf("String = %s, Address = %p\n", str, str); /* 重新分配内存 */


str = (char *) realloc(str, 25);


strcat(str, ".com");


printf("String = %s, Address = %p\n", str, str);


free(str);


return(0);


}

让我们编译并运行上面的程序,这将产生以下结果:

String = runoob,  Address = 0x7fa2f8c02b10

String = runoob.com,  Address = 0x7fa2f8c02b10

关于realloc情况的几种说明:

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

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

1.04(free函数释放内存)

void free ( void* ptr );

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

如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的。

如果参数 ptr 是 NULL 指针,则函数什么事都不做。

2.关于动态内存开辟的相关错误

2.01 对NULL指针进行解引用操作

2.02 对动态开辟空间的越界访问

2.03 对非动态开辟的空间进行free操作

2.04使用free释放内存空间的一部分

2.05 对同一块内存进行多次释放或者忘记释放

3 .关于c和c++程序的内存分配

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

1. 栈区( stack ):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些

存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有

限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

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

于链表。

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

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

4.柔性数组

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

后一个元素允许是未知大小的数组,这就叫做『柔性数组』成员。 比特科技

例如:

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

柔性数组的特点:

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

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

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

柔性数组的预期大小。

例如:

柔性数组的使用

这样柔性数组成员 a ,相当于获得了 100 个整型元素的连续空间。

柔性数组的优势

上述的 type_a 结构也可以设计为:

typedef struct st_type

{

int i ;

int a [ 0 ]; // 柔性数组成员

} type_a ;

typedef struct st_type

{

int i ;

int a []; // 柔性数组成员

} type_a ;

//code1

typedef struct st_type

{

int i ;

int a [ 0 ]; // 柔性数组成员

} type_a ;

printf ( "%d\n" , sizeof ( type_a )); // 输出的是 4

// 代码 1

int i = 0 ;

type_a * p = ( type_a * ) malloc ( sizeof ( type_a ) + 100 * sizeof ( int ));

// 业务处理

p -> i = 100 ;

for ( i = 0 ; i < 100 ; i ++ )

{

p -> a [ i ] = i ;

}

free ( p );

上述 代码 1 和 代码 2 可以完成同样的功能,但是 方法 1 的实现有两个好处: 第一个好处是: 方便内存释放

如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用

户调用 free 可以释放结构体,但是用户并不知道这个结构体内的成员也需要 free ,所以你不能指望用户来发

现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体

指针,用户做一次 free 就可以把所有的内存也给释放掉。

第二个好处是: 这样有利于访问速度 .

连续的内存有益于提高访问速度,也有益于减少内存碎片。


相关文章
|
7天前
|
存储 关系型数据库 分布式数据库
PostgreSQL 18 发布,快来 PolarDB 尝鲜!
PostgreSQL 18 发布,PolarDB for PostgreSQL 全面兼容。新版本支持异步I/O、UUIDv7、虚拟生成列、逻辑复制增强及OAuth认证,显著提升性能与安全。PolarDB-PG 18 支持存算分离架构,融合海量弹性存储与极致计算性能,搭配丰富插件生态,为企业提供高效、稳定、灵活的云数据库解决方案,助力企业数字化转型如虎添翼!
|
6天前
|
存储 人工智能 Java
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
本文讲解 Prompt 基本概念与 10 个优化技巧,结合学术分析 AI 应用的需求分析、设计方案,介绍 Spring AI 中 ChatClient 及 Advisors 的使用。
316 130
AI 超级智能体全栈项目阶段二:Prompt 优化技巧与学术分析 AI 应用开发实现上下文联系多轮对话
|
18天前
|
弹性计算 关系型数据库 微服务
基于 Docker 与 Kubernetes(K3s)的微服务:阿里云生产环境扩容实践
在微服务架构中,如何实现“稳定扩容”与“成本可控”是企业面临的核心挑战。本文结合 Python FastAPI 微服务实战,详解如何基于阿里云基础设施,利用 Docker 封装服务、K3s 实现容器编排,构建生产级微服务架构。内容涵盖容器构建、集群部署、自动扩缩容、可观测性等关键环节,适配阿里云资源特性与服务生态,助力企业打造低成本、高可靠、易扩展的微服务解决方案。
1331 8
|
5天前
|
监控 JavaScript Java
基于大模型技术的反欺诈知识问答系统
随着互联网与金融科技发展,网络欺诈频发,构建高效反欺诈平台成为迫切需求。本文基于Java、Vue.js、Spring Boot与MySQL技术,设计实现集欺诈识别、宣传教育、用户互动于一体的反欺诈系统,提升公众防范意识,助力企业合规与用户权益保护。
|
17天前
|
机器学习/深度学习 人工智能 前端开发
通义DeepResearch全面开源!同步分享可落地的高阶Agent构建方法论
通义研究团队开源发布通义 DeepResearch —— 首个在性能上可与 OpenAI DeepResearch 相媲美、并在多项权威基准测试中取得领先表现的全开源 Web Agent。
1411 87
|
6天前
|
人工智能 Java API
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
本文介绍AI大模型的核心概念、分类及开发者学习路径,重点讲解如何选择与接入大模型。项目基于Spring Boot,使用阿里云灵积模型(Qwen-Plus),对比SDK、HTTP、Spring AI和LangChain4j四种接入方式,助力开发者高效构建AI应用。
312 122
AI 超级智能体全栈项目阶段一:AI大模型概述、选型、项目初始化以及基于阿里云灵积模型 Qwen-Plus实现模型接入四种方式(SDK/HTTP/SpringAI/langchain4j)
|
5天前
|
JavaScript Java 大数据
基于JavaWeb的销售管理系统设计系统
本系统基于Java、MySQL、Spring Boot与Vue.js技术,构建高效、可扩展的销售管理平台,实现客户、订单、数据可视化等全流程自动化管理,提升企业运营效率与决策能力。
|
6天前
|
弹性计算 安全 数据安全/隐私保护
2025年阿里云域名备案流程(新手图文详细流程)
本文图文详解阿里云账号注册、服务器租赁、域名购买及备案全流程,涵盖企业实名认证、信息模板创建、域名备案提交与管局审核等关键步骤,助您快速完成网站上线前的准备工作。
253 82
2025年阿里云域名备案流程(新手图文详细流程)