【C语言 | 内存管理】野指针、静态区、堆、栈、常见的内存错误及对策

😁博客主页😁:🚀https://blog.csdn.net/wkd_007🚀
🤑博客内容🤑:🍭嵌入式开发、Linux、C语言、C++、数据结构、音视频🍭
🤣本文内容🤣:🍭介绍🍭
😎金句分享😎:🍭你不能选择最好的,但最好的会来选择你——泰戈尔🍭

本文未经允许,不得转发!!!

目录

  • 🎄一、概述
  • 🎄二、野指针
    • ✨2.1 什么是野指针
    • ✨1.2 怎么避免野指针
  • 🎄三、 静态区、堆、栈、
  • 🎄四、常见的内存错误及对策
    • ✨ 4.1 指针没有指向一块合法的内存
    • ✨ 4.2 内存分配成功,但并未初始化
    • ✨ 4.3 内存越界
    • ✨ 4.5 内存泄漏
    • ✨ 4.6 使用已释放的内存
  • 🎄五、总结


在这里插入图片描述

🎄一、概述

C语言因为有指针而变得比其他语言更灵活,也更危险,所有的指针、分配的内存都需要仔细检测,不然出现的内存相关的问题容易隐藏重大的bug,更严重的,甚至会导致程序崩溃。本文就介绍一下C语言中内存相关的一些注意点。

在这里插入图片描述

🎄二、野指针

✨2.1 什么是野指针

只定义而没有初始化的指针,就是野指针。
定义了一个指针而不初始化,那么这个指针的值可能是任何值。
看例子:

#include <stdio.h>
void fun()
{int *pi;char *pc;printf("pi=%p pc=%p\n",pi,pc);
}
int main()
{fun();return 0;
}

在函数fun中定义了两个指针pipc,都没有初始化,但它们打印出来却是有值的,如下图。这就是野指针,如果直接使用这些地址,可能是程序发生一些不可预测的行为。
在这里插入图片描述

✨1.2 怎么避免野指针

定义指针变量的同时最好初始化为 NULL,用完指针之后也将指针变量的值设置为 NULL。也就是说除了在使用时,别的时间都把指针“栓”到 0 地址处。这样它就老实了。

在这里插入图片描述

🎄三、 静态区、堆、栈、

不是所有的东西都能存进内存的,内存分为三部分:

  • 静态区:保存自动全局变量和 static 变量(包括 static 全局和局部变量)。静态区的内容在总个程序的生命周期内都存在,由编译器在编译的时候分配。
  • 堆(heap):由 malloc 系列函数或 new 操作符分配的内存。其生命周期由 free 或 delete 决定。在没有释放之前一直存在,直到程序结束。其特点是使用灵活,空间比较大,但容易出错。
  • 栈(stack):保存局部变量。栈上的内容只在函数的范围内存在,当函数运行结束,这些内容也会自动被销毁。其特点是效率高,但空间大小有限。

在这里插入图片描述

🎄四、常见的内存错误及对策

✨ 4.1 指针没有指向一块合法的内存

定义了指针变量,但是没有为指针分配内存,即指针没有指向一块合法的内存。

  • 结构体成员指针未初始化
    struct student
    {char *name;int score;
    }stu,*pstu; //定义了stu,但stu.name是一个未初始化的指针
    int main()
    {strcpy(stu.name,"Jimy");stu.score = 99;return 0;
    }
    
    对策:对于结构体的指针成员,使用前要确保已经给它分配了内存。
  • 没有为结构体指针分配足够的内存
    struct student
    {char *name;int score;
    }stu,*pstu; 
    int main()
    {pstu = (struct student*)malloc(sizeof(struct student*));// 只分配了一个指针大小的内存,错误pstu->score = 99;free(pstu);return 0;
    }
    
    对策:给结构体指针分配内存时,注意要分配完整的结构体大小,而不是结构体指针大小。
  • 函数的入口校验
    不管什么时候,我们使用指针之前一定要确保指针是有效的,在函数入口使用 if(NULL != p)assert(NULL != p) 来判断参数的合法性。

