【C语言】野指针问题详解及防范方法

news2024/11/26 9:16:43

在这里插入图片描述

博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
本文专栏: C语言

文章目录

  • 💯前言
  • 💯什么是野指针?
  • 💯未初始化的指针
    • 代码示例
    • 问题分析
    • 解决方法
  • 💯指针越界访问
    • 代码示例
    • 问题分析
    • 解决方法
  • 💯指向已释放内存的指针(悬空指针)
    • 代码示例
    • 问题分析
    • 解决方法
  • 💯小结


在这里插入图片描述


💯前言

  • C语言是一门以其高效灵活著称的编程语言,但与其高效性伴随而来的,是需要开发者非常小心地管理内存野指针Dangling Pointer)是 C 语言中的一个常见问题,指针的错误使用可能导致程序崩溃数据泄露,甚至被攻击者利用,成为严重的安全漏洞
    在本文中,我们将详细讲解野指针的三种常见情形,分析它们的成因危害以及如何防范,并通过代码示例让大家深入理解这些问题。
    C语言
    在这里插入图片描述

💯什么是野指针?

在这里插入图片描述

野指针是指向无法预测的内存地址的指针,其指向的地址往往是随机的无效的已失效的内存区域。当程序通过一个野指针去访问内存时,可能引发程序崩溃(如段错误)或者产生未定义行为

C语言 中,指针是基础特性之一,赋予程序员直接操作内存的能力,这也是 C 语言的灵活性高效性所在。然而,正是由于这种直接操作内存的能力,使得野指针问题在 C 语言中尤为常见且危险


💯未初始化的指针

在这里插入图片描述

未初始化的指针是指在定义指针变量时,未为其赋予初始值的指针。这种指针所包含的地址值是随机的,可能指向程序的任意内存区域,从而导致未定义行为。


代码示例

在这里插入图片描述

int main()
{
    int* p;      // 定义了一个指针变量 p,但未初始化
    *p = 20;     // 尝试通过 p 修改它指向的内存
    return 0;
}

问题分析

  • int* p; 这行代码中,指针 p 被定义,但并未被初始化,因此它的值是随机的,指向不可预测的内存位置。
  • 当执行 *p = 20; 时,程序试图向一个未知内存位置写入数据,这引发未定义行为,可能导致程序崩溃(例如段错误)或引发安全漏洞。

在这里插入图片描述


解决方法

  • 显式初始化指针:定义指针时,将其初始化为 NULL,这样可以确保指针不会指向任何有效的内存区域,直到它被显式赋值。
    int* p = NULL;
    
  • 分配合法的内存:在使用指针之前,确保它指向有效的内存,可以通过动态分配内存或者将其指向已有的变量。
    int a = 10;
    int* p = &a; // 指针指向变量 a 的地址
    
  • 启用编译器警告:现代编译器通常提供一些有用的警告选项,例如 -Wall,能够帮助开发者检测未初始化的指针并减少潜在的错误。
    在这里插入图片描述

💯指针越界访问

在这里插入图片描述

指针越界访问是指一个指针超出其合法内存范围,从而访问非法区域的情形。这种情况同样可能导致野指针的产生,并引发未定义行为。


代码示例

在这里插入图片描述

int main()
{
    int arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; // 定义数组并初始化
    int *p = arr;                                  // 指针 p 指向数组首元素

    int i = 0;
    int sz = sizeof(arr) / sizeof(arr[0]);         // 计算数组大小,sz = 10
    for (i = 0; i <= sz; i++)                      // 注意这里的循环条件为 i <= sz
    {
        printf("%d ", *p);                       // 试图打印指针 p 所指向的值
        p++;                                       // 指针 p 向后移动
    }

    return 0;
}

