C语言动态内存使用常见错误及其避免方法(初学者动态内存避雷手册)

求个赞求个赞求个赞求个赞 谢谢

先赞后看好习惯 打字不容易,这都是很用心做的,希望得到支持你 大家的点赞和支持对于我来说是一种非常重要的动力 看完之后别忘记关注我哦!️️️

动态内存开辟常见错误
1.对NULL指针的解引用
2.越界访问
3.使用free释放非动态开辟的空间
4.使用free释放动态内存中的一部分
5.对同一块动态开辟的空间,多次释放
6.动态开辟的空间忘记释放-比较严重

对空指针的非法解引用

一般来说,有一定基础的我们都不会故意解引用空指针,但是,我们在使用动态内存开辟的时候,可能会解引用到”无形“的空指针

int main()
{
int*p=(int*)malloc(10000000000000000000);
int i = 0;
for (i = 0; i < 10; i++)
{
*(p + i) = i;//err
}
return 0;
}

在上面这个代码中,看似没有什么问题。但是我们知道malloc函数是有可能开辟动态内存空间失败的,我们一口气开辟这么多字节的空间,我们堆上空间不够用了,malloc函数就会开辟失败,我们通过www.cplusplus.com网站搜索malloc函数我们可以知道,如果函数开辟失败,会返回空指针,那么这个时候,我们的p就是一个空指针,空指针怎么能解引用呢?
我们可以在for之前用一个perror()函数来查看我们的问题perror("main:");


为了避免在编写程序的时候遇到这个问题,我们可以用assert()断言后再使用该指针,或者使用if语句,当指针为真的时候再使用该指针

越界访问问题

int main()
{
int* p = (int*)malloc(10 * sizeof(int));
if (p == NULL)
{
return 1;
}
int i = 0;
//越界访问,我们只开辟了40个字节,不是四十个整型
for (i = 0; i < 40; i++)
{
*(p + i) = i;
}
free(p);
p = NULL;
return 0;
}

正如这个代码,我们必须知道malloc函数在堆上开辟的时候的单位是字节,而我们这里却要访问40个整型,也就是160个字节,这就越界访问了
每写一步我们思考清楚就可以避免这个问题。

使用free释放非动态开辟的空间

free只能用来释放堆上的动态开辟的空间,而不能释放栈上的空间,栈上的内存空间,在函数结束,程序结束都会自动释放的。

//3.使用free释放非动态开辟的空间
int main()
{
int arr[10] = { 0 };
int* p = arr;
free(p);//err
p = NULL;
return 0;
}

每写一步我们思考清楚就可以避免这个问题。

使用free释放动态内存中的一部分

释放了,但没完全释放

//4.使用free释放动态内存中的一部分
int main()
{
int* p = malloc(10 * sizeof(int));
if (p == NULL)
{
return 1;
}
int i = 0;
for (i = 0; i < 5; i++)
{
*p++ = i;//我的p不见了
}
free(p);//err
p = NULL;
return 0;
}

*在这个代码中,由p指针指向的动态内存开辟后,我们的p在后续操作中改变了它自己的值,这意味这什么?
这代表没东西再可以找到这块空间了,我们到时候free§只是free()掉了p后面的一些空间,那么p前面的空间呢?不管了?
所以如果p这个位置改变了,找不到了是一件很可怕的事情。

那么,我们如何避免呢?
如果在后续我们要操作p,我们一开始就要用另一个的指针变量来记录我一开始p的位置,最后free()这个记录起始位置的指针变量,这样就可以避免“free()了,但没完全free()的问题”

对同一块动态开辟的空间,多次释放的问题

//5.对同一块动态开辟的空间,多次释放
int main()
{
int* p = (int*)malloc(100);
//使用
//...
free(p);//万一一个在函数里面,没发现,就会出现这种情况 //
free(p);
return 0;
//所以这个时候,我们需要再free完,立刻把p置为空指针
//这样的话,第二次调用free()的时候,传空指针,什么事情都不会发生
}

看到这里,有些伙伴可能会问:我肯定不会两个free写在一起啊
这里其实只是比较明显而已,如果在函数里面,已经free了,后面又写了很多代码,最后想起来又free一次,这样就会出现这种问题了

为了避免这个问题,我们一定要主动地在free()之后,马上把我们的p置空:p=NULL;这样我们后面就算在free(),free()函数传NULL给它的时候,是不会有任何问题的。

动态开辟的空间忘记释放(比较严重的问题)

//6.动态开辟的空间忘记释放
void test()
{
int* p = (int*)malloc(100);
if (p == NULL)
{
return;
}
//使用
//忘记释放了
//
//
//
//当我们出函数的时候,p会自动释放,那没人可以找到那块在堆上的空间了
//如果return以后,就没有人可以找到p指向的空间了
//这样会造成内存泄露
}
int main()
{
test();
return 0;
}

我们在前面介绍部分释放这个问题的时候已经知道,不free()会造成内存泄漏
在这里,我来为大家总结一下堆上动态开辟的空间的两种释放方式
1.程序员代码主动释放,即调用free()函数
2.程序结束
在我们一开始使用动态内存的阶段,这个问题可能看似没那么严重,程序好像照样跑,反正泄露一点也没关系,程序结束它就自动释放了
但如果我们这是一个服务器的程序呢,24小时跑呢,假如内存只有32个g,每天泄露一点,那机器不就越来越卡了?,最后只会卡死,卡死了就重启,又卡死,再重启。这种问题就会对我们的机器的使用造成很大困扰。所以内存泄漏其实是一个比较严重的问题,所以我们一定要记得free().