✨ 4.2 内存分配成功,但并未初始化

在函数里定义了变量,没初始化就使用;或者为指针malloc一段内存后,直接使用;这些没初始化的情况是存在不可知的问题的,因为没初始化的内存里可能是任何的值,有些值可能导致程序崩溃。

最常用的就是定义了结构体,直接使用,但只给部分结构体成员赋值了,最后会使用到没赋值的成员。
看例子:

#include <stdio.h>typedef struct stu
{char *name;int age;int grade;
}st_stu;void fun(st_stu* pstu)
{printf("name=%s, age=%d grade=%d\n",pstu->name, pstu->age, pstu->grade);
}void createStudent()
{st_stu student;student.name = "mike";fun(&student);
}int main()
{createStudent();return 0;
}

上面代码中,定义了结构体变量student,但只给name成员赋值了,就将结构体变量传给其他函数使用,该函数会使用到三个结构体成员,这样的结果就很随机了。下面是运行结果,age成员是一个随机数。
在这里插入图片描述

对策:定义完变量或分配完内存一定要初始化,如果对于数组、结构体变量这样一整块的内存,可以使用memset函数赋值。

✨ 4.3 内存越界

内存分配成功,且已经初始化,但是操作越过了内存的边界。

  • 情况1:为指针分配了内存,但是内存大小不够,导致出现越界错误。

    char *p1 = “abcdefg”;
    char *p2 = (char *)malloc(sizeof(char)*strlen(p1));
    strcpy(p2,p1);
    

    p1 是字符串常量,其长度为 7 个字符,但其所占内存大小为 8 个 byte。初学者往往忘了字符串常量的结束标志“\0”。这样的话将导致 p1 字符串中最后一个空字符“\0”没有被拷贝到 p2 中。
    对策:分配内存时,如果要存放字符串,要分配的内存大小为strlen(str)+sizeof(char)

  • 情况2:使用数组越界

    int a[10] = {0};
    for (i=0; i<=10; i++)
    {a[i] = i;
    }
    

    对策:操作数组时,要注意判断下标是否越界。

✨ 4.5 内存泄漏

会产生泄漏的内存就是堆上的内存,也就是说由malloc 系列函数或 new 操作符分配的内存。如果用完之后没有及时 free 或 delete,这块内存就无法释放,直到整个程序终止。

对策:规范地使用malloc、free。

malloc 函数分配内存成功之后, 返回这块内存的首地址。你需要一个指针来接收这个地址,但是由于函数的返回值是 void *类型的,所以必须强制转换成你所接收的类型。也就是说,这块内存将要用来存储什么类型的数据。比如:char *p = (char *)malloc(100);

free 函数就做了一件事:斩断指针变量与这块内存的关系。但指针变量的值并没有变,只是那块内存不能再使用了,所以free之后,应该将指针变量赋值为NULL

✨ 4.6 使用已释放的内存

  • 第一种:就是上面所说的, free(p)之后,继续通过 p 指针来访问内存。解决的办法就是给 p 置 NULL。
  • 第二种:函数返回栈内存。这是初学者最容易犯的错误。比如在函数内部定义了一个数组, 却用 return 语句返回指向该数组的指针。 解决的办法就是弄明白栈上变量的生命周期。
  • 第三种:内存使用太复杂,弄不清到底哪块内存被释放,哪块没有被释放。解决的办法是重新设计程序,改善对象之间的调用关系。

在这里插入图片描述

🎄五、总结

👉本质介绍C语言内存管理常见的一些问题,野指针、静态区、堆、栈、常见的内存错误及对策

在这里插入图片描述
如果文章有帮助的话,点赞👍、收藏⭐,支持一波,谢谢 😁😁😁

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

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

相关文章

