C语言之动态内存管理

       在C语言中我们在栈上开辟的空间是固定的,一旦确定好大小就不能随意改变,就想你创建了

int i = 10;
int arr[10] = {0};
int i 一旦确定下来就是四个字节,arr一旦确定好大小在重新运行时也是不能改变的。

为此C语言引入了动态内存空间开辟,这是给程序员自主开辟好空间,并且这个空间是在上开辟的。

动态内存函数

头文件是stdlib.h

malloc

malloc 可以向堆上申请 size 个字节的空间大小,如果开辟成功就会返回相应的指针,并且对于开辟的空间是不会进行初始化赋值,里面都是随机值!
如果开辟空间失败就会返回NULL!
如果开辟0个字节的空间,返回值取决于特定的库实现,可能为NULL也可能不是.
要注意了返回的指针类型是 void*,所以我们需要强制类型转换为我们需要的。

由于可能会返回NULL,一旦被解引用就是野指针的非法访问。
所以我们要对返回的指针做检查

下面我们来实践一下:

#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(sizeof(int) * 5);if (p == NULL){perror("malloc");return 1;}// 使用return 0;
}

free

介绍完malloc 函数后,我们来介绍一下如何释放空间,由于堆的空间是有限的,如果一直开辟不去释放空间,那就会一直占用堆上的空间,导致运行时发生内存泄漏。所以我们需要学会释放空间!

free只能对malloc,calloc和realloc 这些动态内存开辟函数开辟的空间进行释放空间,如果释放的不是这些空间那这个行为就是未定义的行为(也就是错误的)
如果你传过去的指针为NULL的话,那这个函数不会做任何事情
free函数不会改变你传过去的指针的值,所以在释放空件后,可以将指针置为NULL,避免野指针的使用

#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)malloc(sizeof(int) * 5);if (p == NULL){perror("malloc");return 1;}// 使用free(p);p = NULL;return 0;
}

calloc

这个函数也是申请 num 个 size 大小的字节空间,唯一和malloc不同的是,calloc会将空间全部初始化为0

realloc

这个函数就是扩大空间的,如果你觉得malloc或者calloc开辟的空间小了,就传入一个指针,输入你想要扩大的字节数,就可以了。

如果你传的是空指针,那realloc就会像malloc一样,为你开辟一块空间并返回新空间的地址。
如果开辟失败就会返回空指针

这里的开辟方式分两种:

第一种是就地扩容,返回原来的指针
第二种是异地扩容,将原先的空间的值全部拷贝到新空间,并释放就空间,最后返回新空间的地址

#include <stdio.h>
#include <stdlib.h>int main()
{int* p = (int*)calloc(5, sizeof(int));if (p == NULL){perror("calloc");return 1;}// 使用int* ptr = (int*)realloc(p, 50);if (ptr == NULL){perror("realloc");return 1;}p = ptr;//使用free(p);p = NULL;return 0;
}

练习

题目1

void test()
{int* p = (int*)malloc(INT_MAX / 4);*p = 20;free(p);
}

如果p的值是NULL,就是对空指针解引用,发生错误

题目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;}free(p);
}

当i是10的时候就会越界访问

题目3

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

对非动态内存开辟的空间不能使用free

题目4

void test()
{int* p = (int*)malloc(100);p++;free(p);
}

由于p已经不是原先的起始位置,释放的空间不彻底,导致内存泄漏

题目5

void test()
{int* p = (int*)malloc(100);free(p);free(p);
}

对一块动态开辟的内存多次释放是错误的,在第一次释放的时候,空间以及还给操作系统了,free是无权访问操作系统的空间,所以在使用free后,我们可以将指针置空,避免多次释放。

题目6

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

这个就是忘记对开辟的内存进行释放,导致内存泄漏。

笔试题

题目1

void GetMemory(char* p)
{p = (char*)malloc(100);
}
void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}

首先str还是NULL,因为形参的改变不会影响实参,如果要改变str需要传入str的地址,对NULL解引用程序发生崩溃,并且对于开辟的内存空间要记得释放

题目2

char* GetMemory(void)
{char p[] = "hello world";return p;
}void Test(void)
{char* str = NULL;str = GetMemory();printf(str);
}

临时变量p一旦出了GetMemory 函数就被销毁了,str非法访问内存空间。

题目3

void GetMemory(char** p, int num)
{*p = (char*)malloc(num);
}
void Test(void)
{char* str = NULL;GetMemory(&str, 100);strcpy(str, "hello");printf(str);
}

忘记释放内存,发生内存泄漏

题目4

void Test(void)
{char* str = (char*)malloc(100);strcpy(str, "hello");free(str);if (str != NULL){strcpy(str, "world");printf(str);}
}

free已经释放了str所指向的内存空间,但是free不会将str置空,后面的代码段内存空间进行了非法访问!

柔性数组

       柔性数组就是数组的大小是未定义的,这种一般出现在结构体上,如果不知道结构体的大小的话,可以看我上上篇的文章《结构体详解》。

