C指针(野指针、空指针)

  在C语言中,指针是最常用也是最容易出错的地方,不规范使用指针很容易造成程序奔溃,在代码中应该谨慎使用指针,避免产生和使用野指针。所谓野指针,就是该指针是一个随机的地址值,这个随机值可以指向任何不确定的存储空间,因此会导致编译错误或是其他更严重的问题。

两种野指针

  1. 指针没有对应任何真实的存储空间 :这种情况会导致编译错误,编译器会产生告警信息帮助我们排查;
  2. 指针指向其他存储空间:如果指向空间不允许操作,编译器也会提示错误;但如果所指向的空间允许操作,则很可能会导致某个存储空间的数据被篡改,这种编译器不会报错,很难排查;

如何避免产生野指针?

定义指针变量必须要初始化,而且操作指针变量前最好先判断指针是否为空。

初始化指针

int a = 100;
int *p1 = &a;    // 初始化为需要的值
int *p2 = NULL;  // 当不确定初始化为何值时,初始为NULL

将指针初始化为 NULL 的好处在于:当忘了给指针变量复制一个合法指针时,已经被初始化为NULL的指针在编译时会提示错误,便于排查错误

使用前判空

int a = 100;
int *p = &a;
if(NULL != p) {
    printf("p 中所存放的指针为:%p \n",p);    // p -> &a
    *p = 200;  // 当p所指向空间不为空时,才能进行解引用
}
printf("p所指向的空间存放的值为:%d \n",*p);    // *p 解引用

NULL的定义

NULL 的宏定义在 stddef.h 中,如下:

#if defined (__cplusplus)
#define NULL 0    //在C++ 中 NULL 代表 0
#else 
#define NULL ((void*)0)    //在C中 NULL 表示 (void *)0
#endif

段错误

在Linux系统中的指针错误,称为段错误(Segmentation fault)。程序中使用野指针就可能出现段错误,如没有初始化的全局指针变量或局部指针变量。
以下情况会出现段错误:
1.指针所指向的空间不存在
2.指针所指向的空间存在,但没有读写权限

什么是空指针?

空指针,即 void *,在使用空指针时,必须先强制转换数据类型,然后才可以正常使用。malloc函数返回的指针就是 void * 类型

void *malloc(size_t size);
// 因此在开辟动态内存空间时,需要对malloc返回的指针做强制转换,转换成需要的指针类型
int *p = (int *)malloc(sizeof(int));

void * 类型

通过 void * 用来兼容传递不同类型的指针,如下:

typedef struct student {  
    int number;
    char name[10];
}Stu;

static int kind_tmp(int num, void *addr) {
    switch(num) {
    case 1:
        *((int *)addr) = 100;    // 将 addr 强制转换为 int *类型
	break;
    case 2:
        *((double *)addr) = 3.1415;
        break;
    case 3:
        ((Stu *)addr) -> number = 3837;    // 将 addr 强制转换为 Stu * 类型
        strcpy(((Stu *)addr) -> name, "xiaoma");
        break;
    default:
        printf("The point kind error");
    }
    return 0;
}
int main() {
    int a = 0;
    double b = 0;
    Stu s = {0};
    kind_tmp(1, (void *)&a);    // 在传参之前将(int*)转换为(void*),方可传参
    printf("变量将被赋值为 a = %d \n",a);
    kind_tmp(2, (void *)&b);
    printf("变量将被赋值为 a = %lf \n",b);
    kind_tmp(3, (void *)&s);
    printf("变量将被赋值为 number: %d \n",s.number);
    printf("变量将被赋值为 name: %s \n",s.name);
    return 0;
}

以上程序输出结果如下:

变量将被赋值为 a = 100
变量将被赋值为 a = 3.141500
变量将被赋值为 number: 3837
变量将被赋值为 name: xiaoma

发布了52 篇原创文章 · 获赞 81 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/xiaoma_2018/article/details/88728936