问题分析

  • for (i = 0; i <= sz; i++) 这一行中,i <= sz 使得循环多执行了一次,导致 i == sz 时,指针 p 指向了数组边界之外的内存位置,从而产生了野指针。
  • 试图通过 p 访问 arr 数组之外的内存是非法操作,可能导致程序崩溃,或者引发不易检测的安全问题。
    在这里插入图片描述

解决方法

  • 修正循环条件:将循环条件改为 i < sz,确保指针始终在数组的合法范围内。
    for (i = 0; i < sz; i++)
    
  • 加强边界检查:在操作指针时进行边界检查,确保不会超出合法的数组范围。
  • 避免手动递增指针:可以直接使用数组下标访问元素,避免手动管理指针的移动,以降低出错风险。
    for (i = 0; i < sz; i++) {
        printf("%d ", arr[i]);
    }
    

在这里插入图片描述


💯指向已释放内存的指针(悬空指针)

在这里插入图片描述

悬空指针是指向已释放或生命周期结束的内存区域的指针。当函数返回局部变量的地址,或内存被释放后仍继续使用该指针,就会导致悬空指针的问题。


代码示例

在这里插入图片描述

int* test() {
    int a = 10;   // 定义局部变量 a,并初始化为 10
    return &a;    // 返回局部变量 a 的地址
}

int main() {
    int* p = test(); // 函数返回的局部变量地址赋值给指针 p
    printf("%d\n", *p); // 通过 p 访问无效内存
    return 0;
}

问题分析

  • test 函数中,变量 a 是局部变量,存储在栈中。当函数执行完毕后,a 所在的栈帧被释放,其地址变得无效。
  • 指针 p 存储了 a 的地址,然而此时 p 成为了悬空指针,继续通过 p 访问该内存区域会导致未定义行为,可能引发程序崩溃或输出错误数据。
    在这里插入图片描述

解决方法

在这里插入图片描述

  1. 避免返回局部变量的地址

    • 可以通过动态内存分配或者静态变量来替代返回局部变量的地址。

    示例 1:动态内存分配

    int* test() {
        int* a = (int*)malloc(sizeof(int)); // 动态分配内存
        *a = 10;
        return a; // 返回分配的内存地址
    }
    
    int main() {
        int* p = test();
        printf("%d\n", *p); // 正常访问
        free(p);            // 用完后释放内存
        return 0;
    }
    

    示例 2:使用静态变量

    int* test() {
        static int a = 10; // 静态变量,生命周期贯穿程序运行
        return &a;         // 返回静态变量的地址
    }
    
    int main() {
        int* p = test();
        printf("%d\n", *p); // 正常访问
        return 0;
    }
    
  2. 确保指针始终指向有效内存

    • 在函数中返回指针时,必须确保返回的指针指向的内存是有效的,且不会在函数执行完毕后失效。
  3. 使用内存管理工具

    • 现代的内存管理工具(如 Valgrind 或 AddressSanitizer)可以有效地检测悬空指针问题,帮助开发者在开发和测试阶段发现和修复内存管理错误。

💯小结

  • 在这里插入图片描述C语言编程 中,指针的管理是至关重要的环节。C语言赋予开发者直接操作内存的能力,使得程序能够具备极高的性能,但这种能力也伴随着巨大的责任
    开发者需要掌握 指针的生命周期 以及它们在内存中的行为,从而确保程序的稳定安全。在大型项目中,内存管理指针操作尤为重要,团队开发时需要制定明确的标准代码规范,以避免因个人疏忽导致的指针错误
    此外,测试代码审查也应作为内存管理的重要环节,以确保代码在各种边界条件下都能正确运行

在这里插入图片描述


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

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

相关文章

关于如何在k8s中搭建一个nsfw黄图鉴定模型

随着现在应用内图片越来越多&#xff0c;安全审查也是必不可少的一个操作了 下面手把手教你如何将huggingface中的黄图检测模型部署到自己的服务器上去 1.找到对应的模型 nsfw_image_detection 2.在本地先验证如何使用 首先安装transformers python库 pip install transform…

