大白话说一说C++指针的非法访问 非AI生成觉得有用就请您帮忙点赞转发收藏吧多谢看官。目录非法访问指针access violation的危害非法访问指针的常见行为1.野指针wild pointer2.悬空指针dangling pointer3.双重释放double free4.越界访问out-of-bounds access‌总结非法访问指针access violation的危害C程序运行速度快指针在这里面绝对是个大功臣通过指针就能直接操作内存区域的数据可以实现零开销抽象、零拷贝和高效数据结构。为了追求极致的运行速度C几乎舍弃了指针检查如果每次访问指针都先检查指针是否合法势必会影响程序的运行速度。C太信任程序了默认程序通过指针在访问合法的内存数据也把指针检查交给了程序但如果指针使用不当就相当于给程序埋下了一颗定时炸弹常见的非法访问指针也可以算是C编程中的头等”罪行“操作系统一旦发现这种行为就算您写了Try-Catch来捕获异常操作系统也会视而不见生怕程序再闯出什么大祸不会给程序改过自新的机会来继续运行运气差点时操作系统直接结束程序的生命也就是软件崩溃或闪退有时可能运气好点操作系统没有立即出手但不会影响程序的最终命运操作系统终归会在某个时刻给程序判”死刑“并立即执行。非法访问指针的常见行为1.野指针wild pointer野指针是代码中只定义但没有指向一块合法可用内存地址的指针指针p的值不为空而是一个”垃圾值“这时使用if(p)来判断指针的合法性是无效的如果对指针进行解引用操作就会导致程序崩溃。大白话理解的话就是小孩出生了出生证都还没办呢您就想去上户口搞这搞那的。#include QApplication #include QDebug int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()C野指针测试; // 只定义了指针但指针没有指向一块合法和可用的内存区域 // p的值不为空而是随机指向了一块它没有访问权限的内存区域p的值是一个”垃圾地址“ int *p; if(p){ // 此处if判断不起作用程序会对野指针执行解引用操作 // 野指针解引用触发未定义行为Undefined Behavior, UB一般都会导致程序立即闪退 *p 10; } return a.exec(); }程序运行截图那如何预防野指针呢预防野指针的办法很简单最简单的办法定义的时候置空就可以了动态分配内存后再重新给它赋值即可。#include QApplication #include QDebug int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()C野指针测试; int *p nullptr; // 指针置空 if(p){ // 此处if判断不成立 *p 10;// 此行代码不会执行 } return a.exec(); }2.悬空指针dangling pointer有些翻译也译作悬垂指针悬空指针曾经指向了一块合法可用的内存区域但被程序执行了free或delete操作导致指针已经没有访问这块内存区域的权限了但指针的值还是那块内存区域的地址。大白话理解的话就是曾经有个合法的土地证但后面那个土地证被注销了您还想搬出那个旧证准备在那块地盖房子那就属于违建了。#include QApplication #include QDebug int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()C悬空指针测试; int *p new int(0); // 初始化指针指针指向一块合法和可用的内存区域 if(p){ *p 10; // 修改内存区域的数据 } qDebug()打印p指向的内存区域的数据:*p; delete p; // 释放p指向的内存区域 if(p){ *p 20; // 修改内存区域的数据 qDebug()打印p指向的内存区域的数据:*p; } return a.exec(); }程序运行截图那如何预防悬空指针呢对于C初学者如果您不再需要使用这块内存区域执行free或delete操作后务必将指针置空这是一个习惯也是一条铁律能帮助我们避免不必要的麻烦。等您学到C的智能指针使用智能指针和RAII几乎能避免绝大多数的悬空指针访问。#include QApplication #include QDebug int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()C悬空指针测试; int *p new int(0); // 初始化指针指针指向一块合法和可用的内存区域 if(p){ *p 10; // 修改内存区域的数据 } qDebug()打印p指向的内存区域的数据:*p; delete p; // 释放p指向的内存区域 p nullptr; if(p){ *p 20; // 修改内存区域的数据 qDebug()打印p指向的内存区域的数据:*p; } return a.exec(); }3.双重释放double free如果您对指针执行两次free或delete操作就属于双重释放这也是严令禁止的。双重释放也会导致未定义行为一般也会导致程序直接结束。出现这种问题比较常见的情况是违背了指针谁创建谁销毁的原则例如在某个函数正常初始化了一个指针但可能在多个函数都执行了释放操作。#include QApplication #include QDebug int main(int argc, char *argv[]) { QApplication a(argc, argv); qDebug()C指针双重释放测试; int *p new int(0); // 初始化指针指针指向一块合法和可用的内存区域 if(p){ *p 10; // 修改内存区域的数据 } qDebug()打印p指向的内存区域的数据:*p; delete p; // 第一次释放p指向的内存区域 delete p;// 第二次释放p指向的内存区域 p nullptr; if(p){ *p 20; // 修改内存区域的数据 qDebug()打印p指向的内存区域的数据:*p; } return a.exec(); }程序运行截图那如何避免指针的双重释放呢初学者记住一个原则指针谁创建谁释放在主线程创建的由主线程释放在子线程创建的由子线程释放在模块A创建的由模块A释放。不是你负责的活你不要去抢活干。释放资源后指针务必置空释放资源前务必判断指针是否为空。养成这个好习惯也能避免绝大部分的指针双重释放问题。4.越界访问out-of-bounds access‌越界访问是指针访问了不属于它的合法内存范围的数据也是C中严令禁止的高危行为。指针越界访问在 C 中属于未定义行为程序可能崩溃、产生错误结果也可能看似正常运行因此必须在编码阶段通过边界检查和工具检测来避免。常见的越界访问有以下几种1.数组越界int a[5] {1,2,3,4,5}; int *p a; p[5] 10; // ❌ 越界最大合法索引是 4 *(p 6) 20; // ❌ 越界2.指针偏移越界int arr[3] {1,2,3}; int *p arr 3; // 指向末尾之后允许 *p 10; // ❌ 解引用越界3.malloc或new之后的越界int *p new int[10]; p[10] 5; // ❌ 越界那如何避免指针越界访问呢避免指针越界访问比避免悬空指针访问要容易很多关键是做好边界检查和条件判断不是您能访问的内存区域千万不要随便访问。有以下几种办法供您参考1.能用容器就别用裸指针std::vectorint v(10); v.at(i) x; // 自动检查2.明确长度永远带边界判断if (index 0 index size) { p[index] x; }3.指针遍历时写“死边界”int *end arr len; for (int *p arr; p end; p) { ... }4.工具检测强烈推荐工具作用AddressSanitizer (-fsanitizeaddress)检测越界、野指针Valgrind内存错误分析总结C程序中的非法访问指针几乎可以说是C编程中最致命的问题也是现代C之前较难排查的问题随着现代C11/14/17/20发布基本可以依靠智能指针、STL容器、RAII规则、程序逻辑检查Code Review、单元测试、工具检测来避免非法访问指针的问题。Bjarne StroustrupC 之父曾经说过”资源管理是编写可靠软件的关键之一“并将其视为当代 C 设计的核心原则。由于知识水平有限难免会有错误或不严谨的地方欢迎批评指正。