class="tags" href="/C.html" title=
c>
content_views"
class="tags" href="/C.html" title=
c>
class="markdown_views prism-tomorrow-night">
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/class="tags" href="/C.html" title=c>cb7f73class="tags" href="/C.html" title=c>cda1a14130840e356class="tags" href="/C.html" title=c>cb0b6f9e4.png#piclass="tags" href="/C.html" title=c>c_class="tags" href="/C.html" title=c>center" alt="在这里插入图片描述" width="100" />
<
class="tags" href="/C.html" title=
c>
center>
博客主页: [小ᶻ☡꙳ᵃⁱᵍᶜ꙳]
class="tags" href="/C.html" title=
c>
center>
<
class="tags" href="/C.html" title=
c>
center>
本文专栏: C语言
class="tags" href="/C.html" title=
c>
center>
class="tags" href="/C.html" title=c>c="https://img-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/00d4fdeb7b0d4dbb99e88f325ef249d8.gif#piclass="tags" href="/C.html" title=c>c_class="tags" href="/C.html" title=c>center" alt="在这里插入图片描述" width="1000" height="100" />
💯前言
- C语言是一门以其高效和灵活著称的编程语言class="tags" href="/C.html" title=c>c;但与其高效性伴随而来的class="tags" href="/C.html" title=c>c;是需要开发者非常小心地管理内存。野指针(<class="tags" href="/C.html" title=c>code>Dangling Pointerclass="tags" href="/C.html" title=c>code>)是 C 语言中的一个常见问题class="tags" href="/C.html" title=c>c;指针的错误使用可能导致程序崩溃、数据泄露class="tags" href="/C.html" title=c>c;甚至被攻击者利用class="tags" href="/C.html" title=c>c;成为严重的安全漏洞。
在本文中class="tags" href="/C.html" title=c>c;我们将详细讲解野指针的三种常见情形class="tags" href="/C.html" title=c>c;分析它们的成因、危害以及如何防范class="tags" href="/C.html" title=c>c;并通过<class="tags" href="/C.html" title=c>code>代码示例class="tags" href="/C.html" title=c>code>让大家深入理解这些问题。
C语言
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/2562ddclass="tags" href="/C.html" title=c>cd78164994b20b50class="tags" href="/C.html" title=c>c5class="tags" href="/C.html" title=c>cd0130e3.png#piclass="tags" href="/C.html" title=c>c_class="tags" href="/C.html" title=c>center" alt="在这里插入图片描述" />
💯什么是野指针?
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
野指针是指向无法预测的内存地址的指针class="tags" href="/C.html" title=c>c;其指向的地址往往是随机的、无效的或已失效的内存区域。当程序通过一个野指针去访问内存时class="tags" href="/C.html" title=c>c;可能引发程序崩溃(如段错误)或者产生未定义行为。
在 C语言 中class="tags" href="/C.html" title=c>c;指针是基础特性之一class="tags" href="/C.html" title=c>c;赋予程序员直接操作内存的能力class="tags" href="/C.html" title=c>c;这也是 C 语言的灵活性和高效性所在。然而class="tags" href="/C.html" title=c>c;正是由于这种直接操作内存的能力class="tags" href="/C.html" title=c>c;使得野指针问题在 C 语言中尤为常见且危险。
💯未初始化的指针
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
未初始化的指针是指在定义指针变量时class="tags" href="/C.html" title=c>c;未为其赋予初始值的指针。这种指针所包含的地址值是随机的class="tags" href="/C.html" title=c>c;可能指向程序的任意内存区域class="tags" href="/C.html" title=c>c;从而导致未定义行为。
代码示例
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">mainclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 定义了一个指针变量 pclass="tags" href="/C.html" title=c>c;但未初始化class="tags" href="/C.html" title=c>class="token operator">*p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">20class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 尝试通过 p 修改它指向的内存class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
问题分析
- 在 <class="tags" href="/C.html" title=c>code>int* p;class="tags" href="/C.html" title=c>code> 这行代码中class="tags" href="/C.html" title=c>c;指针 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 被定义class="tags" href="/C.html" title=c>c;但并未被初始化class="tags" href="/C.html" title=c>c;因此它的值是随机的class="tags" href="/C.html" title=c>c;指向不可预测的内存位置。
- 当执行 <class="tags" href="/C.html" title=c>code>*p = 20;class="tags" href="/C.html" title=c>code> 时class="tags" href="/C.html" title=c>c;程序试图向一个未知内存位置写入数据class="tags" href="/C.html" title=c>c;这引发未定义行为class="tags" href="/C.html" title=c>c;可能导致程序崩溃(例如段错误)或引发安全漏洞。
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
解决方法
- 显式初始化指针:定义指针时class="tags" href="/C.html" title=c>c;将其初始化为 <class="tags" href="/C.html" title=c>code>NULLclass="tags" href="/C.html" title=c>code>class="tags" href="/C.html" title=c>c;这样可以确保指针不会指向任何有效的内存区域class="tags" href="/C.html" title=c>c;直到它被显式赋值。
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>constant">NULLclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>code>
- 分配合法的内存:在使用指针之前class="tags" href="/C.html" title=c>c;确保它指向有效的内存class="tags" href="/C.html" title=c>c;可以通过动态分配内存或者将其指向已有的变量。
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">int a class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token operator">&aclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 指针指向变量 a 的地址
class="tags" href="/C.html" title=c>code>
- 启用编译器警告:现代编译器通常提供一些有用的警告选项class="tags" href="/C.html" title=c>c;例如 <class="tags" href="/C.html" title=c>code>-Wallclass="tags" href="/C.html" title=c>code>class="tags" href="/C.html" title=c>c;能够帮助开发者检测未初始化的指针并减少潜在的错误。
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
💯指针越界访问
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
指针越界访问是指一个指针超出其合法内存范围class="tags" href="/C.html" title=c>c;从而访问非法区域的情形。这种情况同样可能导致野指针的产生class="tags" href="/C.html" title=c>c;并引发未定义行为。
代码示例
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">mainclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">int arrclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">[class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">] class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token number">1class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">2class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">3class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">4class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">5class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">6class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">7class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">8class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">9class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 定义数组并初始化class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token operator">*p class="tags" href="/C.html" title=c>class="token operator">= arrclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 指针 p 指向数组首元素class="tags" href="/C.html" title=c>class="token keyword">int i class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;class="tags" href="/C.html" title=c>class="token keyword">int sz class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token keyword">sizeofclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(arrclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token operator">/ class="tags" href="/C.html" title=c>class="token keyword">sizeofclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(arrclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">[class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">]class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 计算数组大小class="tags" href="/C.html" title=c>c;sz = 10class="tags" href="/C.html" title=c>class="token keyword">for class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(i class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; i class="tags" href="/C.html" title=c>class="token operator"><= szclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; iclass="tags" href="/C.html" title=c>class="token operator">++class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 注意这里的循环条件为 i <= szclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">printfclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token string">"%d "class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token operator">*pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 试图打印指针 p 所指向的值pclass="tags" href="/C.html" title=c>class="token operator">++class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 指针 p 向后移动class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
问题分析
- 在 <class="tags" href="/C.html" title=c>code>for (i = 0; i <= sz; i++)class="tags" href="/C.html" title=c>code> 这一行中class="tags" href="/C.html" title=c>c;<class="tags" href="/C.html" title=c>code>i <= szclass="tags" href="/C.html" title=c>code> 使得循环多执行了一次class="tags" href="/C.html" title=c>c;导致 <class="tags" href="/C.html" title=c>code>i == szclass="tags" href="/C.html" title=c>code> 时class="tags" href="/C.html" title=c>c;指针 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 指向了数组边界之外的内存位置class="tags" href="/C.html" title=c>c;从而产生了野指针。
- 试图通过 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 访问 <class="tags" href="/C.html" title=c>code>arrclass="tags" href="/C.html" title=c>code> 数组之外的内存是非法操作class="tags" href="/C.html" title=c>c;可能导致程序崩溃class="tags" href="/C.html" title=c>c;或者引发不易检测的安全问题。
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
解决方法
- 修正循环条件:将循环条件改为 <class="tags" href="/C.html" title=c>code>i < szclass="tags" href="/C.html" title=c>code>class="tags" href="/C.html" title=c>c;确保指针始终在数组的合法范围内。
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">for class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(i class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; i class="tags" href="/C.html" title=c>class="token operator">< szclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; iclass="tags" href="/C.html" title=c>class="token operator">++class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)
class="tags" href="/C.html" title=c>code>
- 加强边界检查:在操作指针时进行边界检查class="tags" href="/C.html" title=c>c;确保不会超出合法的数组范围。
- 避免手动递增指针:可以直接使用数组下标访问元素class="tags" href="/C.html" title=c>c;避免手动管理指针的移动class="tags" href="/C.html" title=c>c;以降低出错风险。
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">for class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(i class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; i class="tags" href="/C.html" title=c>class="token operator">< szclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; iclass="tags" href="/C.html" title=c>class="token operator">++class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">printfclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token string">"%d "class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, arrclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">[iclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">]class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
💯指向已释放内存的指针(悬空指针)
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
悬空指针是指向已释放或生命周期结束的内存区域的指针。当函数返回局部变量的地址class="tags" href="/C.html" title=c>c;或内存被释放后仍继续使用该指针class="tags" href="/C.html" title=c>c;就会导致悬空指针的问题。
代码示例
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">int a class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 定义局部变量 aclass="tags" href="/C.html" title=c>c;并初始化为 10class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token operator">&aclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 返回局部变量 a 的地址
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">mainclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 函数返回的局部变量地址赋值给指针 pclass="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">printfclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token string">"%d\n"class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token operator">*pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 通过 p 访问无效内存class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
问题分析
- 在 <class="tags" href="/C.html" title=c>code>testclass="tags" href="/C.html" title=c>code> 函数中class="tags" href="/C.html" title=c>c;变量 <class="tags" href="/C.html" title=c>code>aclass="tags" href="/C.html" title=c>code> 是局部变量class="tags" href="/C.html" title=c>c;存储在栈中。当函数执行完毕后class="tags" href="/C.html" title=c>c;<class="tags" href="/C.html" title=c>code>aclass="tags" href="/C.html" title=c>code> 所在的栈帧被释放class="tags" href="/C.html" title=c>c;其地址变得无效。
- 指针 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 存储了 <class="tags" href="/C.html" title=c>code>aclass="tags" href="/C.html" title=c>code> 的地址class="tags" href="/C.html" title=c>c;然而此时 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 成为了悬空指针class="tags" href="/C.html" title=c>c;继续通过 <class="tags" href="/C.html" title=c>code>pclass="tags" href="/C.html" title=c>code> 访问该内存区域会导致未定义行为class="tags" href="/C.html" title=c>c;可能引发程序崩溃或输出错误数据。
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
解决方法
class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/f174eb4775f94class="tags" href="/C.html" title=c>c6bb7a04d0f9035b4e9.png#piclass="tags" href="/C.html" title=c>c_right" alt="在这里插入图片描述" width="1" />
-
避免返回局部变量的地址
- 可以通过动态内存分配或者静态变量来替代返回局部变量的地址。
示例 1:动态内存分配
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* a class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">*class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">malloclass="tags" href="/C.html" title=c>cclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token keyword">sizeofclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 动态分配内存class="tags" href="/C.html" title=c>class="token operator">*a class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;class="tags" href="/C.html" title=c>class="token keyword">return aclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 返回分配的内存地址
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">mainclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">printfclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token string">"%d\n"class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token operator">*pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 正常访问class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">freeclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 用完后释放内存class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
示例 2:使用静态变量
<class="tags" href="/C.html" title=c>code class="tags" href="/C.html" title=c>class="prism language-class="tags" href="/C.html" title=c>c">class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">staticlass="tags" href="/C.html" title=c>c class="tags" href="/C.html" title=c>class="token keyword">int a class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token number">10class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 静态变量class="tags" href="/C.html" title=c>c;生命周期贯穿程序运行class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token operator">&aclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 返回静态变量的地址
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}class="tags" href="/C.html" title=c>class="token keyword">int class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">mainclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">) class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">{class="tags" href="/C.html" title=c>class="token keyword">intclass="tags" href="/C.html" title=c>class="token operator">* p class="tags" href="/C.html" title=c>class="token operator">= class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">testclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;class="tags" href="/C.html" title=c>class="token funclass="tags" href="/C.html" title=c>ction">printfclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">(class="tags" href="/C.html" title=c>class="token string">"%d\n"class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">, class="tags" href="/C.html" title=c>class="token operator">*pclass="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">)class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">; class="tags" href="/C.html" title=c>class="token class="tags" href="/C.html" title=c>comment">// 正常访问class="tags" href="/C.html" title=c>class="token keyword">return class="tags" href="/C.html" title=c>class="token number">0class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">;
class="tags" href="/C.html" title=c>class="token punclass="tags" href="/C.html" title=c>ctuation">}
class="tags" href="/C.html" title=c>code>
-
确保指针始终指向有效内存
- 在函数中返回指针时class="tags" href="/C.html" title=c>c;必须确保返回的指针指向的内存是有效的class="tags" href="/C.html" title=c>c;且不会在函数执行完毕后失效。
-
使用内存管理工具
- 现代的内存管理工具(如 Valgrind 或 AddressSanitizer)可以有效地检测悬空指针问题class="tags" href="/C.html" title=c>c;帮助开发者在开发和测试阶段发现和修复内存管理错误。
💯小结
- class="tags" href="/C.html" title=c>c="https://i-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/76854class="tags" href="/C.html" title=c>c469808448b9ba55a18730class="tags" href="/C.html" title=c>c9e11.png#piclass="tags" href="/C.html" title=c>c_class="tags" href="/C.html" title=c>center" alt="在这里插入图片描述" />在 C语言编程 中class="tags" href="/C.html" title=c>c;指针的管理是至关重要的环节。C语言赋予开发者直接操作内存的能力class="tags" href="/C.html" title=c>c;使得程序能够具备极高的性能class="tags" href="/C.html" title=c>c;但这种能力也伴随着巨大的责任。
开发者需要掌握 指针的生命周期 以及它们在内存中的行为class="tags" href="/C.html" title=c>c;从而确保程序的稳定和安全。在大型项目中class="tags" href="/C.html" title=c>c;内存管理和指针操作尤为重要class="tags" href="/C.html" title=c>c;团队开发时需要制定明确的标准和代码规范class="tags" href="/C.html" title=c>c;以避免因个人疏忽导致的<class="tags" href="/C.html" title=c>code>指针错误class="tags" href="/C.html" title=c>code>。
此外class="tags" href="/C.html" title=c>c;测试和代码审查也应作为内存管理的重要环节class="tags" href="/C.html" title=c>c;以确保代码在各种边界条件下都能正确运行。
class="tags" href="/C.html" title=c>c="https://img-blog.class="tags" href="/C.html" title=c>csdnimg.class="tags" href="/C.html" title=c>cn/direclass="tags" href="/C.html" title=c>ct/00d4fdeb7b0d4dbb99e88f325ef249d8.gif#piclass="tags" href="/C.html" title=c>c_class="tags" href="/C.html" title=c>center" alt="在这里插入图片描述" width="1000" height="100" />