【MATLAB源码-第101期】基于matlab的蝙蝠优化算BA)机器人栅格路径规划,输出做短路径图和适应度曲线。

操作环境&#xff1a; MATLAB 2022a 1、算法描述 蝙蝠算法&#xff08;BA&#xff09;是一种基于群体智能的优化算法&#xff0c;灵感来源于蝙蝠捕食时的回声定位行为。这种算法模拟蝙蝠使用回声定位来探测猎物、避开障碍物的能力。在蝙蝠算法中&#xff0c;每只虚拟蝙蝠代表…

软件测试实现Finddler的手机抓包过程

Fiddler的手机抓包过程 1、启动Fiddler 打开菜单栏中的 Tools > Fiddler Options&#xff0c;打开“Fiddler Options”对话框&#xff1a; 2、在Fiddler Options”对话框 切换到“Connections”选项卡&#xff0c;然后勾选“Allow romote computers to connect”后面的复选…

UE5 C++(七)— UObject、UGameInstance实例化

文章目录 UObject实例化创建一个MyObject类在Default Pawn Class 中实现MyObject中参数调用 UGameInstance实例化创建GameInstance UObject实例化 创建一个MyObject类 在Default Pawn Class 中实现 注意&#xff1a;要实现运行时调用可在这里提前配置&#xff0c;具体参考之前…

(数据结构)单链表的插入删除

代码实现 #include<stdio.h> #include<stdlib.h> typedef struct LNode {int data;struct LNode* next; }LNode, * LinkList; //创建头结点 LNode* InitList(LinkList L) {L (LNode*)malloc(sizeof(LNode));if (L NULL){printf("申请头结点失败\n");…

公共字段自动填充——后端

场景&#xff1a;当处理一些请求时&#xff0c;会重复的对数据库的某些字段进行赋值&#xff08;如&#xff1a;在插入和更新某个物品时&#xff0c;需要更新该物品的更新时间和更新者的信息&#xff09;&#xff0c;这样会导致代码冗余。 如&#xff1a; 思路&#xff1a; 自…

【经典LeetCode算法题目专栏分类】【第2期】组合与排列问题系列

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能、AIGC、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 组合总和1 class So…

脉冲水表计量方法有哪些?

随着社会的发展和人们对资源的需求不断增长&#xff0c;水资源的有效利用显得尤为重要。而水表作为测量家庭和工业用水的关键设备&#xff0c;其准确性和稳定性对于水资源管理至关重要。本文将重点介绍水表脉冲数计量方法&#xff0c;以帮助读者更好地理解和应用水资源。 一、机…

vue3项目引入电子签名(可横屏竖屏)

实现效果&#xff1a;&#xff08;左边横屏&#xff0c;右边竖屏&#xff09; 前言&#xff1a;【使用开源项目smooth-signature 实现签名的功能。Gitee 地址是 &#xff1a;GitHub - linjc/smooth-signature: H5带笔锋手写签名&#xff0c;支持PC端和移动端&#xff0c;任何前…

【超图】SuperMap iClient3D for WebGL/WebGPU ——地形影像

作者&#xff1a;taco 号外&#xff01;号外&#xff01;开新坑了&#xff01;开新坑了&#xff01;对于一个代码小白来讲&#xff0c;设置可能是刚接触开发的人&#xff08;还没接触准备接触&#xff09;的人来说。对于读代码或是在对产品的使用上会存在许许多多的疑惑。接下来…

Ansible(一)

Ansible: 远程操作主机功能&#xff1a; 自动化运维&#xff08;playbook剧本YAML&#xff09; 是基于Python开发的配置管理应用部署攻具&#xff0c;在自动化运维当中&#xff0c;现在是异军突起 Ansible能批量配置&#xff0c;部署&#xff0c;管理上千台主机&#xff0c…

探索 MajicStudio:一款多功能视频编辑软件

