C语言:动态内存(一篇拿捏动态内存!)

目录

学习目标: 

为什么存在动态内存分配 

动态内存函数:

1. malloc 和 free

2. calloc

3. realloc

常见的动态内存错误:

1. 对NULL指针的解引用操作

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

3. 对非动态开辟内存使用free释放

4. 使用free释放一块动态开辟内存的一部分

5. 对同一块动态内存多次释放

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

程序的内存开辟:

柔性数组:

柔性数组的使用:

柔性数组的优势:

 以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!


学习目标: 

为什么存在动态内存分配?
动态内存函数的介绍:
1、malloc;
2、free;
3、calloc;
4、realloc;
5、常见的动态内存错误;
6、内存开辟;
6、柔性数组。

为什么存在动态内存分配 

一般的开辟空间的方式有两个特点:

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

动态内存函数:

1.malloc和free

void*  malloc (size_t size);
  size:内存块的大小(以字节为单位)。是无符号整型。 size_t
1.1 这个函数向内存申请一块 连续可用 的空间,并返回指向这块空间的指针。
1.2 如果开辟成功,则返回一个指向开辟好空间的指针
      如果开辟失败,则返回一个 NULL 指针,因此 malloc 的返回值 一定要做检查。
1.3 返回值的类型是 void* ,所以 malloc 函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。
1.4 如果参数 size 0 malloc 的行为是标准是未定义的,取决于编译器。

 C语言提供了另外一个函数free,专门是用来做动态内存的释放和回收,函数原型如下:

void  free (void* ptr);
 ptr:指向先前分配有的内存块的指针。
1.1 free 函数用来释放动态开辟的内存
1.2 如果参数 ptr 指向的空间不是动态开辟的,那 free 函数的行为是未定义的。
1.3 如果参数 ptr NULL 指针,则函数什么事都不做
1.4 malloc和free都声明在 stdlib.h 头文件中。
#include <stdio.h>int main()
{//静态代码int num = 0;scanf("%d", &num);int arr[num] = {0};//动态代码int* ptr = NULL;ptr = (int*)malloc(num*sizeof(int));//判断ptr指针是否为空if(NULL != ptr){int i = 0;for(i=0; i<num; i++){*(ptr+i) = 0;}}//释放ptr所指向的动态内存free(ptr);ptr = NULL;return 0;
}

2. calloc

void* calloc (size_t num, size_t size);
  num:要分配的元素数。
    size:每个元素的大小。
2.1 函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且 把空间的每个字节初始化为0。
2.2 与函数 malloc 区别只在于 calloc 会在返回地址之前把申请的空间的每个 字节 初始化为全 0

#include <stdio.h>
#include <stdlib.h>
int main()
{int *p = (int*)calloc(10, sizeof(int));if(NULL != p){//使用这块空间}free(p);p = NULL;return 0;
}

3.realloc

        有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时候内存,我们一定会对内存的大小做灵活的调整。那 realloc 函数就可以做到对动态开辟内存大小的调整。
void*  realloc (void* ptr, size_t size);
        
        ptr:指向先前分配有的内存块的指针。或者这可以是一个 空指针,在这种情况下,将分配一个新块(就像被调用一样)。
        size:内存块的新大小(以字节为单位)。是无符号整型。 size_t
3.1 ptr 是要调整的内存地址。
3.2 size 调整之后新大小。
3.3 返回值为调整之后的内存起始位置。
3.4 这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到 的空间。
3.5 realloc 在调整内存空间的是存在两种情况:
        情况1 :原有空间之后有足够大的空间
                要扩展内存就直接原有内存之后直接追加空间,原来空间的数据不发生变化。
        情况2 :原有空间之后没有足够大的空间
               原有空间之后没有足够多的空间时,扩展的方法是:在堆空间上另找一个合适大小的连续空间来使用。这样函数返回的是一个新的内存地址。

#include <stdio.h>
int main()
{int *ptr = (int*)malloc(100);if(ptr != NULL){//业务处理}else{exit(EXIT_FAILURE);    }//扩展容量//ptr = (int*)realloc(ptr, 1000);//这样可以吗?(如果申请失败会如何?)int*p = NULL;p = realloc(ptr, 1000);if(p != NULL){ptr = p;}free(ptr);return 0;
}

常见的动态内存错误:

1. 对NULL指针的解引用操作

void test()
{int *p = (int *)malloc(INT_MAX/4);*p = 20;//如果p的值是NULL,就会有问题free(p);
}

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

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);
}

3. 对非动态开辟内存使用free释放

void test()
{int a = 10;int *p = &a;free(p);//ok?
}

4. 使用free释放一块动态开辟内存的一部分

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

