空指针和Void指针的基本概念和用法

前言:本文只是限于说明空指针与void指针的基本性质和用法,关于更深层次的用法,则不介绍,因为本人自己还没有搞懂!!!

1:空指针

1.1空指针的基本定义

定义:在C语言中,如果一个指针不指向任何数据,我们就称之为空指针,用NULL表示,NULL在头文件中定义了。

空指针的定义

#include<stdio.h>
int *p1 = NULL;
char *P2 = NULL;
float *p3= NULL;
long *p4 = NULL;

注意:头文件是必不可少的,stdio.h中包含了NULL的定义。空指针定义时,是可以声明为不同的类型的(如整形,字符型 等。。。。)。虽然说在一个源文件中,同时定义多个不同类型空指针没有实际的作用。

#define NULL ((void *)0)

NULL(注意:全是大写) :为宏名;

((void*)0)  是宏参数,先看(void *)先强制定义一个void 类型的指针,0是常量,即把0变换为一个void类型的指针。看起来是不是很神奇

在不同的系统中,NULL并非总是和0等同,NULL仅仅代表空值,也就是指向一个不被使用的地址,在大多数系统中,都将0作为不被使用的地址,所以就有了这样的定义。
(void *)0表示把数值 0 强制转换为void *类型(从这里看出,任何常量都能被强制转换为指针变量),最外层的( )把宏定义的内容括起来,我们自己进行宏定义时也应该这么做。

但是,C规范中并没有将NULL与空指针强制一对一绑定。

结论:普通指针也能够被赋值为NULL

 int *p1=NULL;

    printf("打印p1中的地址%p\n",p1);

2 void指针

2.1 void指针的基本概念

void指针又称为空指针和泛型指针,他可以指向任意类型的数据

#include<stdio.h>
int main()
{
int Var1=10;
char Var2='a';
float Var3=3.1415927;
double Var4 = 1000.0001;
/*声明一个泛型指针Void,确认是否所有的数据都能被正确的写入地址*/
void *p;
p=&Var1;
printf("1:打印Var1的地址%p\n",&Var1);
printf("1:打印指针p的值%p\n",p);
p=&Var2;
printf("2:打印Var2的地址%p\n",&Var2);
printf("2:打印指针p的值%p\n",p);
p=&Var3;
printf("3:打印Var3的地址%p\n",&Var3);
printf("3:打印指针p的值%p\n",p);
p=&Var4;
printf("4:打印Var4的地址%p\n",&Var4);
printf("4:打印指针p的值%p\n",p);
}

看输出结果:

1:打印Var1的地址000000000061FE04
1:打印指针p的值000000000061FE04
2:打印Var2的地址000000000061FE03
2:打印指针p的值000000000061FE03
3:打印Var3的地址000000000061FDFC
3:打印指针p的值000000000061FDFC
4:打印Var4的地址000000000061FDF0
4:打印指针p的值000000000061FDF0

先定义的变量地址值越大。

延伸知识点,堆栈的基本概念和应用拓展:

堆栈的本质是一段内存。

先来了解栈

概念:栈是一种特殊的线性表,其只允许在固定的一端插入和删除操作。进行数据插入和删除操作的一端为栈顶另一端为栈底(栈低是固定的,不允许变化的)。栈中的数据元素遵守后进先出(Last In First Out)和后进先出的原则。

1、内存没有方向的概念,只有高低的区别。
2、如果压栈的顺序是从低地址往高低地址依次压栈,则是向上生长。
高地址往低地址依次压栈,则是向下生长。
这里其实有个潜台词,要先确定栈底位置,比如linux,一块栈内存,栈底位于低地址,所以压栈是从低地址往上增长。windows,栈底则位于高地址。
3、关于函数参数,从右往左压栈没有问题,比如我们例子中的c–>b–>a从栈低依次压栈。
4、关于局部变量,其实也有规律,linux平台是先定义,后入栈。Windows,则是先定义,先入栈

可以看到void类型指针,可以指向任意数据,同样根据上面代码分析还能得出下面结论,就是各种不同类型的指针,也是可以直接赋值给void类型指针的。不需要进行类型转换,但是注意反过来却是不行的,即空指针不能直接赋值给其他类型指针。

/*以下是非法操作*/
int *p1;
void *p2=&Var1;
p1=p2;  //错误不能进行赋值
p1=(int*)p2  //正确,可以进行赋值

补充说明: 从上面代码输出的结果,看栈结构的存储机制

2.2 另外一种类型的void指针

另外一种重要的空指针类型,(准确说是空指针,最常见应用)malloc()也就是在堆上分配指定内存。大家还记得学习malloc时的方法了吧!

教材中说,malloc在堆上开辟了一段指定Byte的内存,如果开辟成功则返回一个类型为void类型,地址为开辟内存首地址的指针变量。如果内存开辟不成功则返回一个空指针。此时我们学习的知识形成完美的闭环。

