C语言——动态内存分配

        前言:通过前面的学习,我们知道C语言中在内存中开辟空间的方法有:变量和数组。既然拥有了开辟空间的方法,我们为什么还要学习动态内存分配呢?

int val = 20;  //在内存中开辟四个字节的空间
int arr[10] = { 0 }; //在内存中开辟四十个字节的连续空间

        变量和数组确实可以在内存中开辟空间,但它们也有一些不足的点 :①、开辟的空间大小是固定的,②、数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。但很多时候我们无法一开始就知道程序到底需要多少内存,使用数值和变量当程序需要的内存变大时,数组和变量开辟的空间是无法变大的,满足不了程序的需求,动态内存正是在这样的基础上诞生。

        一、动态内存函数:

1.1malloc和free:

1.1.1mall函数语法和使用:

malloc函数语法:

 malloc函数作用:动态开辟内存,可以向内存申请一块连续可以的空间,并返回指向这块空间的指针。

malloc开辟空间指针返回注意点:

        如果间开辟成功时,返回指向该空间的指针。
        如果开辟空间失败,返回一个NULL指针。
        malloc函数的返回值类型为:void* 类型,malloc函数不会指定开辟空间的类型,具体类型由使用者决定。

函数头文件:        stdlib.h 

C++plus地址:malloc - C++ 参考 (cplusplus.com)

int main()
{int* p = (int*)malloc(40);return 0;
}

空间打印演示:

int main()
{int* p =(int*) malloc(40);//判断空间是否开辟成功if (p == NULL){perror("malloc"); //开辟失败报错return 1;}//开辟成功int i = 0;for ( i = 0; i < 10; i++){printf("%d\n",*(p+1)); //以十进制打印指针内容} return 0;
}

代码里面的 int* p =(int*) malloc(40); 与int arr[10] 具有相同的效果,int类型为4个字节,10个int类型的数据刚好大小为40个字节。

malloc函数开辟内存块的大小,以字节为单位。是无符号整数类型(size_t);

malloc申请的空间在内存中的存储位置:

malloc申请空间后 :

malloc 申请到空间后,直接返回的是这快空间的起始地址,不会初始化该空间的内容。所以是上面的代码打印过程中,我们会发现打印的值为一些不正常的数字。

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

        上面代码中最后在完成打印数据时,书写了free(p); 的语句,当我们将它去掉,在VS中就行打印时,视乎也没有什么特别大的问题,但这里却必须要使用它,这是为什么呢?

1.1.2 free函数:

free函数语法:

void free (void* ptr);

        free函数的作用:动态内存的释放和回收。

free函数注意点:

        ①、如果ptr指向的空间不是动态开辟的,那么函数free的行为就是未定义行为。

        ②、如果参数ptr是NULL指针,则函数什么事情都不用做。

函数头文件:stdlib.h

 C++plus地址:free - C++ 参考 (cplusplus.com)

1.2calloc和realloc函数:

        前面我们学习了malloc同态内存开辟,calloc函数的作用也是进行动态内存开辟的.

calloc函数语法:

 函数功能:开辟num个大小为size的元素开辟一块空间,并且会将空间的每个字节初始化为0。

int main()
{int* p = (int*)calloc(10, sizeof(int)); //calloc动态空间开辟,大小40字节if (p == NULL){perror("calloc"); //错误检测}//打印数据int i = 0;for ( i = 0; i < 10; i++){printf("%d ",p[i]);}free(p);return 0;
}

realloc函数语法:

         ptr 是要调整的内存地址,size调整之后新大小。

        realloc的返回值为调整后的内存起始位置。

        realloc函数不仅会调整原内存空间大小,还会将原来内存中的数据移动到新的空间。

realloc函数调整内存空间的两种情况:

        ①、原有空间之后有足够大的空间。

直接在原有内存之后追加空间,原空间的数据不变。 

        ②、原有空间之后没有足够大的空间。

第二种情况时,会开辟新的空间,并且将就的空间中的数据拷贝到新的空间中,释放旧的空间,并且返回新空间的地址。 

函数使用代码:

int main()
{int* p = (int*)malloc(40);if (p == NULL){perror("malloc");return 1;}//初始化为1~10int i = 0;for ( i = 0; i < 10; i++){p[i] = i + 1;}//扩展空间int* ptr = realloc(p,80);if (ptr != NULL){p = ptr;}return 0;
}

1.3常见的动态内存错误:

        1.对NULL指针进行解引用操作:

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

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

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

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

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

4、同一块空间多次释放: 

int main()
{int i = 0;int* p = (int*)malloc(10*sizeof(int));if (NULL == p){perror(malloc);}for ( i = 0; i < 10; i++){*(p+i) = i;}free(p);p = NULL;free(p); //错误地方。return 0;
}

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

int main()
{int* p =(int*) malloc(40);//判断空间是否开辟成功if (p == NULL){perror("malloc"); //开辟失败报错return 1;}//开辟成功int i = 0;for ( i = 0; i < 10; i++){printf("%d\n",*(p+1)); //以十进制打印指针内容} return 0;
}

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

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