5. 对同一块动态内存多次释放

void test()
{int *p = (int *)malloc(100);free(p);free(p);//重复释放
}

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

void test()
{int *p = (int *)malloc(100);if(NULL != p){*p = 20;}
}
int main()
{test();return 0;
}

程序的内存开辟:

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

柔性数组:

typedef struct st_type
{
        int i ;
        int a []; // 柔性数组成员
} type_a ;
有些编译器会说上述定义错误,可改成:
typedef struct st_type
{
        int i ;
        int a [ 0 ]; // 柔性数组成员
} type_a ;
1.1 结构中的柔性数组成员前面必须至少一个其他成员。
1.2 sizeof 返回的这种结构大小不包括柔性数组的内存。
1.3 包含柔性数组成员的结构用 malloc () 函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小。
typedef struct st_type
{
int i ;
int a [ 0 ]; // 柔性数组成员
} type_a ;
printf ( "%d\n" , sizeof ( type_a )); // 输出的是 4

柔性数组的使用:

int i = 0;
//这样柔性数组成员a,相当于获得了100个整型元素的连续空间。
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);

柔性数组的优势:

第一个好处是: 方便内存释放
        如果我们的代码是在一个给别人用的函数中,你在里面做了二次内存分配,并把整个结构体返回给用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。
第二个好处是: 这样有利于访问速度.
        连续的内存有益于提高访问速度,也有益于减少内存碎片(开辟的空间中间的间隔内存没有被利用)。

 以上就是个人学习见解和学习的解析,欢迎各位大佬在评论区探讨!

感谢大佬们的一键三连! 感谢大佬们的一键三连! 感谢大佬们的一键三连!

                                              

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

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

相关文章

SpringBoot + layui 框架实现一周免登陆功能

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

【HDFS】XXXRpcServer和ClientNamenodeProtocolServerSideTranslatorPB小记