柔性数组的创建:

struct S
{int i;char arr[];
};

特点

柔性数组前面必须要有一个成员
使用sizeof去计算这个结构体的时候,是没有包含柔性数组的大小(因为他还没大小)
包含柔性数组成员的结构⽤malloc ()函数进行内存的动态分配,并且分配的内存应该⼤于结构的大小,以适应柔性数组的预期大小。

使用

当我们要使用结构体是,就需要对这个柔性数组开辟空间:

#include <stdio.h>
#include <stdlib.h>struct S
{int i;char arr[];
};int main()
{struct S* s1;s1 = (struct S*)malloc(sizeof(int) + 10 * sizeof(char));return 0;
}

这样子我们就获得了10个字节的arr数组的空间了。

优点

我们在学习链表的时候会定义下面的结构体:

#include <stdio.h>
#include <stdlib.h>struct S
{int data;struct S* next;
};int main()
{struct S* p;p = (struct S*)malloc(sizeof(struct S));if (p == NULL){perror("malloc p");return 1;}p->next = (struct S*)malloc(sizeof(struct S));if (p->next == NULL){perror("malloc next");return 1;}//使用free(p->next);p->next = NULL;free(p);p = NULL;return 0;
}

当我们使用这个结构体的时候需要对内存进行两次释放,如果使用柔性数组就可以一次释放。
柔性数组的使用能让内存空间更加连续,减少内存碎片化。

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

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

相关文章

java算法day39 | 动态规划part02 ● 62.不同路径 ● 63. 不同路径 II

62.不同路径 思路&#xff1a; 本题非常巧妙。 第一步&#xff1a;定义一个dp数组存储到达每个位置的路径数。 第二步&#xff1a;每个位置的路径数它左面位置的路径数上面位置的路径数。 第三步&#xff1a;不好想的是如何初始化数组。 既然只能向下或向右走&#xff0c;可推出…

全局UI方法-弹窗三-文本滑动选择器弹窗(TextPickDialog)

1、描述 根据指定的选择范围创建文本选择器&#xff0c;展示在弹窗上。 2、接口 TextPickDialog(options?: TextPickDialogOptions) 3、TextPickDialogOptions 参数名称 参数类型 必填 参数描述 rang string[] | Resource 是 设置文本选择器的选择范围。 selected nu…

C易错注意之分支循环,悬空else,短路表达式,static

接下来的日子会顺顺利利&#xff0c;万事胜意&#xff0c;生活明朗-----------林辞忧 前言&#xff1a; c语言中一些关于分支循环中continue常混淆&#xff0c;悬空esle问题&#xff0c;短路表达式&#xff0c;static ,extern在使用时稍不注意就会出错的点,接下来我们将介绍…

javaWeb项目-学生考勤管理系统功能介绍

项目关键技术 开发工具&#xff1a;IDEA 、Eclipse 编程语言: Java 数据库: MySQL5.7 框架&#xff1a;ssm、Springboot 前端&#xff1a;Vue、ElementUI 关键技术&#xff1a;springboot、SSM、vue、MYSQL、MAVEN 数据库工具&#xff1a;Navicat、SQLyog 1、JAVA技术 JavaSc…

Bat中cd到中文路径报错以及windows上设置快捷方式延迟启动执行

场景 要实现在windows启动目录下&#xff0c;执行bat脚本文件。 脚本文件中需要进入某个中文目录 所以直接 cd /d D:\test\中文路径 start test.bat 此时会提示&#xff1a; 此时需要指定bat的编码方式&#xff0c;修改bat脚本文件&#xff0c;添加如下 chcp 65001 cd /d…

AI预测福彩3D第22弹【2024年3月31日预测--第5套算法开始计算第4次测试】

今天&#xff0c;咱们继续进行本套算法的测试&#xff0c;今天为第四次测试&#xff0c;仍旧是采用冷温热趋势结合AI模型进行预测。好了&#xff0c;废话不多说了。直接上结果~ 仍旧是分为两个方案&#xff0c;1大1小。 经过人工神经网络计算并进行权重赋值打分后&#xff0c;3…

通过WSL在阿里云上部署Vue项目

参考&#xff1a; 阿里云上搭建网站-CSDN博客 云服务器重装 关闭当前运行实例 更换操作系统&#xff0c;还有其他的进入方式。 选择ubuntu系统&#xff08;和WSL使用相同的系统&#xff09;。 设置用户和密码。发送短信验证码。 新系统更新。秒速干净的新系统设置完成。 这…

国内ip切换app,让切换ip变得简单

在数字化快速发展的今天&#xff0c;互联网已经成为我们生活中不可或缺的一部分。然而&#xff0c;随着网络应用的深入&#xff0c;用户对于网络环境的需求也日益多样化。其中&#xff0c;IP地址作为网络中的关键标识&#xff0c;其切换与管理显得尤为重要。为了满足用户对于IP…

MongoDB副本集环境搭建(以单机Windows为例)