void *p3=malloc(5);
//代码解释:先在堆上开辟了5个Byte的内存,然后将首字节的地址作为voi类型的指针返回给我们定义的void类型指针
int *p4=(int*)malloc(sizeof(int))
//这是我们以前学习malloc使用的格式,前面需要加上一个强制类型转换

/*接下来,是对内存分配是否成功的判断,储备知识,分配不成功则返回NULL*/
if(p3==NULL)
printf("p3的内存方配不成功")
else
printf("p3的内存方配成功,且p3所存储的地址是:%p",p3);

 2.3void类型指针不能直接操作指向的数据

根据上面的学习,我们知道了,无论哪种类型的指针变量,其位数都是固定的。且上面的代码中,我们将各种不同类型的数据,赋值给了void类型的数据,且都打印出了正确的地址。有同学会问,那为什么不直接废除指针类型的定义,所有指针都使用void修饰。

int c[2]={100,101};
    void *p3=c;
    p3+=1;
    printf("打印p3中的值%d\n",*p3);
    return 0;

以上代码,我们是要执行打印数组的第二个值 101,。先编译,我们发现编译阶段直接报错

且代码14行,其实就出现问题,void类型指针,+1,编译器是无法确定地址是增长几位的。修改上述代码

int c[2]={100,101};
    void *p3=c;
    printf("1:打印p3中的地址%p\n",p3);
    p3+=1;
    printf("2:打印p3中的地址%p\n",p3);

运行结果:

可以看到地址只是默认增加了一位。

总结:

我们对该地址中到底是个什么类型的对象并不了解,因此不能直接操作 void* 指针所指的对象,也就无法确定能在这个对象上做哪些操作。
概括来说,以 void* 的视角来看内存空间也就是仅仅是内存空间,没办法访问内存空间中所存的对象,因此只有对其进行恰当的类型转换之后才可以对其进行相应的访问。
也就是说一个 void 指针必须要经过强制类型转换以后才有意义。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/410885.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

APP自动化第一步:Appium环境搭建

一、安装Appium Python client包 1.直接cmd窗口输入pip install Appium-Python-Client 2.要确保安装匹配版本的selenium和appium 使用命令pip install selenium -U 首先进入网盘下载这三个软件的压缩包 二、安装Appium Server 1.双击打开压缩包Appium 2.双击进行安装。 3.点…

unity导航网格无法烘培到台阶和斜坡

如图是我在b站学Unity导航网格时建的一个示例场景&#xff0c;本场景使用的为棱长1m的立方体&#xff0c;读者可以以此为参照度量其他物体大小。 可见导航网格根本无法烘焙到斜坡和台阶上&#xff0c;为解决问题我做了不少尝试&#xff0c;调整最大坡度和步高都没办法解决问题…

Kafka 面试八股题整理

前言&#xff1a;本文是博主自行收集的Kafka相关的八股文问题&#xff0c;博主还在准备暑期实习中&#xff0c;应该会持续更新.... 参考&#xff1a; 32 道常见的 Kafka 面试题你都会吗&#xff1f;附答案 【Kafka】10道不得不会的 Kafka 面试题 掌握这10个常见的Kafka经典面试…

openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法

文章目录 openssl3.2 - crypto-mdebug被弃用后, 内存泄漏检查的替代方法概述笔记查看特性列表openssl3.2编译脚本 - 加入enable-crypto-mdebug看看有没有替代内存诊断的方法?main.cppmy_openSSL_lib.hmy_openSSL_lib.c备注备注这招不行啊显势调用默认上下文也不行END openssl3…

【设计模式】工厂模式、建造者模式、原型设计模式

文章目录 1、简单工厂模式2、工厂方法模式3、抽象工厂模式4、建造者模式5、原型设计模式 设计模式即总结出来的一些最佳实现。23种设计模式可分为三大类&#xff1a; 创建型模式&#xff1a;隐藏了创建对象的过程&#xff0c;通过逻辑方法进行创建对象&#xff0c;而不是直接n…

【python开发】面向对象高级和应用

这里写目录标题 一、继承&#xff08;一&#xff09;mro和c3算法&#xff08;二&#xff09;py2和py3区别&#xff08;了解即可&#xff09; 二、内置函数补充&#xff08;一&#xff09;callable&#xff1a;是否可以在后面加括号执行&#xff08;二&#xff09;super()&#…

雷达一维成像:基于数据集的实践

雷达一维成像&#xff1a;基于数据集的实践 (距离压缩\距离-时间图\距离-多普勒图\微多普勒图) 说明 雷达成像技术是雷达发展的一个重要里程碑&#xff1a;从此雷达的功能不仅仅是将所观测的对象视为点目标&#xff0c;并只测量它的位置与运动参数。雷达成像技术使得我们可以获…

EMQX Enterprise 5.5 发布:新增 Elasticsearch 数据集成

EMQX Enterprise 5.5.0 版本已正式发布&#xff01; 在这个版本中&#xff0c;我们引入了一系列新的功能和改进&#xff0c;包括对 Elasticsearch 的集成、Apache IoTDB 和 OpenTSDB 数据集成优化、授权缓存支持排除主题等功能。此外&#xff0c;新版本还进行了多项改进以及 B…

