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.mzph.cn/news/793985.shtml

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

相关文章

springcloud基本使用三(搭建nacos)

window下安装nacos: 下载页面:Releases alibaba/nacos GitHuban easy-to-use dynamic service discovery, configuration and service management platform for building cloud native applications. - Releases alibaba/nacoshttps://github.com/alibaba/nacos/releases…

基于卷积神经网络的中药识别(pytorch框架)【python源码+UI界面+前端界面+功能源码详解】

原作者链接&#xff1a;基于卷积神经网络的中药识别&#xff08;pytorch框架&#xff09;【python源码UI界面前端界面功能源码详解】_识别中药python-CSDN博客 //gitcode,gitee,飞桨&#xff0c;csdn&#xff0c;bilibili。几个有用网站&#xff0c;直接搜索即可&#xff0c;平…

主干网络篇 | YOLOv5/v7 更换骨干网络之 HGNetv2 | 百度新一代超强主干网络

本改进已融入到 YOLOv5-Magic 框架。 论文地址:https://arxiv.org/abs/2304.08069 代码地址:https://github.com/PaddlePaddle/PaddleDetection 中文翻译:https://blog.csdn.net/weixin_43694096/article/details/131353118 文章目录 HGNetv2网络结构1.1 主干网络1.2 颈部…

【Android】毫无耦合性,一个Item根布局搞定 item侧滑删除菜单,像IOS那样简单的使用侧滑删除。(1)

自定义ViewGroup实现侧滑删除简单&#xff0c;难得是还要同时 处理多指滑动的屏蔽&#xff0c;防止两个侧滑菜单同时出现&#xff0c;等等&#xff0c; 有办法将这些东西都用一个ViewGroup搞定么&#xff1f; 看本文如何巧用static类变量来解决这些矛盾冲突。 【2 预览】 那…

真快乐APP抢购源码实现

