零基础非科班也能掌握的C语言知识19 动态内存管理

2024-06-09 21:04

本文主要是介绍零基础非科班也能掌握的C语言知识19 动态内存管理,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

动态内存管理

  • 1.为什么要有动态内存分配
  • 2.malloc和free
    • 2.1 malloc
    • 2.2 free
  • 3.calloc和realloc
    • 3.1 calloc
    • 3.2realloc
  • 4.常见的动态内存的错误
    • 4.1对NULL指针的解引用操作
    • 4.2对动态开辟空间的越界访问
    • 4.3对非动态内存开辟的空间free
    • 4.4使用free释放⼀块动态开辟内存的⼀部分
    • 4.5对同⼀块动态内存多次释放
    • 4.6动态开辟内存忘记释放(内存泄漏)
  • 5.柔性数组
    • 5.1柔性数组的特点
    • 5.2柔性数组的使用
  • 6.总结C/C++中程序内存区域划分

1.为什么要有动态内存分配

我们目前掌握的内存开辟方式仅仅是在栈上开辟一个大小固定好的空间。但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间⼤⼩在程序运⾏的时候才能知道,那在栈上开辟空间的⽅式就不能满⾜了。(尽管我们会通过变长数组的方式开辟栈空间,但是变长数组的大小在确定后就不能改变了),我们需要让程序员⾃⼰可以申请和释放空间,因此C语言引入了动态内存开辟

2.malloc和free

2.1 malloc

C语⾔提供了⼀个动态内存开辟的函数:malloc
在这里插入图片描述

在这里插入图片描述
注意malloc的参数是size_t的类型,开辟的空间是以字节为单位的。

2.2 free

C语⾔提供了另外⼀个函数free,专⻔是⽤来做动态内存的释放和回收的,函数原型如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
注意free释放了动态开辟的内存的之后,应及时将ptr置为空指针否则的话ptr将变成野指针。往往free和置为空指针是同时出现的

3.calloc和realloc

3.1 calloc

在这里插入图片描述

在这里插入图片描述
例子:
在这里插入图片描述

3.2realloc

在这里插入图片描述

在这里插入图片描述
但是动态开辟内存是可能失败的也及时说,情况二下我们开辟动态内存失败会造成原数据丢失,因此我们应该选择代码2。
在这里插入图片描述
当然在没有开辟过动态内存时我们也可以用realloc来开辟

#include<stdlib.h>
int main()
{
realloc(NULL,10);
return 0;
}

4.常见的动态内存的错误

4.1对NULL指针的解引用操作

因此开辟内存空间(可能开辟失败)后一定要判断是否返回的是一个空指针

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

