【C语言】动态内存管理,详细!!!

文章目录

  • 前言
  • 一、为什么存在动态内存分配
  • 二、动态内存开辟函数的介绍
    • 1.malloc
    • 2.calloc
    • 3.realloc
    • 4.free
  • 三、动态内存开辟中的常见错误
    • 1.误对NULL进行解引用操作
    • 2.对于动态开辟的空间进行了越界访问
    • 3.对于非动态开辟的内存进行了free操作
    • 4.只free掉动态开辟内存的一部分
    • 5.多次free已经释放的空间内存
  • 四、总结


添加链接描述

前言

大家好呀,时隔好几天小小樊又来为大家分享C语言学习啦,今天为大家分享一下自己对于动态内存管理的理解!!!

一、为什么存在动态内存分配

对于栈上开辟的空间:

  1. 空间开辟大小是固定的。
  2. 数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了

这时就需要在堆区矩形动态内存开辟了

二、动态内存开辟函数的介绍

1.malloc

大家先看一下库中对于他的说明:
在这里插入图片描述

函数功能:开辟内存块
参数size_t:需要申请的字节数
返回值:申请失败返回空指针,申请成功返回指向申请该空间首地址的指针头文件:stdlib.h
注意:返回指针的类型是void*,这时候需要你把该指针强制类型转化为你想要的类型,这样方便访问,以及解引用,malloc申请来的空间是连续的,但是多次malloc来的是不连续的
malloc的使用