初学 flutter 环境变量配置

一、jdk&#xff08;jdk11&#xff09; 1&#xff09;配置环境变量 新增&#xff1a;JAVA_HOMEC:\Program Files\Java\jdk-11 //你的jdk目录 在path新增&#xff1a;%JAVA_HOME%\bin2&#xff09;验证是否配置成功&#xff08;cmd运行命令&#xff09; java java -version …

信息安全实验--密码学实验工具:CrypTool

1. CrypTool介绍&#x1f4ad; CrypTool 1的开源教育工具&#xff0c;用于密码学研究。通过CrypTool 1&#xff0c;可以实现加密和解密操作&#xff0c;数字签名。CrypTool1和2有很多区别的。 来源于&#xff1a;网络安全快速入门5-密码学及密码破解工具CrypTool实战_百度知道…

服务器数据恢复—raid5阵列+LVM+VXFS数据恢复案例

服务器存储数据恢复环境&#xff1a; 某品牌MSA2000FC存储中有一组由7块盘组建的RAID5阵列&#xff0c;另外还有1块硬盘作为热备盘使用。 基于RAID5阵列划分的几个LUN分配给小机使用&#xff0c;存储空间通过LVM管理&#xff0c;重要数据为Oracle数据库及OA服务端。 服务器存储…

基于微信小程序的酒店客房管理系统+LW示例参考

1.项目介绍 系统角色&#xff1a;管理员、员工、普通用户功能模块&#xff1a;员工管理、用户管理、客房管理、预订管理、商品管理、评价管理、续订管理、订单管理等技术选型&#xff1a;SSM&#xff0c;vue&#xff0c;uniapp等测试环境&#xff1a;idea2024&#xff0c;jdk1…

学习Zookeeper

Zookeeper有手就行 1. 初识ZooKeeper1.1 安装ZooKeeper1.2 ZooKeeper命令操作1.2.1 Zookeeper数据模型1.2.2 Zookeeper 服务端常用命令1.2.3 Zookeeper客户端常用命令 2. ZooKeeperJavaAPl操作2.1 Curator介绍2.2 CuratorAPI常用操作2.2.0 引入Curator支持2.2.1 建立连接2.2.2 …

java基础知识(Math类)

引入&#xff1a;Math 类包含用于执行基本数学运算的方法&#xff0c;如初等指数、对数、平方根 import java.util.Math 1.abs绝对值 int abs Math.abs(-9); 2.pow求幂 double pow Math.pow(2,4); 3.向上取整 double ceil Math.ceil(3.9);//ceil 4 4.向下取整 dou…

【AIGC】大模型面试高频考点-RAG中Embedding模型选型

【AIGC】大模型面试高频考点-RAG中Embedding模型选型 &#xff08;一&#xff09;MTEB排行榜英文模型排名&#xff1a;1、bge-en-icl2、stella_en_1.5B_v53、SFR-Embedding-2_R4、gte-Qwen2-7B-instruct5、stella_en_400M_v56、bge-multilingual-gemma27、NV-Embed-v18、voyage…

学习threejs,使用设置normalMap法向量贴图创建更加细致的凹凸和褶皱

&#x1f468;‍⚕️ 主页&#xff1a; gis分享者 &#x1f468;‍⚕️ 感谢各位大佬 点赞&#x1f44d; 收藏⭐ 留言&#x1f4dd; 加关注✅! &#x1f468;‍⚕️ 收录于专栏&#xff1a;threejs gis工程师 文章目录 一、&#x1f340;前言1.1 ☘️THREE.MeshPhongMaterial高…

SAP ME2L/ME2M/ME3M报表增强添加字段

SAP ME2L/ME2M/ME3M报表增强添加字段&#xff08;包含&#xff1a;LMEREPI02、SE18:ES_BADI_ME_REPORTING&#xff09; ME2L、ME2M、ME3M这三个报表的字段增强&#xff0c;核心点都在同一个结构里 SE11:MEREP_OUTTAB_PURCHDOC 在这里加字段&#xff0c;如果要加的字段是EKKO、…