初始化RouterRpcServer时候会new ClientNamenodeProtocolServerSideTranslatorPB,并把当前RouterRpcServer对象(this)传入构造函数: ClientNamenodeProtocolServerSideTranslatorPBclientProtocolServerTranslator =new ClientNamenodeProtocolServerSideTranslatorPB(this…

2022年03月 C/C++(六级)真题解析#中国电子学会#全国青少年软件编程等级考试

C/C++编程(1~8级)全部真题・点这里 第1题:多项式相加 我们经常遇到两多项式相加的情况, 在这里, 我们就需要用程序来模拟实现把两个多项式相加到一起。 首先, 我们会有两个多项式,每个多项式是独立的一行, 每个多项式由系数、 幂数这样的多个整数对来表示。 如多项式 2…

git 将本地分支与远程master主分支合并

1.git add . // 将本地修改文件加入暂存区 2.git commit -m"修改内容" //提交日志 3.git checkout master // 切换到主分支 (建议操作到这里的时候利用git branch 查看一下本地分支有哪些) 4.git pull // 将本地主分支代码更新 5.git checkout self-branch …

解决:在宝塔站点上添加域名(8080,888等端口)显示“端口范围不合法“

在宝塔上给站点添加域名访问时&#xff0c;有时候需要部署站点的端口为8080或者888端口。但是添加之后显示&#xff1a; 解决方法 点击宝塔上的文件 切换到根目录搜索 public.py 包含子目录 选择这个&#xff1a; 修改其中的checkport函数&#xff1a; 最后&#xff0c;重启面…

android13(T) 以太网设置工具类

13 版本的以太网设置和以前版本有所变动&#xff0c;在 AS 中就能直接调用对应 API 将 build.gradle 版本修改 compileSdkVersion 31, 即可直接调用 EthernetManager 相关&#xff0c; 设置静态等方法可以通过反射调用设置。 以下是核心设置静态和动态参数工具类&#xff0c…

【6】Java建立枚举类,开放接口给前端获取

1.枚举类代码 package com.ruoyi.common.enums;/*** 业务表单枚举.** author *********** date 0800 2023-08-29 17:06*/public enum FabFormEnum {/*** 任务 表单*/Form_JOB(1001,"任务表单"),;private Integer code;private String desc;FabFormEnum(Integer code…

C语言之函数题

目录 1.乘法口诀表 2.交换两个整数 3.函数判断闰年 4.函数判断素数 5.计算斐波那契数 6.递归实现n的k次方 7.计算一个数的每位之和&#xff08;递归&#xff09; 8.字符串逆序&#xff08;递归实现&#xff09; 9.strlen的模拟&#xff08;递归实现&#xff09; 10.求…

微力同步私人网盘部署教程:利用端口映射实现远程访问的解决方案

文章目录 1.前言2. 微力同步网站搭建2.1 微力同步下载和安装2.2 微力同步网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar云端设置3.2 Cpolar本地设置 4. 公网访问测试5. 结语 1.前言 私有云盘作为云存储概念的延伸&#xff0c;虽然谈不上多么新颖&#xff0c;但是其…

六、Kafka-Eagle监控

目录 6.1 MySQL 环境准备6.2 Kafka 环境准备6.3 Kafka-Eagle 安装 6.1 MySQL 环境准备 Kafka-Eagle 的安装依赖于 MySQL&#xff0c;MySQL 主要用来存储可视化展示的数据 6.2 Kafka 环境准备 修改/opt/module/kafka/bin/kafka-server-start.sh 命令 vim bin/kafka-server-sta…

IDEA打开一个项目时,idea左侧project模式下,不显示项目工程目录的解决方法

在IDEA打开一个一个已有的项目chapter3时&#xff0c;idea左侧project模式下&#xff0c;左侧也没有project按钮&#xff0c;如下问题截图&#xff1a;&#xff08;ps:项目结构可以显示&#xff0c;但是src等目录不见&#xff09; 在网上查了一些方法&#xff1a; 1、解决办法…

结构化日志记录增强网络安全性

日志是一种宝贵的资产&#xff0c;在监视和分析应用程序或组织的 IT 基础结构的整体安全状况和性能方面发挥着至关重要的作用。它们提供系统事件、用户活动、网络流量和应用程序行为的详细记录&#xff0c;从而深入了解潜在威胁或未经授权的访问尝试。虽然组织历来依赖于传统的…

算法工程题(中序遍历)

* 题意说明&#xff1a; * 给定一个二叉树的根节点 root &#xff0c;返回 它的 中序 遍历 。 * * 示例 1&#xff1a; * 输入&#xff1a;root [1,null,2,3] * 输出&#xff1a;[1,3,2] * * 示例 2&#xff1a; * 输入&#xff1a;root [] * 输出&#xff1a;[] * *…

混合动力汽车耐久测试

一 背景 整车厂可通过发动机和电机驱动的结合为多款车型提供混合动力驱动技术。汽车集成电机驱动可大大减少二氧化碳的排放&#xff0c;不仅如此&#xff0c;全电动驱动或混合动力驱动的汽车还将使用户体验到更好的驾驶感受&#xff0c;且这种汽车可通过电动机来实现更快的加速…

本地启动若依微服务版本

前置工作&#xff1a; 1.导入sql文件 2.安装完nacos 3.安装完redis 启动步骤&#xff1a; 1.开启nacos&#xff0c;在bin目录下 startup.cmd -m standalone 注意&#xff1a;在这之前要配置nacos持久化&#xff0c;修改conf/application.properties文件&#xff0c;增加支持…

四方定理c++题解

题目描述 四方定理是数论中著名的一个定理&#xff0c;指任意一个自然数都可以拆成四个自然数的平方之和。例如&#xff1a; 251^22^22^24^2 对 25来说&#xff0c;还有其他方案&#xff1a; 250^20^23^24^2 以及 250^20^20^25^2 给定一个自然数 n &#xff0c;请输出 n…

抽象轻松的C语言

#include <stdio.h> /* 预处理指令*/ /* 函数 */ int main() {int log 3.14;printf("hello word * %d\n easy", log);getchar();/* 获取键盘输入的字母&#xff0c;在这个程序中的作用是防止程序瞬间关闭 */return 0; } 上一篇说过&#xff0c;C程序是C语言的…

Ansible学习笔记7

user模块&#xff1a; user模块用于管理用户账户和用户属性。 如果是windows要换一个win_user模块。 创建用户&#xff1a;present&#xff1a; [rootlocalhost ~]# ansible group1 -m user -a "nameaaa statepresent" 192.168.17.106 | CHANGED > {"ansi…

【数据分享】2006-2021年我国省份级别的燃气相关指标(免费获取\20多项指标)

《中国城市建设统计年鉴》中细致地统计了我国城市市政公用设施建设与发展情况&#xff0c;在之前的文章中&#xff0c;我们分享过基于2006-2021年《中国城市建设统计年鉴》整理的2006—2021年我国省份级别的市政设施水平相关指标、2006-2021年我国省份级别的各类建设用地面积数…

【包过滤防火墙——iptables静态防火墙】的简单使用

文章目录 规则链的分类--五链处理的动作iptables常用参数和作用 防火墙就是堵和通的作用 iptables &#xff1a;包过滤防火墙&#xff0c;是内核防火墙netfilter的管理工具 核心&#xff1a;四表五链 规则链的分类–五链 在进行路由选择前处理的数据包&#xff1a;PREROUTIN…