C程序设计——基本变量类型(指针杂谈)

瞎聊

本文后面的内容,可以暂时看不懂,以后如果从事这一行,慢慢会理解,但是这句话要记住:如果 piInt 是一个指向整型的指针变量,那么  *piInt 就是一个整型变量;类似的,如果pcChar是一个指向字符型的指针变量,那么 *pcChar 就是一个字符型的变量;……

其实这部分内容,也许放在 C程序设计——基本变量类型(指针0)的前面更合适,但是思来想去,还是先把指针讲个差不多,再讲这个。

我希望大家记住这句话,将来再慢慢理解:C语言把计算机所有的外设,都抽象为变量。

当你用C语言访问显示器、鼠标、键盘时,最终访问的是一个一个的变量。当然有些变量,被用函数给封装起来,看起来好像是通过调用函数,来控制屏幕显示、获取鼠标状态。

变量

当你入学报名的时候,如果你住校,学校会给你分配一个宿舍,比如你们学校的第14号楼,3层有一个编号360的宿舍刚搞还有一个床位,然后老师大笔一挥,你就住这间了。我们把你住的这个宿舍用一串数字来表示就是: 14360,14代表第14号楼,360代表3层第60号房间。在你们学校,一说14360,就能唯一的标识你们宿舍,你问任何一个同学,都可以告诉你怎么去14号楼,然后上3层找60号宿舍。

计算机的也是一样的,所有外设,包括内存、硬盘、鼠标等等,都分配了很多地址,就好像前面讲了每6个床位分配一个宿舍号,计算机也类似,按照目前的标准,每8位二进制数分配一个地址,通常这8位二进制数,被看做一个整体,叫做一个字节。

C语言下,当你定义一个变量,像下面这样:

    int iInt ;

编译器生成代码的时候,会按照既定的规则(算法)给变量 iInt 分配一片4字节(32bit)连续的内存空间,前面我说了,计算机给每个字节都分配的地址,这一个整形变量占连续4个字节,理论上就有四个地址,按那个算呢?C语言规定,地址中最小的一个,作为整形变量的地址。强调一下,当你定义一个变量是,无论这个变量占多少字节,计算机分配内存时,一定是分配一片地址连续的空间,来存储这个变量。

比如计算机给上述代码中的  iInt 分配了四个字节的空间,地址分别是 4、5、6、7,那么当你给 iInt 取地址(&iInt )时,得到地址将是4。比如下面这段代码:

int main(void)
{int iInt ;int *piInt ; // 定义指向整形的指针变量piInt = &iInt; // 将iInt 的地址,赋值给 piIntiInt = 100;printf("piInt %d\r\n", piInt); // 打印指针变量的值printf("&iInt %d\r\n", &iInt); // 打印 iInt 的地址值printf("iInt %d\r\n", iInt); // 打印 iInt 的值
}

编译后运行结果如下:

我们从打印结果上可以看到变量 iInt 的值是 100,变量 iInt 的地址值是: 6422036。按照前面的讲解,变量 iInt 占4个字节,每个字节都有地址,其中最小的一个是 6422036,另外三个字节的地址就是 6422037、6422038、6422039 。

指针变量,也是变量

我们还看这段代码(不用比较了,就是从上面复制、粘贴过来的)

int main(void)
{int iInt ;int *piInt ; // 定义指向整形的指针变量piInt = &iInt; // 将iInt 的地址,赋值给 piIntiInt = 100;printf("piInt %d\r\n", piInt); // 打印指针变量的值printf("&iInt %d\r\n", &iInt); // 打印 iInt 的地址值printf("iInt %d\r\n", iInt); // 打印 iInt 的值
}

piInt 是一个指针变量,它首先是一个变量,所以计算机也会给它分配地址连续的几个字节(有些计算机是4个字节,有些计算机是8个字节),所以从分配空间的角度,piInt 和 iInt,没有本质区别,如果硬要找区别,那就是分配的空间不一样,可能数量也不一样(当然数量也有可能一样)。既然 piInt 是变量,那就可以给它赋值,比如下面这样:

    piInt = &iInt; // 将iInt 的地址,赋值给 piInt