#include<stdlib.h>
void test()
{int i = 0;int* p = (int*)malloc(10 * sizeof(int));if (NULL == p){exit(EXIT_FAILURE);}for (i = 0; i <= 10; i++){*(p + i) = i;//当i是10的时候越界访问}free(p);
}
int main()
{test();
}

在这里插入图片描述

4.3对非动态内存开辟的空间free

#include<stdlib.h>
void test()
{int a = 10;int* p = &a;free(p);//ok?}
int main()
{test();
}

在这里插入图片描述

4.4使用free释放⼀块动态开辟内存的⼀部分

#include<stdlib.h>
void test(){int *p = (int *)malloc(100);p++;free(p);//p不再指向动态内存的起始位置}

4.5对同⼀块动态内存多次释放

#include<stdlib.h>
void test(){int *p = (int *)malloc(100);free(p);free(p);//重复释放}

4.6动态开辟内存忘记释放(内存泄漏)

#include<stdlib.h>
void test(){int *p = (int *)malloc(100);if(NULL != p){*p = 20;}}
int main(){test();while(1);}

感觉遇到这个问题是最棘手的,因为一开始程序是正常运行的。然后内存泄漏堆区占满了,程序直接崩溃了。关键这个问题还不好察觉,因此动态内存开辟一定要free并且置零

5.柔性数组

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

5.1柔性数组的特点

在这里插入图片描述

5.2柔性数组的使用

#include<stdlib.h>
typedef struct st_type
{int i;int a[0];//柔性数组成员
}type_a;
int main()
{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);return 0;
}

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

在这里插入图片描述

这篇关于零基础非科班也能掌握的C语言知识19 动态内存管理的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1046293

相关文章

Go语言使用select监听多个channel的示例详解

《Go语言使用select监听多个channel的示例详解》本文将聚焦Go并发中的一个强力工具,select,这篇文章将通过实际案例学习如何优雅地监听多个Channel,实现多任务处理、超时控制和非阻... 目录一、前言:为什么要使用select二、实战目标三、案例代码:监听两个任务结果和超时四、运行示例五

python panda库从基础到高级操作分析

《pythonpanda库从基础到高级操作分析》本文介绍了Pandas库的核心功能,包括处理结构化数据的Series和DataFrame数据结构,数据读取、清洗、分组聚合、合并、时间序列分析及大数据... 目录1. Pandas 概述2. 基本操作:数据读取与查看3. 索引操作:精准定位数据4. Group

C语言中%zu的用法解读

《C语言中%zu的用法解读》size_t是无符号整数类型,用于表示对象大小或内存操作结果,%zu是C99标准中专为size_t设计的printf占位符,避免因类型不匹配导致错误,使用%u或%d可能引发... 目录size_t 类型与 %zu 占位符%zu 的用途替代占位符的风险兼容性说明其他相关占位符验证示

在macOS上安装jenv管理JDK版本的详细步骤

《在macOS上安装jenv管理JDK版本的详细步骤》jEnv是一个命令行工具,正如它的官网所宣称的那样,它是来让你忘记怎么配置JAVA_HOME环境变量的神队友,:本文主要介绍在macOS上安装... 目录前言安装 jenv添加 JDK 版本到 jenv切换 JDK 版本总结前言China编程在开发 Java

C语言进阶(预处理命令详解)

《C语言进阶(预处理命令详解)》文章讲解了宏定义规范、头文件包含方式及条件编译应用,强调带参宏需加括号避免计算错误,头文件应声明函数原型以便主函数调用,条件编译通过宏定义控制代码编译,适用于测试与模块... 目录1.宏定义1.1不带参宏1.2带参宏2.头文件的包含2.1头文件中的内容2.2工程结构3.条件编

Spring Boot Actuator应用监控与管理的详细步骤

《SpringBootActuator应用监控与管理的详细步骤》SpringBootActuator是SpringBoot的监控工具,提供健康检查、性能指标、日志管理等核心功能,支持自定义和扩展端... 目录一、 Spring Boot Actuator 概述二、 集成 Spring Boot Actuat

Go语言并发之通知退出机制的实现

《Go语言并发之通知退出机制的实现》本文主要介绍了Go语言并发之通知退出机制的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录1、通知退出机制1.1 进程/main函数退出1.2 通过channel退出1.3 通过cont

MySQL多实例管理如何在一台主机上运行多个mysql

《MySQL多实例管理如何在一台主机上运行多个mysql》文章详解了在Linux主机上通过二进制方式安装MySQL多实例的步骤,涵盖端口配置、数据目录准备、初始化与启动流程,以及排错方法,适用于构建读... 目录一、什么是mysql多实例二、二进制方式安装MySQL1.获取二进制代码包2.安装基础依赖3.清

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

全面掌握 SQL 中的 DATEDIFF函数及用法最佳实践

《全面掌握SQL中的DATEDIFF函数及用法最佳实践》本文解析DATEDIFF在不同数据库中的差异,强调其边界计算原理,探讨应用场景及陷阱,推荐根据需求选择TIMESTAMPDIFF或inte... 目录1. 核心概念:DATEDIFF 究竟在计算什么?2. 主流数据库中的 DATEDIFF 实现2.1