相关文章

如何在Linux部署DataEase数据分析服务并实现无公网IP远程分析内网数据信息

文章目录 前言1. 安装DataEase2. 本地访问测试3. 安装 cpolar内网穿透软件4. 配置DataEase公网访问地址5. 公网远程访问Data Ease6. 固定Data Ease公网地址 前言 DataEase 是开源的数据可视化分析工具&#xff0c;帮助用户快速分析数据并洞察业务趋势&#xff0c;从而实现业务…

mysql数据库:使用 bash脚本 + 定时任务 自动备份数据

mysql数据库&#xff1a;使用 bash脚本 定时任务 自动备份数据 1、前言2、为什么需要自动化备份&#xff1f;3、编写备份脚本4、备份脚本授权5、添加定时任务6、重启 crond / 检查 crond 服务状态7、备份文件检查 &#x1f496;The Begin&#x1f496;点点关注&#xff0c;收藏…

【代码随想录】【二叉树】补day21:二叉搜索树的最小绝对差 、二叉搜索树中的众数 、二叉树的最近公共祖先

最小绝对差 1.申请一个数组&#xff0c;比较两两之间最小的差值 def getresult3(self,node:TreeNode):self.nums[]self.getMinimumDifference(node)mindifferencefloat(inf)for i in range(len(self.nums)-1):mindself.nums[i1]-self.nums[i]if mindifference>mind:mindiff…

U盘打不开怎么办?专家解析原因与数据恢复之道

一、遭遇困境&#xff1a;U盘突然无法访问 在日常生活和工作中&#xff0c;U盘作为重要的数据存储和传输工具&#xff0c;其稳定性和可靠性至关重要。然而&#xff0c;有时我们会突然遭遇U盘打不开的困境&#xff0c;这无疑令人感到焦虑和困惑。当我们将U盘插入电脑时&#xf…

U盘文件夹变exe,数据恢复与防范全攻略

在日常使用U盘的过程中&#xff0c;不少用户都遭遇过这样一个令人头疼的问题&#xff1a;原本整齐有序的文件夹突然变成了exe可执行文件。这种异常情况不仅影响了文件的正常访问&#xff0c;更可能隐藏着数据丢失的风险。本文将深入探讨U盘文件夹变exe现象的背后原因&#xff0…

OSCP靶场--BlackGate

OSCP靶场–BlackGate 考点(1.redis rce 2. CVE-2021-4034提权) 1.nmap扫描 ┌──(root㉿kali)-[~/Desktop] └─# nmap -sV -sC -p- 192.168.163.176 --min-rate 2500 Starting Nmap 7.92 ( https://nmap.org ) at 2024-03-14 03:32 EDT Nmap scan report for 192.168.163.…

《LeetCode热题100》笔记题解思路技巧优化_Part_3

《LeetCode热题100》笔记&题解&思路&技巧&优化_Part_3 &#x1f60d;&#x1f60d;&#x1f60d; 相知&#x1f64c;&#x1f64c;&#x1f64c; 相识&#x1f622;&#x1f622;&#x1f622; 开始刷题链表&#x1f7e2;1. 相交链表&#x1f7e2;2. 反转链表&…

Python常见设计模式库之python-patterns使用详解

概要 设计模式是解决软件设计问题的经验总结和最佳实践。Python 作为一种灵活且强大的编程语言,也可以使用设计模式来提高代码的可读性、可维护性和可扩展性。Python Patterns 库提供了一系列经典和常用的设计模式实现,本文将深入探讨 Python Patterns 库的功能、使用方法以…

java-app后台系统崩溃后的处理

系统架构&#xff1a; 系统用的是ngixn 、spirngcloud、nacos作为注册中心、gateway网管&#xff0c;数据库是mysql 数据库只有一个 服务也是单实例的 所以没有办法做负载均衡什么的。 问题描述&#xff1a; 公司近期开了几个活动之后由于访次数较多和代码问题导致系统挂了。…

Git如何清除账户凭证

场景&#xff1a;一般发生在Git用户变更的情况 1.git base 操作 Git会使用凭证助手 credential.helper来储存账户凭证&#xff0c;通过以下命令移除&#xff1a; git config --system --unset credential.helper 除了system系统级外&#xff0c;还有 global、local范围。 查…

【数据结构】二叉树---红黑树的实现

目录 一. 红黑树的概念及性质 二. 红黑树结点结构的定义 三. 红黑树的插入操作 1. 情况一 2. 情况二 3. 情况三 四. 红黑树的验证 五. 红黑树与AVL树的比较 一. 红黑树的概念及性质 红黑树是一种自平衡的二叉搜索树&#xff0c;它在每个节点上增加了一个存储位来表示…

并发编程之创建线程的几种方式以及运行的详细解析

3.1 创建和运行线程 方法一&#xff0c;直接使用 Thread // 创建线程对象 Thread t new Thread() {public void run() {// 要执行的任务} }; // 启动线程 t.start(); 例如&#xff1a; // 构造方法的参数是给线程指定名字&#xff0c;推荐 Thread t1 new Thread("t1…