C语言基础:野指针、空指针、空悬指针

server/2025/1/12 13:02:34/

野指针、空指针、空悬指针

野指针

定义:只想一块未知区域(以及销毁或者访问受限的内存区域外的已存在或不存在的内存区域)的指针,被称作野指针。野指针是危险的。

危害:

① 引用野指针,相当于访问了非法的内存,常常会导致段错误(segmentation fault),也有可能编译运行不报错。

② 引用野指针,可能会破坏系统的关键数据,导致系统崩溃等严重后果

野指针产生的场景:

  1. 变量未初始化,通过指针访问该变量

     int a;int *p = &a;//p是野指针printf("%d\n",*p);//访问野指针,数据不安全
  2. 指针变量未初始化

     int *p; // p 是野指针printf("%d\n",*p);​int a = get();p = &a;
  3. 指针指向的内存空间被(free)回收了

     int *p = malloc(4);*p = 12;//此时的p不是野指针free(p);printf("%d\n",*p); // 此时的p就是野指针
  4. 指针函数中直接返回了局部变量的地址

     int *get_num(){int a = 15;int *p = &a;//此时p对应的数据是一个局部作用域的数据return p;}main(){int *p = get_num();//此时p是野指针}

如何避免野指针?

  1. 指针变量要及时初始化,如果暂时没有对应的值,建议赋初值NULL。

  2. 数组操作(遍历和指针运算)时,注意数组的长度,避免越界

  3. 指针指向的内存空间被回收,建议给这个指针遍历赋值为NULL

     int *p = (int *)malloc(10);free(p);p = NULL;
  4. 指针遍历使用之前要检查它的有效性(非空检验)

     int *p = NULL;// if(p == NULL)if(!p){return -1;}

空指针

很多情况下,我们不可避免的会遇到野指针,比如刚定义的指针无法立即为其分配一块恰当的内存,又或者指针指向的内存已经被释放了等等。一般的做法是将这些危险的野指针指向一块确定的内存,比如零地址内存(NULL)。

定义:空指针即保存了零地址的指针(赋值为NULL的指针),也就是指向零地址的指针。(NULL是空常量,它的值是0,这个NULL一般存放在内存0x0000 0000的位置,这个地址只能存NULL,不能被其他程序修改)

示例:

 // 1.刚定义的指针,让其指向零地址以确保安全char *p1 = NULL;int *p2 = NULL;​// 2.被释放了内存的指针,让其指向零地址以确保安全char *p3 = malloc(100);free(p3);p3 = NULL;

空悬指针

在C语言中,悬空指针指的是指向已删除(或释放)的内存位置的指针。如果一个指针指向的内存已经被释放,但指针本身并未重新指向其他有效的内存地址,那么这个指针就变成了悬空指针。悬空指针会引发不可预知的错误,并且如果一旦发生,就很难定位,因此在编程中尽量避免使用悬空指针。

 // 2.被释放了内存的指针,让其指向零地址以确保安全char *p3 = malloc(100);free(p3);printf("%p,%c\n",p3,*p3);//此时地址依然可以访问,但是地址对应的原本数据不可访问

void与void*的区别

定义:

  • void:是空类型,是数据类型的一种

  • void*:是指针类型,是指针类型的一种,可以匹配任意类型的指针,类似与通配符,又被叫做万能指针。

void:

  • 说明:void作为返回值类型说明,表示没有返回值;作为形参,表示形参列表为空,在调用的时候不能给实参

  • 举例:

 //函数定义void fun(void){..}//等效于 void fun(){..}//函数调用fun();

void*:

  • 说明:

    • void*是一个指针类型,但该指针的数据类型不明确,无法通过解引用获取内存中的数据,因为void*不知道访问几个内存单元。

    • void*是一种数据类型可以作为函数返回值类型,也可以作为形参类型

    • void*类型的变量在使用之前必须强制类型转换,明确它能够访问几个字节的内存空间

     int *p = (int*)malloc(4);
  • 说明:

    • void*作为返回值类型,这个函数可以返回任意类型的指针

    • void*作为形参类型,这个函数在调用时,可以给任意类型的指针

  • 总结:

    • void*类似于通配符,不能对void*类型的变量解引用(因为不明确数据类型,所以无法确定内存单元的大小)

    • void*在间接访问(解引用)前要强制类型转换,但不能太随意,否则存和取的数据类型不一致


http://www.ppmy.cn/server/157248.html

相关文章

el-table 多级表头

1.结构 <el-table:data"tableData"border:height"700"style"width: 100% !important; overflow: auto":header-cell-style"{ background: #becee1, color: #333 }":cell-style"{ padding: 5px }"><template v-for…

数据结构:二叉搜索树详解

二叉搜索树详解 一、二叉搜索树的概念二、 二叉搜索树的性能分析&#xff08;一&#xff09;二叉搜索树的效率&#xff08;二&#xff09;数组结构和二叉排序树的比较 三、二叉排序树的插入&#xff08;一&#xff09;操作规则&#xff08;二&#xff09;代码实现 四、二叉排序…

rust如何在类中保存一个闭包,它可以捕获类自己?

首先这个为什么在 Rust 中这么难实现&#xff1f; 我们得承认一个残酷的现实&#xff1a;Rust 不是 C。在 C 中&#xff0c;可以随心所欲地使用引用&#xff0c;编译器不会过多干涉。但在 Rust 中&#xff0c;编译器会像严厉的监管者一样盯着我们的每一个动作&#xff0c;生怕…

软件测试的未来:如何跨越自动化到自主测试的鸿沟

近年来&#xff0c;随着人工智能&#xff08;AI&#xff09;的飞速发展&#xff0c;软件测试领域迎来了技术变革。从传统的手工测试到自动化测试&#xff0c;再到如今炙手可热的自主测试&#xff0c;测试技术正以前所未有的速度演进。然而&#xff0c;从自动化测试到自主测试&a…

通过架构提升后端接口性能

引言 在现代软件开发中,后端接口的性能优化是确保系统高效运行的关键因素之一。 随着用户数量的增加和数据量的增长,未优化的后端接口会导致响应时间变长,用户体验下降,甚至引发系统崩溃。 本文将探讨一些常见且有效的后端接口性能优化方法,并通过具体的Java代码实例来展…

【C】编译与链接

在本文章里面&#xff0c;我们讲会讲解C语言程序是如何从我们写的代码一步步变成计算机可以执行的二进制指令&#xff0c;并最终执行的。C语言程序运行主要包括两大步骤 -- 编译和链接&#xff0c;接下来我们就来一一讲解。 目录 1 翻译环境和运行环境 2 翻译环境 1&#…

2025.01.15docker

韩梅梅是某新兴技术公司的新进实习生&#xff0c;该公司专注于提供基于容器的云原生解决方案。为了提升公司的服务效 率和响应速度&#xff0c;公司决定采用Docker容器技术来管理和部署应用。韩梅梅被分配到了Docker运维团队&#xff0c;她的主要任务是 通过Docker CLI和Dock…

Unity3D Huatuo热更环境安装与示例项目详解

前言 Unity3D作为一款强大的游戏开发引擎&#xff0c;广泛应用于各类游戏和应用程序的开发中。然而&#xff0c;随着游戏版本的迭代和功能的增加&#xff0c;热更新技术变得越来越重要。Huatuo是一款基于Unity3D的IL2CPP解释执行框架&#xff0c;可以实现对游戏代码的热更新&a…