[其他] C语言中的野指针

[复制链接]
 楼主| OKAKAKO 发表于 2024-6-18 08:42 | 显示全部楼层 |阅读模式
本帖最后由 OKAKAKO 于 2024-6-18 08:43 编辑

野指针,顾名思义,是指那些未被初始化或已经被释放但仍然被引用的指针。

1.野指针的成因
a.指针未初始化:在声明指针变量后,未对其进行初始化,导致指针指向未知的内存地址。

例如:

  1. 1#include <stdio.h>  
  2. 2
  3. 3int main(int argc, char *argv[]) {  
  4. 4    // 指针未初始化  
  5. 5    int *ptr;
  6. 6    // 试图在未初始化的指针上写入值,这是未定义行为  
  7. 7    *ptr = 10;
  8. 8    printf("Value: %d\n", *ptr);  
  9. 9    return 0;  
  10. 10}

在上述代码中,ptr 是一个指向 int 类型的指针,但它没有被初始化。紧接着的代码试图通过该指针向内存写入值 10,这是一个严重的错误,因为 ptr 可能指向任何随机的内存位置,导致不可预测的行为。

b.指针越界访问:访问数组或其他数据结构时,指针超出有效范围,指向非法内存。

例如:

  1. 1#include <stdio.h>  
  2. 2
  3. 3int main(int argc, char *argv[]) {  
  4. 4    int arr[5] = {1, 2, 3, 4, 5};  
  5. 5    // 指针指向数组的首元素
  6. 6    int *ptr = arr;
  7. 7
  8. 8   // 注意这里的循环条件是 i <= 5,会导致越界  
  9. 9    for (int i = 0; i <= 5; i++) {  
  10. 10        printf("%d ", *(ptr + i));  
  11. 11    }  
  12. 12
  13. 13    return 0;  
  14. 14}

在这个例子中,ptr 是一个指向数组 arr 首元素的指针。在循环中,我们试图访问从 arr[0] 到 arr[5] 的元素,但数组 arr 的有效索引范围是从0 到 4。因此,当 i 等于 5 时,*(ptr + i) 访问的是数组界限之外的内存,这同样是未定义行为。

c.错误地释放指针:误将指针设置为NULL,但之后仍然试图访问该指针,导致程序崩溃。

例如:

  1. 1#include <stdio.h>  
  2. 2#include <stdlib.h>  
  3. 3
  4. 4int main(int argc, char *argv[]) {  
  5. 5    int *ptr = (int *)malloc(sizeof(int)); // 分配内存  
  6. 6    if (ptr == NULL) {  
  7. 7        printf("Memory allocation failed.\n");  
  8. 8        return 1;  
  9. 9    }  
  10. 10
  11. 11    *ptr = 10;  
  12. 12    // 正确释放内存  
  13. 13    free(ptr);
  14. 14
  15. 15    // 错误:在释放内存后继续使用指针  
  16. 16    // 此时ptr是一个野指针,因为指向的内存已经被释放  
  17. 17    *ptr = 20;
  18. 18  // 未定义行为,可能会导致程序崩溃  
  19. 19    printf("Value: %d\n", *ptr);
  20. 20    return 0;  
  21. 21}

在这个例子中,我们首先使用 malloc 分配了一块内存,并通过指针 ptr 访问它。之后,我们正确地使用 free 释放了这块内存。然而,紧接着我们又试图通过同一个指针 ptr 向已经释放的内存写入值 20,这是不允许的。此时,ptr 变成了一个野指针,因为它指向的内存已经不属于程序了。尝试访问或修改这块内存是未定义行为。

请注意,以上示例代码中的行为都是未定义的,可能会导致程序崩溃、数据损坏或其他不可预测的后果。在实际编程中,应该始终避免这类错误。

 楼主| OKAKAKO 发表于 2024-6-18 08:43 | 显示全部楼层
2.野指针的防范策略
a.初始化指针:在声明指针变量时,应将其初始化为NULL或有效的内存地址。