一、产品简介 MajicStudio是一款基于人工智能的图片编辑与设计工具&#xff0c;拥有简洁的界面与丰富功能。采用深度学习和计算机视觉技术可以自动识别图片要素。 二、应用场景 MajicStudio的AI图像功能适用于多场景&#xff0c;包括艺术设计、电商、游戏和文创等场景。 三、…

【ranger】CDP环境 更新 ranger 权限策略会发生低概率丢失权限策略的解决方法

一、问题描述&#xff1a; 我们的 kafka 服务在更新&#xff08;添加&#xff09; ranger 权限时&#xff0c;会有极低的概率导致 MM2 同步服务报错&#xff0c;报错内容 Not Authorized。但是查看 ranger 权限是赋予的&#xff0c;并且很早配置的权限策略也会报错。 相关组件…

数据结构与算法-动态规划-地下城游戏

地下城游戏 恶魔们抓住了公主并将她关在了地下城 dungeon 的 右下角 。地下城是由 m x n 个房间组成的二维网格。我们英勇的骑士最初被安置在 左上角 的房间里&#xff0c;他必须穿过地下城并通过对抗恶魔来拯救公主。 骑士的初始健康点数为一个正整数。如果他的健康点数在某…

DDR4 设计概述以及分析仿真案例(硬件学习)

引言&#xff1a;随着计算机&#xff0c;服务器的性能需求越来越高&#xff0c;DDR4开始应用在一些高端设计中&#xff0c;然而目前关于DDR4的资料非常少&#xff0c;尤其是针对SI(信号完整性)部分以及相关中文资料&#xff0c;另外一方面&#xff0c;DDR4的高速率非常容易引起…

SQL进阶理论篇(十四):CBO优化器是如何计算代价的?

文章目录 简介能调整的代价模型的参数有哪些&#xff1f;mysql.server_costmysql.engine_cost 如何修改这些代价参数&#xff1f;代价模型具体是如何计算的参考文献 简介 大部分RDBMS都支持基于代价的优化器CBO&#xff0c;但其实CBO仍然存在缺陷&#xff08;比如参数配置的不…

Xcode 恢复Discard Changes

当开发的时候&#xff0c;Discard All Changes后 文件的修改都被放弃了&#xff0c;怎么才可以撤销更改呢 Xcode和Git没有这个功能&#xff0c;Finder可以实现 首先我们先退出Xcode用TextEdit打开你想恢复的文件转到文件 > 还原到 > 浏览所有版本...选择你想恢复的版本即…

【Python-批量修改视频分辨率】

Python-批量修改视频分辨率 1 使用Python修改视频分辨率2 常见的视频编码格式2.1 等效的编码格式表示方式2.2 常见的编码格式 1 使用Python修改视频分辨率 首先拷贝视频文件并修改后缀&#xff0c;然后修改图片的分辨率&#xff0c;实现视频批量修改和转换。 import os impor…

3dmax怎么制作软装模型?

软装在室内设计中经常用到&#xff0c;很多人感觉很难&#xff0c;其实也有很多简单的方法&#xff0c;这里介绍一种软装的制作方法。 1、打开3dmax&#xff0c;创建一个切角长方体&#xff0c;对长方体的长和宽进行适当的分段。 2、将切角长方体转换成可编辑多边形。推荐&…

实战篇:一文讲清楚电商平台用户评价分析

01 明确问题 随着电商平台的成熟&#xff0c;如何提升用户体验、提高客户留存率也成为了电商平台关注的重点。而用户评价是最直观地能反应用户体验的指标。用户差评更是其中的重点&#xff0c;通过差评分析&#xff0c;可以寻找到平台目前存在的可能导致用户打出差评的因素&am…

聊聊CISP证书

文章目录 什么是CISP为什么要考这个证报考条件是什么没达到工作年限可不可以考必须要报班吗如何找培训机构培训机构能提供什么考试一般安排在什么时候学习多长时间可以考证多长时间出成绩&拿证必须要和自己工作关联吗考试注意事项怎么选择方向需要学的内容证书有效期多长时…