c语言:初识指针

目录

目录

目录

CPU与内存协同工作

访问内存中的“房间”

基础数据类型怎样居住“房间”

取地址运算符 &

声明指针类型的变量

定义

指针类型

空间大小

小结 

 使用指针

取值运算符 *

指针类型的大小

强制转换指针类型


CPU与内存协同工作

以整型加法为例,我们来看看在计算机内部,CPU(中央处理器)是如何配合其他硬件进行计算的。

CPU由三部分构成:

  1. 算术、逻辑单元:对数据执行运算(例如加法、减法)的电路。
  2. 控制单元:协调机器活动的电路。
  3. 寄存器组 :数据临时存储。

然而,寄存器能够存储的信息量很少,仅仅是当前工作所必要的。话说鱼的记忆只有7秒,CPU的记忆恐怕是更短。总不能,CPU做一步操作,就把上一步操作的结果给忘了吧。

因此,我们需要内存来配合CPU进行数据操作

数据几乎都存储在内存上,仅有当前正在处理的数据,才放到CPU的寄存器组上,等待CPU进行计算。

CPU将数据计算完毕后,再存储到内存中。数据通过数据总线,在CPU和内存上进行传输。

接下来,我们来看看,将两个数据相加会经历哪些步骤。

  1. 从内存中取出一个加数放到一个寄存器中。
  2. 从内存取出另一个加数,放到另一个寄存器中。
  3. 激活算术、逻辑单元中的加法电路,将前面两步的寄存器作为输入,用另一个寄存器存放结果。
  4. 将结果存放到内存中。


访问内存中的“房间”

只有正在被处理的数据才会被放到CPU的寄存器上,等待CPU进行计算,CPU将数据计算完毕后,再存储到内存中。所以,内存才是数据的大本营。

我们知道,计算机通过晶体管的开关状态来记录数据。它们通常8个编为一组,我们称之为字节。既然内存需要存储数据,内存上必然有非常多的这种8个开关组成的编组。

我们可以把这种编组看作居住数据的房间,而为了方便地找到这些房间,每个房间均有一个编号。第一个房间编号从0开始,此后依次加1

我们把房间号,称之为内存地址。

就像生活中我们所说的:“AA大街,BB公寓,123房间一样。只不过在内存中没有大街和公寓,仅需要编号即可表示地址了。


基础数据类型怎样居住“房间”

 

int为例,我们有以下两种表达方式:

1. 列举所有的房号:301302303304

2. 首房间及房间数:301开始的4个房间。

对于int还好,仅需要4房间。如果数据需要的房间很多,第一种方式需要保存更多的房间号。很显然第二种方式更为灵活。

计算机使用第二种方式记录一个数据对象在内存中的存储位置。

我们把第一个房间房间号,称为这个数据对象的首地址。那么数据对象需要的房间数量,就是它所占用的存储空间大小。

因此,记录一个数据对象在内存中的存储位置,需要两个信息:

  1. 数据对象的首地址。
  2. 数据对象占用存储空间大小。 


取地址运算符 &

现在我们认识一个新的运算符——取地址运算符&

取地址运算符是一个一元运算符,写在一个数据对象的左边,可以获取一个数据对象的首地址和所需存储空间大小

int n;
类型 pn = &n; // 获取数据对象n的首地址和所需空间大小

变量 pn ,存储了变量 n 的首地址和所需空间大小,那么通过变量 pn 可以在内存中找到变量 n 。所以,变量 pn 到底是什么类型呢?


声明指针类型的变量

int n;
int* pn = &n;

char c;
char* pc = &c;

 

int* pn 声明一个保存了 int 类型的首地址大小的变量。

char* pc 声明一个保存了 char 类型的首地址大小的变量。

变量 pn 存储了变量 n 的首地址与大小,变量 pc 存储了变量 c 的首地址与大小。通过 pn pc 可以在内存中找到变量 n c


定义

设一个数据对象为 x ,设另一个数据对象为 p p 存储了 x 的首地址和所占空间大小。那么, p 称之为 x 的指针,或者说 p 指向 x

对于上面的代码:

pn 被称作 n 的指针,或者说 pn 指向 n

pc 被称作 c 的指针,或者说 pc 指向 c

int* pn; // 将空格放在变量旁

int *pn; // 将空格放在类型旁

int*pn; // 不用空格

另外,声明指针变量时,将空格放在变量旁或者将空格放在类型旁,甚至不用空格。这3种写法都是可以的。


指针类型