前言 近期有搭建MongoDB副本集的需求,简单记录一下搭建过程(以本地Windows环境为例)。 一、副本集选型 1 Primary节点、1 Secondary 节点、1 Arbiter节点模式副本集环境搭建。 二、搭建过程 1. 安装MongoDB服务 下载地址:https://www.mongodb.com,如下图所示: 选择…

element表格 加滚动,监听底部实现分页加载

表格要实现滚动很简单&#xff0c;给他加一个高度即可 height"300" 然后是监听事件 mounted() {this.lazyLoading();}, methods:{lazyLoading(){let dom document.querySelector(".el-table__body-wrapper");dom.addEventListener("scroll", (…

数据结构——优先级队列及多服务台模拟系统的实现

一、优先级队列的定义和存储 优先级队列定义&#xff1a;优先级高的元素在队头&#xff0c;优先级低的元素在队尾 基于普通线性表实现优先级队列&#xff0c;入队和出队中必有一个时间复杂度O(n),基于二叉树结构实现优先级队列&#xff0c;能够让入队和出队时间复杂度都为O(log…

2024年【N1叉车司机】考试技巧及N1叉车司机复审考试

题库来源&#xff1a;安全生产模拟考试一点通公众号小程序 N1叉车司机考试技巧参考答案及N1叉车司机考试试题解析是安全生产模拟考试一点通题库老师及N1叉车司机操作证已考过的学员汇总&#xff0c;相对有效帮助N1叉车司机复审考试学员顺利通过考试。 1、【多选题】《中华人民…

基于springboot+vue实现的学校田径运动会管理系统

作者主页&#xff1a;Java码库 主营内容&#xff1a;SpringBoot、Vue、SSM、HLMT、Jsp、PHP、Nodejs、Python、爬虫、数据可视化、小程序、安卓app等设计与开发。 收藏点赞不迷路 关注作者有好处 文末获取源码 技术选型 【后端】&#xff1a;Java 【框架】&#xff1a;spring…

开源AI引擎:文本自动分类在公安及消防执法办案自动化中的应用

一、实际案例介绍 通过文本分类算法自动化处理文本数据&#xff0c;快速识别案件性质和关键特征&#xff0c;极大地提高了案件管理和分派的效率。本文将探讨这两种技术如何帮助执法机构优化资源分配&#xff0c;确保案件得到及时而恰当的处理&#xff0c;并增强公共安全管理的…

图论-最短路

一、不存在负权边-dijkstra算法 dijkstra算法适用于这样一类问题&#xff1a; 从起点 start 到所有其他节点的最短路径。 其实求解最短路径最暴力的方法就是使用bfs广搜一下&#xff0c;但是要一次求得所有点的最短距离我们不可能循环n次&#xff0c;这样复杂度太高&#xf…

第十五届蓝桥杯第三期模拟赛第十题 ← 上楼梯

【问题描述】 小蓝要上一个楼梯&#xff0c;楼梯共有 n 级台阶&#xff08;即小蓝总共要走 n 级&#xff09;。小蓝每一步可以走 a 级、b 级或 c 级台阶。 请问小蓝总共有多少种方案能正好走到楼梯顶端&#xff1f;【输入格式】 输入的第一行包含一个整数 n 。 第二行包含三个整…

DeviceNET转EtherCat:水处理行业新神器

在现代水处理行业&#xff0c;自动化控制系统的运用日益广泛。特别是上位机通过DeviceNET转EtherCAT网关的技术&#xff0c;以其高速、高效和精准的特点&#xff0c;正逐步成为水处理自动化控制的主流解决方案。我们需要了解什么是上位机、DeviceNET和EtherCAT。上位机通常指的…

[蓝桥杯 2019 省赛 AB] 完全二叉树的权值

# [蓝桥杯 2019 省 AB] 完全二叉树的权值 ## 题目描述 给定一棵包含 $N$ 个节点的完全二叉树&#xff0c;树上每个节点都有一个权值&#xff0c;按从上到下、从左到右的顺序依次是 $A_1,A_2, \cdots A_N$&#xff0c;如下图所示&#xff1a; 现在小明要把相同深度的节点的权值…

【学习】软件科技成果鉴定测试有何作用

软件科技成果鉴定测试是针对软件进行项目申报、科技成果鉴定等相关目的进行的测试。软件测试报告可作为项目申报、科技成果鉴定等工作的依据之一。软件类科技成果鉴定测试从软件文档、功能性、使用技术等方面对软件系统进行符合性测试。其测试结果证明软件的质量是否符合技术合…

魔改一个过游戏保护的CE

csdn审核不通过 网易云课堂有配套的免费视频 int0x3 - 主页 文章都传到github了 Notes/外挂/魔改CE at master MrXiao7/Notes GitHub 为什么要编译自己的CE 在游戏逆向的过程中&#xff0c;很多游戏有保护&#xff0c;我们运行原版CE的时候会被检测到 比如我们开着CE运…