当前位置: 首页 > news >正文

71.【C语言】动态内存管理(重点)(4)

本文为数据结构打下基础

备注:数据结构需要掌握指针,结构体和动态内存管理

目录

6.常见的动态内存的错误

1.对空指针解引用

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

3.对非动态内存空间进行free释放

4.使用free只释放开辟的内存空间的一部分

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

6.动态开辟的内存忘记释放

7.动态开辟的内存无法释放

代码改进

7.动态内存练习题

1.VS下,求下列代码的执行结果

 答案速查

分析

改进后

方案1

方案2


承接70.【C语言】动态内存管理(重点)(3)文章

6.常见的动态内存的错误

1.对空指针解引用

之前在68.【C语言】动态内存管理(重点)(1)说过

如果真的解引用了, 可能会引发程序崩溃,内存损坏或数据丢失

因此在使用malloc,calloc,recalloc开辟内存空间时,要先判断返回的指针是否为空指针,再做其他操作

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

#include <stdlib.h>
int main()
{int* p = (int*)malloc(4);*(p + 1) = 2;*(p + 2) = 3;return 0;
}

打开VS的内存窗口,输入p

显然脱离了动态分配的空间,入侵了其他数据处,可能会引发程序崩溃,内存损坏或数据丢失

3.对非动态内存空间进行free释放

#include <stdlib.h>
int main()
{int a[5] = { 0 };int* p = a;free(p);p = NULL;return 0;
}

导致错误:

 

4.使用free只释放开辟的内存空间的一部分

#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}for (int i = 0; i < 5; i++)*(p + i) = i;p++;free(p);p = NULL;return 0;
}

 导致错误:

起始的指针不能移动!(上方代码的p++;是禁止使用的,不能改变p的值)

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

#include <stdlib.h>
int main()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}free(p);free(p);p = NULL;return 0;
}

 导致错误:

如果非要多次释放,在第一次释放后使p置NULL,再free(p);

    free(p);p = NULL;free(p);

 free(NULL);时,free函数什么也不做(free函数具体参见69.【C语言】动态内存管理(重点)(2))

6.动态开辟的内存忘记释放

忘记释放导致该内存不能再使用,可能会造成内存泄漏,程序性能下降,系统资源耗尽,程序崩溃问题

7.动态开辟的内存无法释放

#include <stdlib.h>
void function()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}//使用//......
}int main()
{function();free(p);return 0;
}

function函数内的p是局部变量,函数执行结束时,局部变量被销毁(找不到动态内存的地址),交换给操作系统,如果此时在main函数里free(p);编译无法通过,无法释放空间

(具体介绍局部变量的特性见4.【C语言】初识常量与变量)

同样的,无法释放导致该内存不能再使用,可能会造成内存泄漏,程序性能下降,系统资源耗尽,程序崩溃问题

代码改进

在function函数中返回p

#include <stdlib.h>
int* function()
{int* p = (int*)malloc(20);if (p == NULL){perror("malloc");return 1;//错误返回}//使用//......return p;
}int main()
{//r_p是return_pointer的缩写int* r_p=function();free(r_p);r_p = NULL;return 0;
}

因此

1.在函数中开辟的动态内存空间一定要返回动态内存空间的起始地址,用于main的free函数释放;

2.malloc和free成对使用;calloc和free成对使用(如果是在自定义函数中,则一定要在其返回前使用free)

7.动态内存练习题

1.VS下,求下列代码的执行结果

#define _CRT_SECURE_NO_WARNINGS 
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void GetMemory(char* p)
{p = (char*)malloc(100);
}void Test(void)
{char* str = NULL;GetMemory(str);strcpy(str, "hello world");printf(str);
}int main()
{Test();return 0;
}

 答案速查

程序崩溃

分析

运行到strcpy处发生错误

注意到0x00000000,这实际上是空指针,说明str还是空指针,进一步推导得出:GetMemory并没有改变str的内容,该函数调用结束,p被销毁,即传值调用

(有关传值调用和传址调用的介绍见29.【C语言】函数系列中 自定义函数)

因此:strcpy(str, "hello world");等价为strcpy(NULL, "hello world");

在51.【C语言】字符函数和字符串函数(strcpy函数)文中提到过,strcpy函数的参数不接受空指针,因此这里会报错

而且printf(str);实际上是对空指针解引用,这是本文介绍的6.常见的动态内存的错误的第1点错误

除此之外,该代码有两处明显不规范的地方:

1.malloc函数的返回值没有判断是否为空指针

2.有malloc但没有free,容易发生内存泄漏

改进后
方案1

使用传址(GetMemory(&str);)调用,p为二级指针(接收str指针的指针)

#define _CRT_SECURE_NO_WARNINGS 
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
void GetMemory(char** p)
{*p = (char*)malloc(100);
}int Test(void)
{char* str = NULL;GetMemory(&str);if (str == NULL){perror("malloc");return 1;//错误返回}strcpy(str, "hello world");printf(str);free(str);str = NULL;return 0;
}int main()
{Test();return 0;
}
方案2

p为一级指针,此时GetMemory无需参数

#define _CRT_SECURE_NO_WARNINGS 
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
char* GetMemory()
{char* p = (char*)malloc(100);return p;
}int Test(void)
{char* str = NULL;str = GetMemory();if (str == NULL){perror("malloc");return 1;}strcpy(str, "hello world");printf(str);free(str);str = NULL;return 0;
}int main()
{Test();return 0;
}

http://www.lryc.cn/news/454145.html

相关文章:

  • JavaScript 用HTML5约束验证API做表单验证
  • Unity 编辑器多开
  • 【Spring Boot React】Spring Boot和React教程 完整版
  • Linux中的多线程
  • 《计算机原理与系统结构》学习系列
  • 征程6 工具链常用工具和 API 整理(含新手示例)
  • 我有一张图,我怎么让midjourney按照这张图继续生成呢?
  • MSF捆绑文件
  • 01_SQLite
  • 【STM32开发笔记】移植AI框架TensorFlow到STM32单片机【下篇】
  • 畅阅读小程序|畅阅读系统|基于java的畅阅读系统小程序设计与实现(源码+数据库+文档)
  • 【机器学习(十一)】糖尿病数据集分类预测案例分析—XGBoost分类算法—Sentosa_DSML社区版
  • 二分查找一>寻找峰值
  • 《Linux从小白到高手》理论篇:深入理解Linux的网络管理
  • redis数据类型介绍
  • 一张照片变换古风写真,Flux如何做到?
  • 医药行业的智能合同审查:大模型与AI赋能合规管理
  • 幂等性接口实现
  • C++ 语言特性29 - 协程介绍
  • [Day 84] 區塊鏈與人工智能的聯動應用:理論、技術與實踐
  • 八大排序--01冒泡排序
  • 【Kubernetes】常见面试题汇总(五十)
  • Linux 操作系统中的 main 函数参数和环境变量
  • Vue项目中通过插件pxtorem实现大屏响应式
  • (Django)初步使用
  • 【星汇极客】单片机竞赛之2024睿抗机器人大赛-火线速递赛道(持续更新)
  • 生信科研,教授(优青)团队一站式指导:高通量测序技术--农业植物基因组分析、组蛋白甲基化修饰、DNA亲和纯化测序、赖氨酸甲基化
  • 【Immich部署与访问】自托管媒体文件备份服务 Immich 本地化部署与远程访问存储数据
  • AI少女/HS2甜心选择2 仿逆水寒人物卡全合集打包
  • C/C++逆向:数据类型识别