C语言动态内存空间分配

1. 前言

        在讲内存分配前,咱来聊一下为什么会有内存分配这个概念呢,大家都知道C语言当中是有着许多的数据类型,使用这些数据类型就会在内存上开辟其相对应的空间,那既然会开辟相应的空间,为什么还会有内存分配呢,我们会发现C语言分配内存空间,是已经被固定好了的,固定开辟多少空间,但是这样开辟空间会不会太死板了呢,如果我用不上这些空间呢,这样会导致内存的利用率很低,有没有一种,我需要多少空间,就开辟多少空间的方法呢,这个时候C语言就为我们引进了动态内存分配的这个概念,顾名思义,就是你想分配多少空间就分配多少空间,下边我们来一起了解一下怎样在内存上开辟我们想要的空间

(注意:使用这些函数都需要包含#include<stdlib.h>这个头文件)

2. malloc函数:

2.1 malloc函数的声明:

函数向内存申请⼀块连续可⽤的空间,并返回指向这块空间的指针(由于不知道你要申请的类型,使用返回值为void*)

  1. 如果开辟成功,则返回⼀个指向开辟好空间的指针。
  2. 如果开辟失败,则返回⼀个 NULL 指针,因此malloc的返回值⼀定要做检查
  3.  如果参数 size 为0,malloc的⾏为是标准是未定义的取决于编译器决于编译器(vs2022)

所以一个malloc的使用可以分为以下几步:

  1. 使用malloc函数对内存空间申请指定空间
  2. 判断返回值是否为NULL
  3. 内存空间的释放

2.2 malloc函数的简单应用:

#include <stdlib.h>
int main()
{int* p = (int*)malloc(sizeof(int) * 5); //向内存申请5个int型的内存空间if (p == NULL)  //判断返回值是否为空{perror("malloc");  //为空,则报错malloc函数处有问题return 1;}free(p);  //释放内存,在下边会说喔p = NULL;  //将p指针赋为NULL,防止出现野指针return 0;
}

3. free函数:

        在前边的代码当中,我们了解到free函数是专门用来释放动态申请的内存空间,同时也说明了它只能释放动态申请的内存空间,关于这一点兄弟们不要搞混咯

3.1 free函数声明:

​​​​​

  1. 如果参数 ptr 指向的空间不是动态开辟的,那free函数的⾏为是未定义的
  2. 如果参数 ptr 是NULL指针,则函数什么事都不做
关于free函数的使用前面有提到,有需要的兄弟可以往上翻翻

4. malloc与free的实际运用:

int main()
{int* p = (int*)malloc(sizeof(int) * 10);//申请10个int型元素if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < 10; i++)  //对malloc申请的空间进行赋值{*(p + i) = i;}for (int i = 0; i < 10; i++)  //输出{printf("%d ", *(p + i));}free(p);  //释放空间p = NULL;return 0;
}
//执行结果
0 1 2 3 4 5 6 7 8 9

5. calloc函数:

5.1 calloc函数的声明:

calloc

void* calloc (size_t num, size_t size);
  1. 与malloc相似,也是用来开辟内存空间
  2. 开辟num个size大小的元素
  3. 相较于malloc来说,calloc开辟好空间后,还会将空间内的每个字节初始化为0

5.2 calloc的简单应用:

下边我们来一段代码调试进行了解:

int main()
{int* p1 = (int*)calloc(10, sizeof(int));if (p1 == NULL){perror("calloc");return 1;}free(p1);return 0;
}

题解分析:

6 realloc函数:

        当你觉得动态内存申请的空间,不够使用的时候,这个时候就可以运用realloc函数对内存空间进行扩容,所以realloc函数是对动态内存空间进行扩容的

6.1 realloc函数的声明:

realloc

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

        1. ptr 是要调整的内存地址

        2. size 为调整之后新大小
        3. 返回值为调整之后的内存起始位置
        4.  这个函数调整原内存空间⼤⼩的基础上,还会将原来内存中的数据移动到新的空间

6.2 relloc函数扩容内存时的两种情况:

        1. 原有的空间在扩容的时候,后边有足够的空间

        2.  原有的空间在扩容的时候,后边没有足够的空间

6.3 relloc函数的简单应用:

int main()
{int* p = (int*)malloc(sizeof(int) * 10);if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < 10; i++){*(p + i) = i;}for (int i = 0; i < 10; i++){printf("%d ", *(p + i));}printf("\n");int* p1 = (int*)realloc(p,sizeof(int) * 15);  //扩容5个int型if (p1 == NULL){perror("realloc");return 2;}for (int i = 10; i < 15; i++){*(p1 + i) = i;}for (int i = 0; i < 15; i++){printf("%d ", *(p1 + i));}free(p1);p1 = NULL;return 0;return 0;
}
//执行结果
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14