现在让我们来探究一下,指针类型怎样保存下面两种信息。

  1. 数据对象的首地址。
  2. 数据对象占用存储空间大小。
#include <stdio.h>

int main()

{

int n1;

int n2;

int n3;

int n4;

int *pn1 = &n1;

int *pn2 = &n2;

int *pn3 = &n3;

int *pn4 = &n4;

printf("pn1 = %u\n", pn1);

printf("pn2 = %u\n", pn2);

printf("pn3 = %u\n", pn3);

printf("pn4 = %u\n", pn4);

return 0;

}

我们用 %u 尝试打印指针变量 pn1 pn4 ,看出它们确实为一些数值。

并且,数值之间均相差4。我们有理由怀疑,n1n4它们相邻排布,而这些数值就是n1n4的首地址。事实上,指针类型的值就是目标数据对象的首地址 


空间大小

既然指针类型的值已经被用于存储首地址了,那么目标对象的空间大小存储到哪呢?

#include <stdio.h>
int main()

{
    int a;
    int* pa = &a;

    char b;
    char* pb = &b;

    pa = pb;
    return 0;

}

无法从char转换为int

我们尝试让 pn 赋值为 pc 试试看。

编译出现了错误,无法将 char* 转换为 int*

仅仅看变量的值, pn pc 都是一个整型数据。那么它们理应是可以相互赋值的才对。但是,现在的编译结果告诉我们无法将 char* 转换为 int*

另外,既然变量值已经用于存储首地址了,那么空间大小怎么存储呢?

对于 char* int* 它们的区别就只剩下类型不同且无法直接相互转换了。

我们推测:

指向int的指针类型标识了目标对象的空间大小为 sizeof(int)

指向char的指针类型标识了目标对象的空间大小为 sizeof(char)

没错,C语言中通过不同的指针类型来标记目标数据对象的空间大小

int* pn = &n; 
char* pc = &c;

表达式 &n 的结果为一个类型为 int* 数据对象。它的值为变量 n 的首地址,类型 int* 标记变量 n 占用 sizeof(int) 字节。

表达式 &c 的结果为一个类型为 char* 数据对象。它的值为变量 c 的首地址,类型 char* 标记变量 c 占用 sizeof(char) 字节。

 如果尝试将 pc 赋值给 pn ,虽然首地址可以正确地从 pc 赋值给 pn 。但是指针类型的变化导致数据长度的变化,因此无法进行自动转换。


小结 

指针类型通过值来保存目标数据对象的首地址,类型本身标记目标数据对象的空间大小。 


 使用指针

 既然指针存储了一个数据对象的首地址与大小,并且通过这两个信息可以在内存中找到该数据对象。那么,我们肯定可以使用指针来访问所指向的数据对象。


取值运算符 *

现在我们再认识一个新的运算符——取值运算符*

取值运算符是一个一元运算符,写在一个指针的左边,可以根据指针中存储的首地址和空间大小找到目标数据对象

虽然它和乘法运算符很像,但是,它是一个一元运算符,仅需要一个操作对象。

int n = 123;

int* pn = &n;

printf("%u\n", pn);      // 打印n的首地址

printf("%d\n", *pn);    // 根据`pn`中的首地址与大小,找到的数据对象的值

pn 变量内存储的值,即 n 的首地址。

*pn 表达式结果为,根据 pn 中的首地址与大小,找到的数据对象的值。即 n 的值。

除了通过指针访问所指向的数据对象,也可以通过指针修改所指向的数据对象。



指针类型的大小

charint存储的是数据范围不同的两种数据。char存储小一点的整数范围、int存储大一点的数据范围。所以,char可以占用小一点的空间,而int会占用大一些的空间。

但是, char* int* 存储的均为数据对象的地址,因此它们所占用的空间是相同的。

不同的编译器或编译配置可以让编译器生成32位或64位的程序,有时候被称作x86x64

  1. 32位程序可以访问从0232次方的地址范围。
  2. 64位程序可以访问从0264次方的地址范围。

 

visual studio中,你可以使用上图红框中的下拉列表,切换编译生成的程序是32位或64位。

指针类型必须拥有可以表达所有内存地址的能力。因此在32位程序中,指针类型占用4字节大小。64位程序中,指针类型占用8字节大小。

如果指针类型的大小为4字节,使用 %u 作为printf的占位符是合适的。但是指针类型的大小为8字节时, 使用 %u 有可能不能完全打印地址,你可以使用长度指示符,将长度加长到8字节,例如 %llu 。

 占位符 %p 是指针类型专用的占位符,32位或64位程序使用它均能保证打印的结果正确。不过,它通常是以十六进制显示的。


