打印
[其他]

C语言中的野指针

[复制链接]
373|1
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
OKAKAKO|  楼主 | 2024-6-18 08:42 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 OKAKAKO 于 2024-6-18 08:43 编辑

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

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

例如:

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

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

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

例如:

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

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

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

例如:

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

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

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

使用特权

评论回复

相关帖子

沙发
OKAKAKO|  楼主 | 2024-6-18 08:43 | 只看该作者
2.野指针的防范策略
a.初始化指针:在声明指针变量时,应将其初始化为NULL或有效的内存地址。

例如:

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

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

例如:

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

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

例如:

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

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

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

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

168

主题

1248

帖子

3

粉丝