Linux第63步_为新创建的虚拟机添加必要的目录和安装支持linux系统移植的软件

1、创建必要的目录 输入密码“123456”&#xff0c;登录虚拟机 这个“zgq”&#xff0c;是用户名&#xff0c;也是下面用到的的“zgq”目录。 1)、创建“/home/zgq/linux/”目录 打开终端&#xff0c;进入“/home/zgq/”目录 输入“mkdir linux回车”&#xff0c;创建“/ho…

电子版证件照怎么弄?分享完整制作方法!

在数字化时代&#xff0c;电子版证件照已成为我们生活中不可或缺的一部分。无论是求职、办理证件还是网络注册&#xff0c;都需要用到电子版证件照。那么&#xff0c;如何制作一份合格的电子版证件照呢&#xff1f;本文将为您详细介绍电子版证件照的制作方法&#xff0c;并推荐…

开年大吉!安全狗入选工信部工业互联网试点示范名单

近日&#xff0c;工业和信息化部信息通信管理局公布了2023年工业互联网试点示范名单。此次名单根据《工业和信息化部办公厅关于组织开展2023年工业互联网试点示范项目申报工作的通知》&#xff08;工信厅信管函﹝2023﹞319号&#xff09;&#xff0c;经企业申报、地方推荐、专家…

通过OCR实现纯数字识别

基于飞浆paddle训练框架 照这个改的 https://www.paddlepaddle.org.cn/documentation/docs/zh/practices/cv/image_ocr.html 训练不到10分钟 10epoch cpu&#xff1a;inter i5 8250 U 脚本生成的图10000 验证训练&#xff1a;3:7 预测结果 chatgpt写的代码&#xff0c;生成数…

从ChatGPT到Sora,来了解大模型训练中的存储

1 从chatGPT到Sora 2022年底&#xff0c;OpenAI推出人工智能聊天机器人ChatGPT&#xff0c;开启了大模型领域的“竞速跑”模式。2024年2月15日&#xff0c;随着视频生成模型Sora的横空出世&#xff0c;OpenAI再度掀起热潮。 Sora将视频生成内容拉到了一个全新的高度&#xff0c…

Pybind11 在C++中运行python脚本操作内存数据

pybind11资料 官方Github:Pybind11 Github Pybind11文档&#xff1a;Pybind11 文档 文档在深入使用后需要细细读懂&#xff0c;包括全局只能有一个解释器&#xff0c;如何从C中返回指针/引用等。基本文档中需要注意的点都会遇到 Python环境安装及维护 对于正常使用人员&…

python自动化测试三部曲之request+django实现接口测试

这里废话少说&#xff0c;进入正题 我的思路是这样的 1、先用django实现登陆、增加、删除、查看4个接口 2、在excel定义好测试案例、然后读取excel中的案例&#xff0c;然后把案例用unittest框架组装和封装 3、启动django&#xff0c;执行测试案例 一、先跑通unittest到dj…

Scikit-Learn逻辑回归

Scikit-Learn逻辑回归 1、逻辑回归概述1.1、逻辑回归1.2、逻辑回归的优缺点1.3、逻辑回归与线性回归 2、逻辑回归的原理2.1、逻辑回归的概念与原理2.2、逻辑回归的损失函数 3、 1、逻辑回归概述 1.1、逻辑回归 逻辑回归&#xff08;Logistic Regression&#xff09;主要解决二…

【IDEA】java 项目启动偶现Kotlin 版本问题 error:Kotlin:module was

一、问题描述&#xff1a; error:Kotlin:module was compiled with an incompatible version of kotlin the binary version of its metadata is二、问题原因&#xff1a; jar包版本冲突 三、解决方式&#xff1a; 1、Rebuild Project&#xff08;推荐☆&#xff09; 重新构…

【web】云导航项目部署及环境搭建(复杂)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、项目介绍1.1项目环境架构LNMP1.2项目代码说明 二、项目环境搭建2.1 Nginx安装2.2 php安装2.3 nginx配置和php配置2.3.1 修改nginx文件2.3.2 修改vim /etc/p…

内存溢出排查

1、进入k8s容器对应服务节点查看进程号 ps aux|grep javaps aux 是用BSD的格式来显示 java这个进程 显示的项目有&#xff1a;USER , PID , %CPU , %MEM , VSZ , RSS , TTY , STAT , START , TIME , COMMAND USER: 行程拥有者 PID: pid %CPU: 占用的 CPU 使用率 %MEM: 占用的记…

python Airtest自动化测试工具的的使用

Airtest全称AirtestProject&#xff0c;是由网易游戏推出的一款自动化测试框架&#xff0c;在软件测试的时候使用到了该框架。这里记录一下安装、使用和遇到的坑的问题… Airtest的官网介绍项目构成 Airtest&#xff1a;是一个跨平台的、基于图像识别的UI自动化测试框架&#x…