强制转换指针类型

变量 pn 为指向int类型的指针。变量 pc 为指向char类型的指针。

虽然变量 pn pc 不能在赋值时自动转换。但是,使用强制转换可以将 pn 转换为 char* 后赋值给 pc

赋值后, pn pc 均存储了 n 的首地址,均打印出了同样的首地址。但是,C语言使用不同的指针类型标识目标对象的空间大小。

pn int* 类型, *pn 表达式会从首地址开始处取 sizoef(int) 字节,将其转换成int类型作为表达式结果。因此,结果为1431655765

pc char* 类型, *pc 表达式会从首地址开始处取 sizoef(char) 字节,将其转换成char类型作为表达式结果。因此,结果为85

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

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

相关文章

Vue3页面如何设置rem单位的依据“根font-size”的两种方式

最近在对项目做整体的自适应。我们可以通过设置meta的viewport属性设置屏幕的缩放&#xff0c;但有时候&#xff0c;屏幕缩放了但字体大小也需要做相应的调整才能达到更好的自适应效果。我们很容易想到使用媒体查询rem来实现字体的自适应。 rem单位&#xff1a;“rem” 是 “ro…

Linux学习教程(第十一章 Linux高级文件系统管理)二

第十一章 Linux高级文件系统管理&#xff08;二&#xff09; 九、Linux如何判断磁盘配额是否生效&#xff1f; 我们的磁盘配额已经生效&#xff0c;接下来测试一下是否会限制我们的用户。以 lamp1 用户为例&#xff0c; 因为 lamp1 用户除容量被限制外&#xff0c;也限制了文…

MyBatis 四大核心组件之 StatementHandler 源码解析

&#x1f680; 作者主页&#xff1a; 有来技术 &#x1f525; 开源项目&#xff1a; youlai-mall &#x1f343; vue3-element-admin &#x1f343; youlai-boot &#x1f33a; 仓库主页&#xff1a; Gitee &#x1f4ab; Github &#x1f4ab; GitCode &#x1f496; 欢迎点赞…

利用n_gram进行情感分析

一、思路 二、关键步骤实现 1、利用tf-idf进行特征提取 详见利用tf-idf对特征进行提取-CSDN博客 2、利用svm进行模型训练 详见​​​​​​​​​​​​​​利用svm进行情感分析-CSDN博客

大数据分析与应用实验任务十二

大数据分析与应用实验任务十二 实验目的&#xff1a; 通过实验掌握spark机器学习库本地向量、本地矩阵的创建方法&#xff1b; 熟悉spark机器学习库特征提取、转换、选择方法&#xff1b; 实验任务&#xff1a; 一、逐行理解并参考编写运行教材8.3.1、8.3.3节各个例程代码…

服务器数据恢复-raid5多块磁盘掉线导致上层卷无法挂载的数据恢复案例

服务器数据恢复环境&#xff1a; 一台服务器中有一组由24块FC硬盘组建的raid5磁盘阵列&#xff0c;linux操作系统ext3文件系统&#xff0c;服务器上层部署有oracle数据库。 服务器故障&检测&#xff1a; raid5阵列中有两块硬盘出现故障掉线&#xff0c;导致服务器上层卷无法…

中通快递查询,中通快递单号查询,并进行多次揽收分析

批量查询中通快递单号的物流信息&#xff0c;并将其中的多次揽收件分析筛选出来。 所需工具&#xff1a; 一个【快递批量查询高手】软件 中通快递单号若干 操作步骤&#xff1a; 步骤1&#xff1a;运行【快递批量查询高手】软件&#xff0c;第一次使用的伙伴记得先注册&…

RocketMQ容器化最佳实践

前言 在上一篇文章基于RocketMQ实现分布式事务我们完成基于消息队列实现分布式事务&#xff0c;为了方便后续的开发和环境统一&#xff0c;我们决定将RocketMQ容器化部署到服务器上。所以这篇文章就来演示一下笔者基于docker-compose完成RocketMQ容器化的过程。 本篇文章为了…

移远通信5G智能模组SG520B系列正式上线,为智能终端轻松提供强大多媒体功能

12月13日&#xff0c;全球领先的物联网整体解决方案供应商移远通信宣布&#xff0c;正式推出新一代 5G Sub-6GHz智能模组SG520B系列。 SG520B系列支持5G、Wi-Fi 6E和蓝牙等多种连接技术&#xff0c;且多媒体功能强大&#xff0c;推入市场后将可直接满足智能网关、智慧工业、智慧…