dubbo-go框架介绍

框架介绍 什么是 dubbo-go Dubbo-go 是 Apache Dubbo 的 go 语言实现&#xff0c;它完全遵循 Apache Dubbo 设计原则与目标&#xff0c;是 go 语言领域的一款优秀微服务开发框架。dubbo-go 提供&#xff1a; API 与 RPC 协议&#xff1a;帮助解决组件之间的 RPC 通信问题&am…

不只是请求和响应:使用Fiddler抓包URL和Method全指南(中)

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持! 不只是请求和响应&#xff1a;使用Fiddler抓包HTTP协议全指南(上)-CSDN博客https://blog.csdn.net/Chunfeng6yugan/article/details/144005872?spm1001.2014.3001.5502 &#x1f649;在(上)篇博客中&#xf…

Linux操作系统学习---初识环境变量

目录 ​编辑 环境变量的概念&#xff1a; 小插曲&#xff1a;main函数的第一、二个参数 获取环境变量信息&#xff1a; 1.main函数的第三个参数 2.查看单个环境变量 3.c语言库函数getenv() 和环境变量相关的操作指令&#xff1a; 1.export---导出环境变量&#xff1a; 2.unse…

跨平台应用开发框架(1)----Qt(组件篇)

目录 1.Qt 1.Qt 的主要特点 2.Qt的使用场景 3.Qt的版本 2.QtSDK 1.Qt SDK 的组成部分 2.安装 Qt SDK 3.Qt SDK 的优势 3.Qt初识 1.快速上手 widget.cpp mian.cpp widget.h Helloworld.pro 2.对象树 3.坐标系 4.信号和槽 1. 信号和槽的基本概念 2. 信号和槽的…

mysql索引失效的五种情况

第一种 违反最左前缀法则 这个是针对联合索引的。 假设有个tb_seller表&#xff0c;现在给三个字段建立联合索引&#xff0c;建立的时候字段顺序不可随便设置&#xff0c;字段顺序&#xff1a; name, status, address。下图Seq_in_index对应的是联合索引顺序。 判断索引失效用…

H3C OSPF 多区域实验

目录 前言 实验拓扑 实验需求 实验解析 路由器配置 测试 前言 此篇文章为 OSPF多区域试验&#xff0c;建议先食用OSPF单区域实验&#xff0c;理解实验原理 学习基本配置&#xff0c;再来使用此篇&#xff0c;效果更佳&#xff01;&#xff08;当然如果你已经了解原理与基…

算法 Java实现

一.查找算法 1.分块查找 二.排序算法 1.冒泡排序

优先算法 —— 双指针系列 - 快乐数

1. 快乐数 题目链接&#xff1a; 202. 快乐数 - 力扣&#xff08;LeetCode&#xff09;https://leetcode.cn/problems/happy-number/description/ 2. 题目解析 示例1&#xff1a; 示例2&#xff1a; 3. 算法原理 两种情况&#xff1a;我们可以把两种情况都看作为循环&#xff0…

【机器学习】——卷积与循环的交响曲:神经网络模型在现代科技中的协奏

&#x1f3bc;个人主页&#xff1a;【Y小夜】 &#x1f60e;作者简介&#xff1a;一位双非学校的大二学生&#xff0c;编程爱好者&#xff0c; 专注于基础和实战分享&#xff0c;欢迎私信咨询&#xff01; &#x1f386;入门专栏&#xff1a;&#x1f387;【MySQL&#xff0…

php 导出excel 一个单元格 多张图片

public function dumpData(){error_reporting(0); // 禁止错误信息输出ini_set(display_errors, 0); // 不显示错误$limit $this->request->post(limit, 20, intval);$offset $this->request->post(offset, 0, intval);$page floor($offset / $limit) 1 ;$wh…