尾声

看到这里,相信你对动态内存使用的一些雷区有了更深的了解,也相信你已经学会了避免这些问题的方法。
如果你感觉这期博客对你帮助的话,别忘了转发,收藏,点赞,关注,一波四连再走哦!

【动态内存】C语言动态内存使用常见错误及其避免方法(初学者避雷)的更多相关文章

  1. 深入理解C语言 - 指针使用的常见错误

    在C语言中,指针的重要性不言而喻,但在很多时候指针又被认为是一把双刃剑.一方面,指针是构建数据结构和操作内存的精确而高效的工具.另一方面,它们又很容易误用,从而产生不可预知的软件bug.下面总结一下指 ...

  2. R语言编程中的常见错误

    R语言编程中的常见错误有一些错误是R的初学者和经验丰富的R程序员都可能常犯的.如果程序出错了,请检查以下几方面. 使用了错误的大小写.help().Help()和HELP()是三个不同的函数(只有第 ...

  3. 微信jssdk常见错误及解决方法

    调用config 接口的时候传入参数 debug: true 可以开启debug模式,页面会alert出错误信息.以下为常见错误及解决方法: invalid url domain当前页面所在域名与使用 ...

  4. WCF项目中出现常见错误的解决方法:基础连接已经关闭: 连接被意外关闭

    在我们开发WCF项目的时候,常常会碰到一些莫名其妙的错误,有时候如果根据它的错误提示信息,一般很难定位到具体的问题所在,而由于WCF服务的特殊性,调试起来也不是那么方便,因此往往会花费不少时间来进行跟 ...

  5. Servlet常见错误及解决方法

    常见错误及解决方法 1. 404产生的原因为Web服务器(容器)根据请求地址找不到对应资源,以下情况都会出现404的错误提示: 输入的地址有误(应用名大小写不正确,名称拼写不正确) 在web.xml文 ...

  6. IIS7常见错误及解决方法

    IIS7常见错误及解决方法   问题一:HTTP 错误 500.19 - Internal Server Error 无法访问请求的页面,因为该页的相关配置数据无效.  详细错误信息模块 IIS We ...

  7. centos linux 系统日常管理4 scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法 第十七节课

    centos linux 系统日常管理4  scp,rsync,md5sum,sha1sum,strace ,find Rsync 常见错误及解决方法  第十七节课 rsync可以增量同步,scp不行 ...

  8. python循环删除列表元素常见错误与正确方法

    python循环删除列表元素 觉得有用的话,欢迎一起讨论相互学习~Follow Me 常见错误 常见错误一:使用固定长度循环删除列表元素 # 使用固定长度循环pop方法删除列表元素 num_list_ ...

  9. cmd常见错误及解决方法

    [英文] Bad command or file name [译文] 错误的命令或文件名 错误原因和解决: 这大概是大家最常见到的错误提示了,它的意思是输入的命令无效.当输入的命令既不是DOS内部命令 ...

  10. jmeter常见错误及解决方法

    jmeter常见错误:   错误一: Response code: Non HTTP response code: java.net.SocketTimeoutException Response m ...

随机推荐

  1. JXUST_NC - ACM工作室20级选拔赛题解

    A - RioTian学长的星际航线 并查集板子 #include <bits/stdc++.h> using namespace std; const int maxn = 1010; ...

  2. OKR之剑·实战篇04:OKR执行过程优化的那些关键事

    作者:vivo 互联网平台产品研发团队 本文是<OKR 之剑>系列之实战第 4 篇--OKR执行过程不是一成不变的,团队和个人在执行中不断优化执行的具体行动,保障OKR的高效执行. 前言 ...

  3. Java23种设计模式学习笔记

    创建型模式:关注对象的创建过程 1.单例​模式: 保证一个类只有一个实例,并且提供一个访问该实例的全局访问点 主要: 饿汉式(线程安全,调用效率高,但是不能延时加载) 懒汉式(线程安全,调用效率不高, ...

  4. springboot启动流程简单总结

    Spring Boot程序有一个入口,就是main方法.main里面调用SpringApplication.run()启动整个Spring Boot程序,该方法所在类需要使用@SpringBootAp ...

  5. 一次完整的HTTP服务过程

  6. C#设计模式13——建造者模式的写法

    1. 什么是建造者模式? 建造者模式是一种创建型设计模式,它通过将一个复杂的对象分解为多个简单的对象并按照一定的顺序进行组装而创建出一个复杂的对象.这样可以使得构造过程更加灵活,同时也可以隐藏创建过程 ...

  7. Docker-01基本命令

    1.Docker安装 系统镜像为Centos7.x yum包更新到最新 sudo yum update 安装需要的软件包,yum-util提供yum-config-manager功能.另外两个是dev ...

  8. [转帖]使用Rclone实现minio数据的迁移

    使用Rclone实现minio数据的迁移 一.准备 1.1 使用工具 rclone:开源的对象存储在线迁移工具,用于文件和目录的同步,支持阿里云的oss.minio .亚马逊S3 等. 1.2 注意事 ...

  9. [转帖]jmeter学习笔记(二十二)——监听器插件之jp@gc系列

    一.jp@gc - Actiive Threads Over Time 不同时间活动用户数量展示 下面是一个阶梯加压测试的图标   二.jp@gc - Transactions per Second ...

  10. [转帖]Jmeter之界面语言设置

    https://developer.aliyun.com/article/1173114#:~:text=%E6%B0%B8%E4%B9%85%E6%80%A7%E8%AE%BE%E7%BD%AE%E ...