表示把 iInt的地址,赋值给 piInt。根据运行结果  iInt 的地址其实就是一个数字6422036 ,如果我们能未卜先知,这里直接把 6422036赋值给 piInt,效果是一样的:

    piInt = 6422036; // 如果能未卜先知,就可以用 6422036 来代替&iInt

获取指针指向的值

先明确一个概念,比如我定义一个整形变量 iInt,计算机给它分配的地址是 6422036,然后给 iInt 赋值 100,我们就说地址 6422036 指向的值是100,如果我们改变了 iInt 为 200,则我们说地址 6422036 指向的值是200 。

我们如果定义了一个指针变量  piInt,然后给它赋值 为 iInt 的地址(&iInt),给 iInt 赋值 100,我们就说指针变量 piInt 指向的值是100,如果我们改变了 iInt 为 200,则我们说指针变量 piInt 指向的值是200 。

那么我们如何获取指针 piInt 指向的值呢?像下面这样:

    *piInt ; 

请寻找下面两行的不同:

    int *piInt ; // 定义一个指针变量*piInt ; // 获取 piInt 指向的值

*piInt 左面有类型名,就是定义指针变量。没有类型名,就是获取指向的值。

指针指向的值还可以改变,像下面这样:

    *piInt = 200; // 改变 piInt 指向的值,使之为200

int main(void)
{int iInt ;int iValue ;int *piInt ; // 定义指向整形的指针变量piInt = &iInt; // 将iInt 的地址,赋值给 piIntiValue = *piInt ; // 获取 piInt 指向的值,并赋值给 iValue*piInt = 200; // 改变 piInt 指向的值,使之为200
}

指针变量类型的意义

我们现在知道,定义指针的时候,要声明指针指向什么类型的数据,比如下面这些:

int main(void)
{char *pcChar ; // 指向字符型变量的指针short int *psShort ; // 指向短整形变量的指针int *piInt ; // 指向整形变量的指针long int *plLong ; // 指向长正向变量的指针long long *pllLongLong; // 指向超长整型变量的指针unsigned char *pcChar ; // 指向无符号字符型变量的指针unsigned short int *psShort ; // 指向无符号短整型变量的指针unsigned int *piInt ; // 指向无符号整形变量的指针unsigned long int *plLong ; // 指向无符号长整型变量的指针unsigned long long *pllLongLong; // 指向无符号超长整形变量的指针float *pFloat ; // 指向单精度浮点数的指针double *pDouble ; // 指向双精度浮点数的指针
}

我再本节最开头说了,再强调一次:如果 piInt 是一个指向整型的指针变量,那么  *piInt 就是一个整型变量;类似的,如果pcChar是一个指向字符型的指针变量,那么 *pcChar 就是一个字符型的变量;……

因为不同类型的变量,计算机给分配的空间是不一样的,比如 char型就是1个字节,short int 就是2个字节 ……,指针变量指定的类型, 获取指针指向的值时,才能知道该取几个字节的数据。

指针变量 + 1 

先看下面这行代码:

    piInt = &iInt; // 将iInt 的地址,赋值给 piInt

经过前面的讲解,我们知道 piInt 中存放的地址,是  iInt 的4个字节中,地址最小的那个字节的。piInt 逻辑上,代表的是 4个字节的地址,因此 piInt + 1 ,逻辑上代表 iInt 后面的那个 整型数据,因此   piInt = piInt + 1 ,piInt的值加了4 。

同样的下面代码定义的指针中:

int main(void)
{char *pcChar ; // 指向字符型变量的指针short int *psShort ; // 指向短整形变量的指针int *piInt ; // 指向整形变量的指针long int *plLong ; // 指向长正向变量的指针long long *pllLongLong; // 指向超长整型变量的指针unsigned char *pcChar ; // 指向无符号字符型变量的指针unsigned short int *psShort ; // 指向无符号短整型变量的指针unsigned int *piInt ; // 指向无符号整形变量的指针unsigned long int *plLong ; // 指向无符号长整型变量的指针unsigned long long *pllLongLong; // 指向无符号超长整形变量的指针float *pFloat ; // 指向单精度浮点数的指针double *pDouble ; // 指向双精度浮点数的指针
}