使用CFimagehost源码自建无需数据库支持的PHP图片托管服务

文章目录 1.前言2. CFImagehost网站搭建2.1 CFImagehost下载和安装2.2 CFImagehost网页测试2.3 cpolar的安装和注册 3.本地网页发布3.1 Cpolar临时数据隧道3.2 Cpolar稳定隧道&#xff08;云端设置&#xff09;3.3.Cpolar稳定隧道&#xff08;本地设置&#xff09; 4.公网访问测…

大数据笔记(待续)

mysql 缓存技术 数据库和缓存双写数据一致性问题常见的解决方案 常见方案通常情况下&#xff0c;我们使用缓存的主要目的是为了提升查询的性能。大多数情况下&#xff0c;我们是这样使用缓存的&#xff1a; 用户请求过来之后&#xff0c;先查缓存有没有数据&#xff0c;如果有…

做数据分析为何要学统计学(2)——如何估计总体概率分布

我们可以通过手头掌握的样本来估计总体的概率分布。这个过程由以下步骤组成。 第一步&#xff0c;我们采用Seaborn软件的histplot函数建立核密度图&#xff08;一种概率密度图&#xff09;。 import numpy as np #输入样本数据 xnp.array([2.12906357, 0.72736725, 1.0515282…

如何删除/替换3D模型的材质贴图

在线工具推荐&#xff1a; 3D数字孪生场景编辑器 - GLTF/GLB材质纹理编辑器 - 3D模型在线转换 - Three.js AI自动纹理开发包 - YOLO 虚幻合成数据生成器 - 三维模型预览图生成器 - 3D模型语义搜索引擎 在3D设计和动画领域&#xff0c;材质是呈现真实感和逼真效果的关键因…

电脑监控软件丨你能接受在电脑上安装吗

很多人说自己是不能接受老板在电脑上安装电脑监控软件的&#xff0c;怎么说呢&#xff0c;我自己本身是没有任何意见的。 我是可以接受的。 先来说说我的理由&#xff1a; 我是站在企业管理者的角度上&#xff0c;来思考这个问题的。老板花钱雇佣员工不是来公司来上网聊天打游…

【笔试强化】Day 1

文章目录 一、单选1.2.3.4.5.6. &#xff08;写错&#xff09;7. &#xff08;不会&#xff09;8. &#xff08;常错题&#xff09;9.10. &#xff08;写错&#xff09; 二、编程1. 组队竞赛题目&#xff1a;题解&#xff1a;代码&#xff1a; 2. 删除公共字符题目&#xff1a;…

自定义Axure元件库及原型图泳道图的绘制(详细不同类的案例)

目录 前言 一.自定义元件库 1.1 自定义元件库的作用 1.2 自定义元件的操作 二.流程图 2.1 流程图的作用 2.2 绘制流程图 2.3 简易流程图案例 三.泳道图 3.1 泳道图的作用 3.2 流程图和泳道图的区别 3.3 绘制泳道图 四.绘制前的准备 五.案例 4.1 门诊模块案例 4.2 …

mysql踩坑

关于安装 1报错&#xff1a;ER_NOT_SUPPORTED_AUTH_MODE: Client does not support authentication protocol requested by server; consider upgrading MySQL client具体代码如下&#xff1a; import mysql from "mysql"//连接数据库 const dbmysql.createPool({h…

前端体系:前端应用

目录 前端体系基础 html&#xff08;超文本标记语言&#xff09; css&#xff08;层叠样式单&#xff09; javascript&#xff08;&#xff09; 一、前端体系概述 二、前端框架 React Vue Angular 三、前端库和工具 lodash Redux Webpack 四、模块化和组件化 ES…

ZLMediaKit中的线程

EventLoop的线程模型 服务器通用的IO模型event-loop 非阻塞IO。线程模型可以是单线程&#xff0c;可以是多线程。对于已经普及了的多核环境&#xff0c;通常都是采用多线程。 通常一个线程中有一个EventLoop&#xff0c;比如accept是一个专门线程&#xff0c;accept后的fd分…

AJAX原理解析与案例实践,助你成为前端技术高手

大家有关于JavaScript知识点不知道可以去 &#x1f389;博客主页&#xff1a;阿猫的故乡 &#x1f389;系列专栏&#xff1a;JavaScript专题栏 &#x1f389;ajax专栏&#xff1a;ajax知识点 &#x1f389;欢迎关注&#xff1a;&#x1f44d;点赞&#x1f64c;收藏✍️留言 学习…