6.4 柔性数组:

        在c99中规定,一个结构体中最后的数组如果没有指定大小,则这个数组被称为柔性数组

柔性数组的特点:

  1. 结构中的柔性数组成员前⾯必须⾄少⼀个其他成员
  2. sizeof 返回的这种结构⼤⼩不包括柔性数组的内存
  3. 包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大小,以适应柔性数组的预期大小
举例:
struct S
{int a;char a1;int a3[];
}q;int main()
{printf("%结构体大小为:zd", sizeof(q)); //计算结构体大小,了解柔性数组是否分配了大小struct S* s = (struct S*)malloc(sizeof(struct S) + sizeof(int) * 5); //为a3数组分配了5个int型的空间return 0;
}

题解分析:

6.4.1 柔性数组的简单应用:

        申请一块动态内存空间后,对齐扩容,扩大柔性数组的内存空间,然后对柔性数组进行赋值,最后输出结构体中成员的值:

//柔性数组
struct S
{int a;char a1;int a3[];
}q;int main(){int ret = sizeof(struct S);struct S* p2 = (struct S*)malloc(sizeof(struct S));if (p2 == NULL){perror("malloc");return 1;}p2->a = 100;p2->a1 = 48;struct S* p3 = (struct S*)realloc(p2, sizeof(struct S)+sizeof(int)*5); //扩容柔性数组的大小printf("%zd\n", sizeof(p3));if (p3 == NULL){perror("realloc");return 2;}p2 = NULL;for (int i = 0; i < 5; i++){p3->a3[i] = i;}printf("%d\n", p3->a);printf("%d\n", p3->a1);for (int i = 0; i < 5; i++){printf("%d ", p3->a3[i]);}free(p3);p3 = NULL;return 0;}
//执行结果
8
100
48
0 1 2 3 4

7. 常见的动态内存错误:

7.1 使用free对非动态内存进行释放:

int main()
{int a = 10;int* p = &a;free(p); //free对非动态内存申请的空间进行释放return 0;
}

执行结果:

7.2 动态内存越界访问:

int main()
{int* p = (int*)malloc(sizeof(int) * 5);//向内存动态申请5个int型空间if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < 6; i++) //向p执行的空间放入6个int型元素{*(p + i) = i;}return 0;
}

执行结果:

(程序死循环加上报错)

7.3 使⽤free释放⼀块动态开辟内存的⼀部分:

int main()
{int* p = (int*)malloc(sizeof(int) * 5);if (p == NULL){perror("malloc");return 1;}for (int i = 0; i < 5; i++) {*p = i;p++;   //每执行一次p++,则p指向的地址加1}free(p);return 0;
}

题解分析:

执行结果:

(程序死循环加上报错)

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

int main()
{int* p = (int*)malloc(sizeof(int) * 5);if (p == NULL){perror("malloc");return 1;}free(p);free(p);return 0;
}

执行结果:

(程序死循环加上报错)

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

        什么意思呢,简单来讲,就是你申请了空间,但是没有及时的将空间释放掉,与上边多次释放刚好相反:

int main()
{int* p = (int*)malloc(sizeof(int) * 5);if (p == NULL){perror("malloc");return 1;}//free(p);  //为注释掉的内容//free(p);return 0;
}

执行以后不会报错,但是会造成内存上的浪费


7.6 对NULL指针的解引⽤操作

int main()
{int* p = (int*)malloc(INT_MAX*10);*p = 100;free(p);return 0;
}

由于并没有判断p是否为NULL,当p为NULL时,就会发生以下报错:

(死循环直至程序崩溃)

(今日分享到此结束,如觉得对您有帮助,还请点赞关注支持一下,Thanks♪(・ω・)ノ!!!)

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

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

相关文章

如何利用FLUENT计算流体力学方法解决大气与环境领域流动问题

ANSYS FLUENT是目前全球领先的商用CFD 软件&#xff0c;市场占有率达70%左右&#xff0c;是工程师和研究者不可多得的有力工具。由于采用了多种求解方法和多重网格加速收敛技术&#xff0c;因而FLUENT能达到最佳的收敛速度和求解精度。灵活的非结构化网格和基于解的自适应网格技…

Pycharm安装request的时候出现警告“由于目标计算机积极拒绝,无法连接”,然后出现报错无法安装

Pycharm安装request的时候出现警告“由于目标计算机积极拒绝&#xff0c;无法连接”&#xff0c;然后出现报错无法安装 一、报错二、解决办法 一、报错 二、解决办法 1、点击WinR 2、输入 regedit、进入注册表 3、在搜索框处输入&#xff1a;HKEY_CURRENT_USER\Software\Mic…

HTML基础知识详解(上)(如何想知道html的全部基础知识点,那么只看这一篇就足够了!)

前言&#xff1a;在学习前端基础时&#xff0c;必不可少的就是三大件&#xff08;html、css、javascript &#xff09;&#xff0c;而HTML&#xff08;超文本标记语言——HyperText Markup Language&#xff09;是构成 Web 世界的一砖一瓦&#xff0c;它定义了网页内容的含义和…

57 npm run build 和 npm run serve 的差异

前言 npm run serve 和 npm run build 的差异 这里主要是从 vue-cli 的流程 来看一下 我们经常用到的这两个命令, 他到传递给 webpack 打包的时候, 的一个具体的差异, 大致是配置了那些东西? 经过了那些流程 ? vue-cli 的 vue-plugin 的加载 内置的 plugin 列表如下, 依次…

Python云计算技术库之libcloud使用详解

概要 随着云计算技术的发展,越来越多的应用和服务迁移到了云端。然而,不同云服务商的API和接口千差万别,给开发者带来了不小的挑战。Python的libcloud库应运而生,它提供了一个统一的接口,让开发者可以轻松地管理不同云服务商的资源。本文将深入探讨libcloud库的特性、安装…

keycloak - 鉴权VUE

目录 一、前言 1、背景 2、实验版本 二、开始干活 1、keycloak配置 a、创建领域(realms) b、创建客户端 c、创建用户、角色 2、vue代码 a、依赖 b、main.js 三、未解决的问题 目录 一、前言 1、背景 2、实验版本 二、开始干活 1、keycloak配置 a、创建领域(r…

51单片机入门:认识开发板

认识开发板 板载资源&#xff1a; 数码管模块 说明&#xff1a; 2个四位一体共阴数码管 详细&#xff1a; 2个四位一体&#xff1a;两个独立的四位数码管&#xff0c;每个四位数码管都是“一体”的设计&#xff0c;也就是说&#xff0c;每个数码管内部集成了四个独立的七段LE…

【学习】成为优秀的软件测试工程师需要学哪些知识

成为软件测试工程师&#xff0c;需要学习的内容非常的多&#xff0c;但是无非是这几大类&#xff0c;今天就和小编一起来看看这些知识&#xff0c;你是否都已经掌握。 01、测试环境的搭建 本部分主要是学习从操作系统开始&#xff0c;有关的计算机基础知识、软件和硬件知识、…

golang设计模式图解——模板方法模式

设计模式 GoF提出的设计模式有23个&#xff0c;包括&#xff1a; &#xff08;1&#xff09;创建型(Creational)模式&#xff1a;如何创建对象&#xff1b; &#xff08;2&#xff09;结构型(Structural )模式&#xff1a;如何实现类或对象的组合&#xff1b; &#xff08;3&a…

LeNet卷积神经网络

文章目录 简介conv2d网络层的结构 简介 它是最早发布的卷积神经网络之一 conv2d 这个卷积成的参数先进行介绍一下&#xff1a; self.conv1 nn.Conv2d(in_channels3, out_channels10, kernel_size3, stride1, padding1)先看一下in_channels 输入的通道数&#xff0c;out_cha…

初识MySQL(中篇)

使用语言 MySQL 使用工具 Navicat Premium 16 代码能力快速提升小方法&#xff0c;看完代码自己敲一遍&#xff0c;十分有用 目录 1.SQL语言 1.1 SQL语言组成部分 2.MySQL数据类型 2.1 数值类型 2.2 字符串类型 2.3 日期类型 3.创建数据表 3.1 创建数据表方法1 …

scala实现通过Spark统计人均登录次数最终写入MySQL

谨以此博客作为记录 小编这里用的版本是&#xff1a; <hadoop.version>2.7.7</hadoop.version> <spark.version>2.4.5</spark.version> <scala.version>2.12.10</scala.version> 如果没用到Hadoop可以忽略 步骤 准备数据&#xff0c;知道…

Python网络爬虫(四):b站评论

首先来看一下采集的数据格式: 本文不对数据采集的过程做探讨,直接上代码。首先要在程序入口处bvids列表内替换成自己想要采集的视频bvid号,然后将self.cookies替换成自己的(需要字典格式),代码可以同时爬取多个视频的评论,且爬取的评论较为完整,亲测有效: im…

SRS 实时视频服务器搭建及使用

一、SRS 介绍 SRS是一个开源的&#xff08;MIT协议&#xff09;简单高效的实时视频服务器&#xff0c;支持RTMP、WebRTC、HLS、HTTP-FLV、SRT、MPEG-DASH和GB28181等协议。 SRS媒体服务器和FFmpeg、OBS、VLC、 WebRTC等客户端配合使用&#xff0c;提供流的接收和分发的能力&am…

【QT+QGIS跨平台编译】056:【PDAL+Qt跨平台编译】(pdalcpp错误处理)

点击查看专栏目录 文章目录 一、报错信息:二、原因分析三、解决思路四、原版FileUtils.cpp五、修改后的FileUtils.cpp一、报错信息: ① exists is unavaiable: introduced in macOS 10.15 ② create_directory is unavaiable: introduced in macOS 10.15 ③ create_director…

VSCode美化

今天有空收拾了一下VSCode&#xff0c;页面如下&#xff0c;个人觉得还是挺好看的~~ 1. 主题 Noctis 色彩较多&#xff0c;有种繁杂美。 我使用的是浅色主题的一款Noctis Hibernus 2. 字体 Maple Mono 官网&#xff1a;Maple-Font 我只安装了下图两个字体&#xff0c;使…

基于Python近红外光谱分析与机器学、深度学习方法融合技术应用

郁磊副教授&#xff0c;主要从事MATLAB 编程、机器学习与数据挖掘、数据可视化和软件开发、人工智能近红外光谱分析、生物医学系统建模与仿真&#xff0c;具有丰富的实战应用经验&#xff0c;主编《MATLAB智能算法30个案例分析》、《MATLAB神经网络43个案例分析》相关著作。已发…

数据结构和算法:十大排序

排序算法 排序算法用于对一组数据按照特定顺序进行排列。排序算法有着广泛的应用&#xff0c;因为有序数据通常能够被更高效地查找、分析和处理。 排序算法中的数据类型可以是整数、浮点数、字符或字符串等。排序的判断规则可根据需求设定&#xff0c;如数字大小、字符 ASCII…

什么是Redis共享Session?

如图所示&#xff0c;一个分布式部署的Web服务器将用户的Session信息&#xff08;例如用户登录信息&#xff09;&#xff0c;保存在各自服务器内部。这样会造成一个问题&#xff0c;在分布式部署多个Web服务器时&#xff0c;我们通常会采用负载均衡算法&#xff0c;将多个用户的…

语义分割——自动驾驶鱼眼数据集

一、重要性及意义 环境感知&#xff1a;语义分割技术能够精确识别道路、车辆、行人、障碍物、交通标志和信号等各种交通场景元素。这为自动驾驶系统提供了丰富的环境信息&#xff0c;有助于车辆准确理解周围环境的结构和动态变化。决策规划&#xff1a;基于语义分割的结果&…