如果 pcChar=  pcChar + 1,pcChar 加了 1;

如果 psShort = psShort + 1,psShort 加了2;

……

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

原生微信小程序笔记完整总结4.0

🤹‍♀️潜意识起点:个人主页 🎙座右铭:得之坦然,失之淡然。 💎擅长领域:大前端 是的,我需要您的: 🧡点赞❤️关注💙收藏💛 是我…

【MySQL】事务管理

【MySQL】事务管理 什么是事务为什么要有事务事务的版本支持事务的提交方式事务的常见操作事务的隔离级别如何理解隔离性隔离级别隔离级别的设置与查看读未提交【Read Uncommitted】读提交【Read Committed】可重复读【Repeatable Read】串行化【serializable】一致性(Consiste…

代码随想录算法训练营43期 | Day 14——226.翻转二叉树、101. 对称二叉树、104.二叉树的最大深度、二叉树最小深度

代码随想录算法训练营 226.翻转二叉树101. 对称二叉树递归法 104.二叉树的最大深度二叉树最小深度 226.翻转二叉树 leetcode链接 思路: 递归三部曲: 确定递归函数的参数和返回值确定终止条件确定单层递归的逻辑 递归法 TreeNode* invertTreeNode(Tree…

并发系统的 CSP+PAT 形式化建模与验证方法(以Kafka系统为例)

消息队列中间件是分布式系统的重要组成部分。它允许应用程序仅关注数据本身,而无需关心数据传输的具体细节。这一特性有效解决了消息异步传输、应用程序解耦以及流量削峰等问题。Kafka是一个开源的分布式消息系统,它基于发布-订阅模型构建。Kafka具有低延…

Unity使用代码生成ScriptableObject数据并赋值之后,重启数据就没有啦!

2024年8月14日早,因数据持续化存储,重启电脑后数据会丢失,而我找不到原因被领导质疑了,故写一片博客记录这个错误。 省流 使用在编辑器的play模式中为ScriptableObject赋值之后,需要使用 #if UNITY_EDITORUnityEdit…

Codeforces Round 495 (Div. 2) F. Sonya and Bitwise OR(线段树)

原题链接:F. Sonya and Bitwise OR 题目大意: 给出一个长度为 n n n 的数组 a a a,并给出 m m m 次询问以及一个数字 x x x。 每个询问形式如下给出: 1 1 1 i i i y y y :将 a i a_{i} ai​ 位置的值更改为 y…

数据库分库分表的介绍

为什么要分库分表 把存于一个库的数据分散到多个库中,把存于一个表的数据分散到多个表中。如果说读写分离是为了分散数据库读写操作压力,分库分表就是为了分散存储压力,一般情况下,单表数据量到达千万级别,就可以考虑…

基于飞腾平台的Hbase的安装配置

【写在前面】 飞腾开发者平台是基于飞腾自身强大的技术基础和开放能力,聚合行业内优秀资源而打造的。该平台覆盖了操作系统、算法、数据库、安全、平台工具、虚拟化、存储、网络、固件等多个前沿技术领域,包含了应用使能套件、软件仓库、软件支持、软件适…

支持S/MIME证书的邮件客户端有哪些?

S/MIME证书,也叫做邮件安全证书,支持安全/多用途互联网邮件扩展协议(S/MIME协议),是通过加密和数字签名来确保电子邮件的安全性、保密性和完整性的数字证书。GDPR、HIPAA、FDA等多个行业都要求邮件发送方在发送邮件时对…

基于R语言遥感随机森林建模与空间预测;遥感数据处理与特征提取;数据分析与可视化

目录 第一章 理论基础与数据准备【夯实基础】 第二章 随机森林建模与预测【讲解实践】 第三章 实践案例与项目 更多应用 随机森林作为一种集成学习方法,在处理复杂数据分析任务中特别是遥感数据分析中表现出色。通过构建大量的决策树并引入随机性,随…

C++ 特殊类设计以及单例模式

目录 1 不能被拷贝 2 只能在堆上创建对象 3 只能在栈上创建对象 4 禁止在堆上创建对象 5 不能被继承的类 6 单例类 特殊类就是一些有特殊需求的类。 1 不能被拷贝 要设计一个防拷贝的类,C98之前我们只需要将拷贝构造以及拷贝赋值设为私有,同时只声明…

RTX 4070 GDDR6显存曝光:性能与成本的平衡之选

近期,关于NVIDIA RTX 4070新显卡的信息曝光,这款显卡将配备较为缓慢的GDDR6显存,而非更高性能的GDDR6X。这一配置的选择引发了业内的广泛关注,特别是在性能与成本的平衡问题上。 新版RTX 4070 OC 2X的核心特点 **1.显存类型与带…

8B 端侧小模型 | 能力全面对标GPT-4V!单图、多图、视频理解端侧三冠王,这个国产AI开源项目火爆全网

这两天, Github上一个 国产开源AI 项目杀疯了!一开源就登上了 Github Trending 榜前列,一天就获得将近600 star。 这个项目就是国内大模型四小龙之一面壁智能最新大打造的面壁「小钢炮」 MiniCPM-V 2.6 。它再次刷新端侧多模态天花板&#xf…

微分方程求解的三种解析方法:经典时域法(齐次解+特解,零状态+零输入),冲激响应卷积法、传递函数法

经典时域分析方法 以例题的形式对经典时域解法(齐次解特解)进行说明,最后进行总结。考虑如下形式微分方程: y ′ ′ ( t ) 5 y ′ ( t ) 6 y ( t ) 2 f ′ ( t ) 6 f ( t ) y\left( t \right) 5y\left( t \right) 6y\left(…

pyinstaller使用

pyinstaller 入门 Pyat5 的安装程序开发PyQt6 的安装程序开发 编写好的程序编译成可执行文件资源文件:用 zip 打包,基本可以压缩到 1/3 大小;然后再用 pyqt 写一个 setup 安装程序,安装到指定目录(安装的过程实际就是把文件解压、拷贝到指定目录、注册到…

[000-01-030].第2节 :Zookeeper本地安装

1.Zookeeper下载地址 1.Zookeeper官网地址 2.会显示Zookeeper的一些版本 2.Zookeeper本地模式安装: 2.1.Zookeeper安装前准备 1.在Centos7虚拟机中安装jdk8 2.2.Zookeeper安装过程: 1.下载zookeeper压缩版本,解压放在opt/moduel目录下…

虚拟人实时主持创意互动方案:赋能峰会论坛会议等活动科技互动感

随着增强现实、虚拟现实等技术的不断发展,“虚拟人实时主持”创意互动模式逐渐代替传统单一真人主持模式,虚拟主持人可以随时随地出现在不同活动现场,也可以同一时间在不同分会场中担任主持工作,在峰会、论坛、会议、晚会、发布会…

计算机网络三级笔记--原创 风远 恒风远博

典型设备中间设备数据单元网络协议物理层中继器、集线器中继器、集线器数据位(bit) binary digit二进 制数据的缩写HUB使用了光纤、 同轴电缆、双绞 线.数据链路层网卡、网桥、交换机网桥、交换机数据帧(Frame)STP、ARQ、 SW、CSMA/CD、 PPP(点对点)、 HDLC、ATM网络层路由器、…

MySQL 管理

启动及关闭 MySQL 服务器 Windows 系统下 启动 MySQL 服务器: 1、通过 “服务” 管理工具: 打开“运行”对话框(Win R),输入 services.msc,找到“MySQL”服务,右击选择“启动”。 2、通过命…

汇量科技Mintegral发布全新产品矩阵:助力广告主高效增长与变现

近期,汇量科技旗下程序化互动式广告平台Mintegral正式推出全新产品命名,期望通过简洁明确的产品名称,更好地传达Mintegral的品牌理念,使客户与平台的每一次接触都更加直接高效。 Mintegral AppGrowth(原Mintegral Self-Service Pl…