支持多个平台的自动 滑动验证码、选字验证码。缺点就是需要自己找一个验证码识别服务器,可以自己用python写一个,或者使用超级鹰(本篇教程就是使用它) 下面是实现源码 "ui"; Date.prototype.Format = function (fmt) {var o = {"M+": this.getMonth() …

2024年做抖音小店商家,最不该忽视的三个运营要点,一定要避开!

大家好&#xff0c;我是电商花花。 每一次平台规则的改变都深深的影响着我们无货源商家&#xff0c;我们只有在规则内行使&#xff0c;遵守规则&#xff0c;才能在安然无恙。 所以我们做抖音小店一定要及时关注平台的规则变化&#xff0c;以及整体的做店趋势。 只有这样才不…

App.vue触发axios报错及解决方案

App.vue触发axios报错及解决方案 修改根目录下vue.config.js文件 module.exports {publicPath: ./,assetsDir: assets,configureWebpack: {devServer: {client: {overlay: false}}} }重新npm run dev 搞定

十个排序算法

目录 冒泡排序(Bubble Sort) 选择排序(Select Sort) 插入排序&#xff08;InsertSort&#xff09; 希尔排序&#xff08;ShellSort&#xff09; 计数排序&#xff08;CountSort&#xff09; 快速排序&#xff08;QuickSort&#xff09; 归并排序&#xff08;Merge Sort&a…

Jenkins 安装部署

1、安装下载 官网地址&#xff1a;Jenkins 下载 war 包 1、前置环境 JDK 环境&#xff08;根据 Jenkins 版本不同&#xff0c;需要的 JDK 版本不同&#xff0c;目前需要 JDK11 的版本来支持&#xff09;Maven maven 官网下载压缩包 &#xff0c;并将其传输到服务器&#xf…

【热门话题】计算机视觉入门:探索数字世界中的“视觉智能”

&#x1f308;个人主页: 鑫宝Code &#x1f525;热门专栏: 闲话杂谈&#xff5c; 炫酷HTML | JavaScript基础 ​&#x1f4ab;个人格言: "如无必要&#xff0c;勿增实体" 文章目录 计算机视觉入门&#xff1a;探索数字世界中的“视觉智能”摘要正文一、计算机视…

scoped原理及使用

一、什么是scoped&#xff0c;为什么要用 在vue文件中的style标签上&#xff0c;有一个特殊的属性&#xff1a;scoped。 当一个style标签拥有scoped属性时&#xff0c;它的CSS样式就只能作用于当前的组件&#xff0c;通过该属性&#xff0c;可以使得组件之间的样式不互相污染。…

重构智能防丢产品,苹果Find My技术引领市场发展

目前市场上最主要的防丢技术是蓝牙防丢和GPS防丢&#xff0c;蓝牙防丢是通过感应防丢器与绑定手机的距离来实现防丢的。一般防丢会默认设置一个最远安全距离&#xff0c;超过这个安全距离后&#xff0c;与手机蓝牙信号断开&#xff0c;触发防丢报警&#xff0c;用户根据防丢报警…

Shell GPT:直接安装使用的chatgpt应用软件

ShellGPT是一款基于预训练生成式Transformer模型&#xff08;如GPT系列&#xff09;构建的智能Shell工具。它将先进的自然语言处理能力集成到Shell环境中&#xff0c;使用户能够使用接近日常对话的语言来操作和控制操作系统。 官网&#xff1a;GitHub - akl7777777/ShellGPT: *…

深度学习理论基础(三)封装数据集及手写数字识别

目录 前期准备一、制作数据集1. excel表格数据2. 代码 二、手写数字识别1. 下载数据集2. 搭建模型3. 训练网络4. 测试网络5. 保存训练模型6. 导入已经训练好的模型文件7. 完整代码 前期准备 必须使用 3 个 PyTorch 内置的实用工具&#xff08;utils&#xff09;&#xff1a; ⚫…

TXT文本高效编辑神器,教你进行隔行删除不需要的内容,轻松整理文本内容。

在信息爆炸的时代&#xff0c;我们每天都会接触到大量的文本信息&#xff0c;无论是工作中的报告、邮件&#xff0c;还是生活中的读书笔记、备忘录&#xff0c;都需要我们对文本进行高效的管理和编辑。然而&#xff0c;传统的文本编辑方式往往繁琐低效&#xff0c;无法满足我们…

PTA L2-048 寻宝图

给定一幅地图&#xff0c;其中有水域&#xff0c;有陆地。被水域完全环绕的陆地是岛屿。有些岛屿上埋藏有宝藏&#xff0c;这些有宝藏的点也被标记出来了。本题就请你统计一下&#xff0c;给定的地图上一共有多少岛屿&#xff0c;其中有多少是有宝藏的岛屿。 输入格式&#xf…

LeetCode练习题--567.字符串的排列

今天讲一个非常经典的滑动窗口的问题 这道题的意思很明显: 给你两个字符串s1与s2,判断s2中是否存在一个子串:它包含s1中所有字符且不包含其他字符 让我们先来写一下滑动窗口的模板: /*** 滑动窗口模板 * param s1 * param s2 */public static void model (String s1, String s2…

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

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

HTTPS跟HTTP有区别吗?

HTTPS和HTTP的区别&#xff0c;白话一点说就是&#xff1a; 1. 安全程度&#xff1a; - HTTP&#xff1a;就像是你和朋友面对面聊天&#xff0c;说的话大家都能听见&#xff08;信息明文传输&#xff0c;容易被偷听&#xff09;。 - HTTPS&#xff1a;就像是你们俩戴着加密耳机…

论大数据服务化发展史

引言 一直想写一篇服务化相关的文章&#xff0c;那就别犹豫了现在就开始吧 正文 作为大数据基础架构工程师&#xff0c;业界也笑称“运维Boy”&#xff0c;日常工作就是在各个机器上部署以及维护服务&#xff0c;例如部署Hadoop、Kafka、Pulsar这些等等&#xff0c;用于给公…