int main()
{int*p=(int*) malloc(40);//申请了40个字节,强制转化为int*类型指针if (p == NULL)//如果返回空指针的话,申请失败{perror("malloc:");//打印错误信息return 1;//非正常退出}for (int i = 0; i < 10; i++){*(p + i) = i;//对每一个四个字节大小的元素赋值,这里*(p+i)的本质就是p[i];printf("%d", *(p + i));//打印每个元素}return 0;//程序正常退出}

2.calloc

大家先看一下库中对于他的说明:
在这里插入图片描述
功能:申请一个数组在内存中,并且初始化为0;
参数:size_t num申请数组元素的个数,size_t size每个元素的字节大小
返回值:申请失败返回空指针,申请成功返回指向申请该空间首地址的指针头文件:stdlib.h
calloc函数的使用:

int main()
{int i = 0;int*p=(int*) calloc(10,sizeof(int));//申请10个元素,每个元素字节大小4if (p == NULL)//如果返回空指针的话,申请失败{perror("calloc:");//打印错误信息return 1;//非正常退出}for (int i = 0; i < 10; i++){printf("%d ", *(p + i));//打印初始化的值}free(p);p = NULL;return 0;}

在这里插入图片描述
malloc和calloc的区别:
与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

3.realloc

大家先看一下库中对于他的说明:
在这里插入图片描述
功能:内存块的扩容
参数:第一个参数接收要扩容内存块的首地址,扩容后总字节大小(包括原来的字节大小)
头文件:stdlib.h
初始扩容的空间为空,则realloc和malloc的用法一模一样
返回值:扩容后空间的首地址
在这里插入图片描述
在这里插入图片描述
realloc函数的使用:

int main()
{int* p = (int*)malloc(40);//申请了40个字节,强制转化为int*类型指针if (p == NULL)//如果返回空指针的话,申请失败{perror("malloc:");//打印错误信息return 1;//非正常退出}for (int i = 0; i < 10; i++)//循环打印扩容前的元素{*(p + i) = i;printf("%d ", *(p + i));}int* ptr = (int*)realloc(p, 80);//原空间够用ptr==p,不够用的话ptr存放新地址if (ptr != NULL)//扩容成功{p = ptr;//原空间够用ptr==p,不够用的话ptr存放新地址,重新将新地址给p}for (int i = 10; i < 20; i++)//扩容后新空间的{*(p + i) = i;printf("%d ", *(p + i));}free(p);p = NULL;return 0;
}

在这里插入图片描述

4.free

大家先看一下库中对于他的说明:
在这里插入图片描述
功能:释放内存块
参数:指针接收要释放内存块的首地址
头文件:stdlib.h
返回值:无

注意:
当p所指向的申请的空间释放时,p指针指向随机位置,p变成野指针,所以我们要在释放后将其置为空!!!

如果我们不释放动态内存申请的内存的时候,程序结束,动态申请内存由操作系统自动回收,如果不用free函数释放申请好的空间,就会在程序运行结束前一直存在于堆中,造成内存泄漏

三、动态内存开辟中的常见错误

1.误对NULL进行解引用操作

比如:

int main()
{int* p = (int*)malloc(1000);int i = 0;if (p ==NULL){return 1;}for (i = 0; i < 250; i++){*(p + i) = i;}free(p);p = NULL;return 0;
}

当开辟内存失败时会返回空,这时容易造成此错误。
解决方法:开辟内存后进行判断,如上面代码中的 if 判断

2.对于动态开辟的空间进行了越界访问

int main()
{int* p = (int*)malloc(100);int i = 0;if (p ==NULL){return 1;}for (i = 0; i <=25; i++)//越界访问{*(p + i) = i;}free(p);p = NULL;return 0;
}

解决方法:人为进行检查是否越界

3.对于非动态开辟的内存进行了free操作

int main()
{int a = 10;int* p = &a;free(p);p = NULL;return 0;
}

4.只free掉动态开辟内存的一部分

int main()
{int* p = (int*)malloc(100);if (p == NULL){return 1;}int i = 0;for (i = 0; i < 10; i++){*p = i;p++;}free(p);p = NULL;return 0;
}

解决方案:
别改变保存动态开辟空间首地址的指针变量,使用时可以采用中间变量的方法!!!
例如:

int main()
{int* p = (int*)malloc(100);if (p == NULL){return 1;}int i = 0;for (i = 0; i < 10; i++){*(p+i)= i;printf("%d ", *(p + i));}free(p);p = NULL;return 0;
}

5.多次free已经释放的空间内存

int main()
{int* p = malloc(40);if (p == NULL){return 1;}free(p);free(p);p = NULL;return 0;
}

四、总结

本次内容到这里就分享完啦,如果大家觉得对自己有帮助的话还请大家点个赞呀,有分享不对的地方还恳请大家指正,谢谢大家的阅读!!!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/103955.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

笔记:transformer系列

1、和其他网络的比较 自注意力机制适合处理长文本&#xff0c;并行度好&#xff0c;在GPU上&#xff0c;CNN和Self-attention性能差不多&#xff0c;在TPU&#xff08;Tensor Processing Uni&#xff09;效果更好。 总结&#xff1a; 自注意力池化层将当做key,value,query来…

意外发现Cortex-M内核带的64bit时间戳,比32bit的DWT时钟周期计数器更方便,再也不用担心溢出问题了

视频&#xff1a; https://www.bilibili.com/video/BV1Bw411D7F5 意外发现Cortex-M内核带的64bit时间戳&#xff0c;比32bit的DWT时钟周期计数器更方便&#xff0c;再也不用担心溢出问题了 介绍&#xff1a; 看参数手册的Debug章节&#xff0c;System ROM Table里面带Timestam…

django自动创建model数据

目前使用的环境&#xff1a;django4.2.3&#xff0c;python3.10 django通过一些第三方库&#xff0c;可以轻易的自动生成一系列的后台数据。 首先先创建一个数据库&#xff1a; 然后&#xff0c;在setting.py中就可以指定我们新创建的数据库了。 DATABASES {default: {ENGI…

食品饮料制造行业如何实现数字化转型和工业4.0

随着科技的不断进步和全球产业的不断发展&#xff0c;食品饮料制造行业也正迎来数字化转型和工业4.0的浪潮。这一转型不仅提升了生产效率和质量&#xff0c;还满足了消费者对更健康、更可持续产品的需求。本文将深入探讨食品饮料制造行业在数字化转型和工业4.0方面的趋势、挑战…

使用Python搭建服务器公网展示本地电脑文件

文章目录 1.前言2.本地http服务器搭建2.1.Python的安装和设置2.2.Python服务器设置和测试 3.cpolar的安装和注册3.1 Cpolar云端设置3.2 Cpolar本地设置 4.公网访问测试5.结语 1.前言 Python作为热度比较高的编程语言&#xff0c;其语法简单且语句清晰&#xff0c;而且python有…

Git,分布式版本控制工具

1.为常用指令配置别名&#xff08;可选&#xff09; 打开用户目录&#xff0c;创建.bashrc文件 &#xff08;touch ~/.bashrc&#xff09; 2.往其输入内容 #用于输出git提交日志 alias git-loggit log --prettyoneline --all --graph --abbrev-commit #用于输出当前目录所有文…

Redis Pub/Sub 指南

Redis 不仅仅是一个数据库&#xff0c;还可以作为支持发布和订阅&#xff08;Pub/Sub&#xff09;操作的消息代理。本文将使用 Navicat for Redis 简要概述 Redis 的 Pub/Sub 功能。 关于发布或订阅消息范式 Pub/Sub 是一种模式&#xff0c;发送者&#xff08;广播者&#xf…

C++11特性详解

一、简介 在C11标准出来之前&#xff0c;一直是C98/03标准占引领地位&#xff0c;而C98/03标准是C98标准在2003年将存在的一些漏洞进行了修复&#xff0c;但并没有核心语法的改动。相比于C98/03&#xff0c;C11则带来了数量可观的变化&#xff0c;其中包含了约140个新特性&…

linux部署clickhouse(单机)

一、下载安装 1.1、下载地址 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区阿里巴巴开源镜像站&#xff0c;免费提供Linux镜像下载服务&#xff0c;拥有Ubuntu、CentOS、Deepin、MongoDB、Apache、Maven、Composer等多种开源软件镜像源&#xff0c;此外还提供域名解析DNS、…

支持向量机SVM原理

目录 支持向量机SVM原理 SVM原理 从线性分类器说起 SVM的目标是最大化分类间隔 转化为对偶问题求解 支持向量机SVM原理 【数之道】支持向量机SVM是什么&#xff0c;八分钟直觉理解其本质_哔哩哔哩_bilibili SVM是由Vapnik等人于1995年提出的&#xff0c;在之后的20多年里…

【数据结构OJ题】链表的回文结构

原题链接&#xff1a;https://www.nowcoder.com/practice/d281619e4b3e4a60a2cc66ea32855bfa?tpId49&&tqId29370&rp1&ru/activity/oj&qru/ta/2016test/question-ranking 目录 1. 题目描述 2. 思路分析 3. 代码实现 1. 题目描述 2. 思路分析 在做这道…

嵌入式Linux开发实操(十二):PWM接口开发

# 前言 使用pwm实现LED点灯,可以说是嵌入式系统的一个基本案例。那么嵌入式linux系统下又如何实现pwm点led灯呢? # PWM在嵌入式linux下的操作指令 实际使用效果如下,可以通过shell指令将开发板对应的LED灯点亮。 点亮3个LED,则分别使用pwm1、pwm2和pwm3。 # PWM引脚的硬…

React前端开发架构:构建现代响应式用户界面

在当今的Web应用开发中&#xff0c;React已经成为最受欢迎的前端框架之一。它的出色性能、灵活性和组件化开发模式&#xff0c;使得它成为构建现代响应式用户界面的理想选择。在这篇文章中&#xff0c;我们将探讨React前端开发架构的核心概念和最佳实践&#xff0c;以帮助您构建…

猜数游戏-Rust版

cargo new guessing_game 创建项目 输入任意内容&#xff0c;并打印出来 main.rs: use std::io; // 像String这些类型都在预先导入的prelude里&#xff0c;如果要使用的不在prelude里&#xff0c;则需要显式导入fn main() { println!("猜数"); println!("…

Spring 自动装配机制详解

文章目录 一、手动装配二、自动装配1. XML 方式2. 注解方式 一、手动装配 首先知道 Spring 装配是干了件啥事&#xff1f;我的理解&#xff0c;它就是用来解决 bean 之间依赖关系的一个手段。 比如说我这里有一个 People 类和一个 Dog 类&#xff0c;People 依赖 Dog&#xff…

11.redis持久化

1.redis持久化 Redis的所有数据都是保存在内存中&#xff0c;因此redis重启后数据就丢失了&#xff0c;所以需要不定期的通过异步方式保存到磁盘上(这称为“半持久化模式”)&#xff1b;或者把每一次数据变化都写入到一个append only file(aof)里面(这称为“全持久化模式”)。 …

基于微信小程序的物流管理系统3txar

在此基础上&#xff0c;结合现有物流管理体系的特点&#xff0c;运用新技术&#xff0c;构建了以 springboot为基础的物流信息化管理体系。首先&#xff0c;以需求为依据&#xff0c;对目前传统物流管理基础业务进行了较为详尽的了解和分析。根据需求分析结果进行了系统的设计&…

类的加载过程二:Linking

1、验证&#xff08;Verify&#xff09; 目的在于确保Class文件的字节流中包含信息符合当前虚拟机要求&#xff0c;保证被加载类的正确性&#xff0c;不会危害虚拟机自身安全。主要包括四种验证&#xff0c;文件格式验证&#xff0c;元数据验证&#xff0c;字节码验证&#xff…

无涯教程-PHP - XML GET

XML Get已用于从xml文件获取节点值。以下示例显示了如何从xml获取数据。 Note.xml 是xml文件&#xff0c;可以通过php文件访问。 <SUBJECT><COURSE>Android</COURSE><COUNTRY>India</COUNTRY><COMPANY>LearnFk</COMPANY><PRICE…