例如:

  1. 1#include <stdio.h>  
  2. 2#include <stdlib.h>  
  3. 3
  4. 4int main(int argc, char *argv[]) {   
  5. 5    // 初始化指针为NULL  
  6. 6    int *ptr = NULL;
  7. 7
  8. 8    // 检查指针是否为NULL,再进行内存分配  
  9. 9    if (ptr == NULL) {  
  10. 10        ptr = (int *)malloc(sizeof(int));  
  11. 11        if (ptr == NULL) {  
  12. 12            printf("Memory allocation failed.\n");  
  13. 13            return 1;  
  14. 14        }  
  15. 15    }  
  16. 16
  17. 17    *ptr = 10;  
  18. 18    printf("Value: %d\n", *ptr);  
  19. 19
  20. 20    // 使用完内存后,释放它  
  21. 21    free(ptr);
  22. 22    // 将指针重置为NULL,避免成为悬挂指针  
  23. 23    ptr = NULL; // 将指针重置为NULL,避免成为悬挂指针  
  24. 24
  25. 25    return 0;  
  26. 26}

b.检查指针边界:在访问数组或其他数据结构时,确保指针在有效范围内。

例如:

  1. 1#include <stdio.h>  
  2. 2
  3. 3int main(int argc, char *argv[]) {  
  4. 4    int arr[5] = {1, 2, 3, 4, 5};  
  5. 5    int *ptr = arr;  
  6. 6    int index;  
  7. 7  // 确保索引在数组范围内  
  8. 8    for (index = 0; index < 5; index++) {
  9. 9        printf("%d ", *(ptr + index));  
  10. 10    }  
  11. 11
  12. 12    // 如果需要动态地确定数组的大小,请务必确保不要越界  
  13. 13    int size = sizeof(arr) / sizeof(arr[0]);  
  14. 14    for (index = 0; index < size; index++) {  
  15. 15        printf("%d ", arr[index]);  
  16. 16    }  
  17. 17
  18. 18    return 0;  
  19. 19}

c.避免误操作:不要随意修改指针的值,特别是在不知道指针指向的具体内容时。

例如:

  1. 1#include <stdio.h>  
  2. 2
  3. 3void modifyPointerSafely(int **pptr, int newValue) {
  4. 4    // 只有在确认pptr和*pptr都有效时才修改指针指向的值
  5. 5    if (pptr != NULL && *pptr != NULL) {   
  6. 6        **pptr = newValue;
  7. 7    }  
  8. 8}  
  9. 9
  10. 10int main(int argc, char *argv[]) {  
  11. 11    int *ptr = (int *)malloc(sizeof(int));  
  12. 12    if (ptr == NULL) {  
  13. 13        printf("Memory allocation failed.\n");  
  14. 14        return 1;  
  15. 15    }  
  16. 16
  17. 17    *ptr = 10;  
  18. 18    printf("Original value: %d\n", *ptr);  
  19. 19
  20. 20    // 安全地修改指针指向的值  
  21. 21    modifyPointerSafely(&ptr, 20);
  22. 22    printf("Modified value: %d\n", *ptr);  
  23. 23
  24. 24    free(ptr);  
  25. 25    ptr = NULL;  
  26. 26
  27. 27    return 0;  
  28. 28}

在这个例子中,我们定义了一个函数modifyPointerSafely,它接受一个指向指针的指针和一个新值。这个函数在修改指针指向的值之前,首先检查传入的指针和它所指向的指针是否都不为NULL。这样可以确保我们不会意外地修改一个无效的指针。

请注意,虽然这些示例展示了如何防范野指针的常见策略,但在实际编程中,还需要结合代码审查、动态分析工具和其他安全措施来确保程序的健壮性。

LOVEEVER 发表于 2024-7-15 14:52 | 显示全部楼层
任何时候一定要初始化参数
szt1993 发表于 2024-7-17 19:04 | 显示全部楼层
野指针,是指那些未被初始化或已经被释放但仍然被引用的指针,一定要非常重要
您需要登录后才可以回帖 登录 | 注册

本版积分规则

257

主题

2006

帖子

4

粉丝
快速回复 在线客服 返回列表 返回顶部