「程序员面试」一文搞懂野指针、悬空指针、空指针和内存泄漏,附代码示例!

野指针、悬空指针、空指针和内存泄漏是内存管理中四个重要概念。
野指针:指针变量未被初始化,或者被赋予了一个随意的、无效的地址值。它指向的内存区域可能是随机的,使用野指针会导致程序出现不可预测的行为,如程序崩溃或数据损坏
悬空指针:指针原来指向的内存已经被释放(例如通过free函数),但指针本身没有被置为NULL,仍然保存着之前内存的地址。再尝试访问这个指针所指向的已释放内存,就会产生错误。
空指针:一个特殊的指针值,它不指向任何有效的内存地址。C语言中通常用NULL表示,可用于初始化指针变量,或者在指针不指向有效地址时作为一个明确的标识。对空指针进行解引用操作是不允许的,会导致程序出错。
内存泄漏:指程序在动态分配内存(例如使用malloc、calloc等函数)后,没有释放这些内存,导致这些内存块在程序运行过程中一直被占用,无法被操作系统重新利用。随着程序的运行,内存泄漏会逐渐消耗系统内存,导致程序性能下降甚至系统崩溃。
总结,野指针和悬空指针指向无效内存(通常可以统一称为野指针),空指针则明确不指向任何内存,而内存泄漏则是未释放的有效内存,三者均可能导致程序错误和性能问题。
野指针代码示例

#include <stdio.h>
int main() {
    int *wild_ptr;
    // 没有初始化wild_ptr,它是野指针
    // 下面这行代码可能会导致错误,因为wild_ptr指向的位置不确定
    *wild_ptr = 5;
    return 0;
}
在这个例子中,指针wild_ptr没有被初始化就进行解引用操作,它指向的位置是不确定的,可能会导致程序崩溃或者出现不可预期的行为。
空指针代码示例
#include <stdio.h>
int main() {
    int *null_ptr = NULL;
    // 下面这行代码会导致程序出错,因为不能对空指针解引用
    *null_ptr = 10;
    return 0;
}

悬空指针代码示例

#include <stdio.h>
#include <stdlib.h>
int main() {
    int *ptr = (int *)malloc(sizeof(int));
    *ptr = 10;
    free(ptr);
    // ptr现在是悬空指针,下面的操作会导致未定义行为
    *ptr = 20;
    return 0;
}

在这里,通过free函数释放了指针ptr所指向的内存空间,之后ptr就变成了悬空指针。再对ptr进行解引用操作是不合法的,会导致未定义行为。
内存泄漏代码示例

#include <stdio.h>
#include <stdlib.h>
void func() {
    int *leak_ptr = (int *)malloc(sizeof(int));
    *leak_ptr = 5;
    // 没有释放leak_ptr所指向的内存,产生内存泄漏
}
int main() {
    memory_leak_function();
    // 函数调用结束后,之前分配的内存没有被释放
    return 0;
}

在func函数中,动态分配了一块内存给指针leak_ptr,但是在函数结束时没有释放这块内存。这样,每次调用该函数,就会有一块内存被占用而无法回收,造成内存泄漏。如果频繁调用,会导致程序内存占用越来越大,最终可能耗尽系统资源。
面试建议

  1. 对于野指针、悬空指针、空指针和内存泄露,是我们开发过程中经常会遇到的问题,一定要理解其原理以及如何规避。这是计算机非常重要的基础知识。
  2. 在移动端开发过程中,内存泄漏是一个常见的问题,可能导致应用性能下降或崩溃。
    以下是几种常见的内存泄漏场景
    使用闭包(closure)时,如果闭包强引用了外部对象,而外部对象又强引用了闭包,就会形成循环引用,导致内存无法释放。
    在使用资源(如图像、视频或数据库连接)时,如果没有在不需要的时候释放它们,可能会导致内存泄漏。
    如何规避内存泄漏:
    使用弱引用:避免循环引用。
    资源管理:确保在不需要时释放大型资源。
    使用内存分析工具:如 Android Profiler 或 Xcode Instruments,帮助检测内存泄漏。
posted @ 2024-11-23 07:35  Newton爱编程  阅读(43)  评论(0编辑  收藏  举报