C语言指针2大问题:指针类型有什么用?指针如何运算?

news/2024/4/24 23:52:19/文章来源:https://blog.csdn.net/xiang_bolin/article/details/130372131

如题,本篇博客主要解决2个疑点:指针类型的用处,指针如何运算。

在这里插入图片描述

1.指针类型

C语言中的指针类型,在X86环境下大小是4个字节,在X64环境下大小是8个字节。既然指针的大小和指针类型无关,那么指针类型究竟有什么用呢?

事实上,指针类型决定看待内存的视角,具体是以下2点:

  1. 指针“走一步”能走多远。
  2. 指针解引用时,访问的权限。

1.1 决定步长

先说第一点。假设给一个int*类型的指针和一个char*类型的指针+1,分别跳过几个字节呢?

#include <stdio.h>int main()
{int a = 100;int* pa = &a;char c = 'f';char* pc = &c;printf("    pa = %p\n", pa);printf("pa + 1 = %p\n", pa + 1);printf("    pc = %p\n", pc);printf("pc + 1 = %p\n", pc + 1);return 0;
}

输出结果:
在这里插入图片描述
有意思的是,int*类型的指针+1会跳过4个字节,而char*类型的指针+1会跳过1个字节。

这是为什么呢?在整型指针眼里,内存中的数据都是int类型的,如果+1,自然跳过一个int,也就是跳过了4个字节。同理,在字符指针眼里,内存中的数据都是char类型的,如果+1,自然跳过一个char,也就是跳过了1个字节。

那+2,+3,-1呢?如果是整型指针,+2就应该跳过2个整型,也就是向后跳8个字节。而-1就应该向前跳过1个整型,也就是向前跳4个字节。其实,这就是指针的运算之一:指针±整数。

综上所述:指针的类型,决定了指针±整数时,向前/后走的步长。具体来说,对于一个type*类型的指针,±n后,会向后/前跳过n*sizeof(type)个字节。

1.2 决定访问权限

如果对一个int*类型的指针解引用,在整型指针眼里,内存中的数据都是整型,解引用后,会向后看4个字节,并且认为这4个字节中,存储的数据是整型。如果对一个char*类型的指针解引用,在字符指针眼里,内存中的数据都是字符,解引用后,会向后看1个字节,并且认为这1个字节中,存储的数据是字符。

如何验证这一点呢?可以这样做:假设内存中存储了一个16进制数字:

int a = 0x11223344;

如果我把它的地址给一个int*类型的指针,再解引用会发生啥?

int* pa = &a;
*pa = 0;

如果大家对指针有一定的了解,应该知道,pa里存的是a的地址,对pa解引用,就能访问a,并且把a给改了,a的值就变成了0。而a是4个字节的数据,这一改,其实把这4个字节都改成了0,这就证明了int*类型的指针解引用会访问4个字节。

那如果是char*类型的指针呢?

char* pc = &a;
*pc = 0;

我们来观察一下内存。这是修改前:
在这里插入图片描述
由于我的环境是小端字节序,在内存中是倒着存储的。此时如果执行*pc = 0;,会发生啥?
在这里插入图片描述
第一个字节的数据被改成了0!也就是说,对一个char*类型的指针解引用,只会访问一个字节的数据。

综上所述:指针类型决定了访问的权限,即解引用后能访问几个字节。一个type*类型的指针,解引用后能访问sizeof(type)个字节。

2.指针运算

指针有4中常见运算,分别是:

  1. 解引用。
  2. ±整数。
  3. 指针-指针。
  4. 指针之间的大小比较。

下面分别详细讲解。

2.1 指针的解引用

对一个指针解引用,会先在内存中找到指针变量中存放的地址处,再根据指针变量的类型决定访问的权限。

比如,一个很基础的代码:

int a = 10;
int* pa = &a;
*pa = 20;

int* pa = &a;这句代码中,会把a的地址存放到pa中。而*pa = 20;这句代码会如何执行呢?

  1. 首先,在pa中取出前面存放的a的地址。
  2. 在内存中,找到该地址。
  3. 根据pa的类型是int*,决定了看待内存的视角:一次访问4个字节的空间,且这4个字节的空间内存储的类型是int。
  4. 以存储的地址为首地址,向后访问4个字节,认为这4个字节存储的数据是int数据,并且把这个数据改成20。

2.2 指针±整数

指针±整数,这个整数是几,就会根据指针的类型,向后/前跳过几个该类型的元素,其中“加”就向后跳,“减”就向前跳。

一个很经典的例子,就是使用指针访问数组。

int arr[] = {1,2,3,4,5,6,7,8,9,10};
int* p = arr;
for (int i = 0; i < sizeof(arr)/sizeof(arr[0]); ++i)
{printf("%d ", *(p+i));
}

这里的p+i,就会从p指向的位置开始,向后跳i个int类型的数据,其实就相当于找到了数组下边为i的元素,此时解引用就能拿到这个元素。

咦,有没有发现,*(p+i)似乎作用就相当于arr[i]?而我们前面写了int* p = arr;是不是可以理解为,p就等价于arr,也就是说,下面这4个玩意是等价的:

*(p+i) <—> *(arr+i) <—> arr[i] <—> p[i]

所以,用下标访问数组,如arr[i]的形式,其实本质上就是指针±整数指针的解引用的结合!

2.3 指针-指针

指针-指针,得到的是指针之间的元素个数。比如:

int arr[10];
int n = &arr[9] - &arr[0];

上述代码中,n就是9,因为arr[9]和arr[0]都是int类型的数据,取出地址后,会得到2个int*类型的指针。它们的差,就是arr[9]和arr[0]相差了几个int类型的数据,显然是9个,所以答案是9。注意,如果写成&arr[0] - &arr[9],得到的就是-9。

其实,根据前面的讲解,a[i]就等价于*(a+i)。那么,下面的等式成立(这是一个不太严谨的理解):

&arr[9]-&arr[0] = &*(arr+9) - &*(arr+0) = (arr+9) - (arr+0) = 9

是不是很有意思?

2.4 指针之间的大小比较

这个就很简单了,单纯是比较指针变量存储的地址之间的大小。

比如,随着数组下标的增长,地址是由低到高变化的,所以就有:&arr[0] < &arr[9]。

总结

  1. 指针的类型决定了看待内存的视角。具体决定了指针±整数时的步长,以及解引用时访问的权限。
  2. 指针主要有4种运算,分别是:解引用,±整数,指针-指针以及指针的关系运算。

感谢大家的阅读!

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

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

相关文章

银行系统【GUI/Swing+MySQL】(Java课设)

系统类型 Swing窗口类型Mysql数据库存储数据 使用范围 适合作为Java课设&#xff01;&#xff01;&#xff01; 部署环境 jdk1.8Mysql8.0Idea或eclipsejdbc 运行效果 ​​​​​​​ 本系统源码地址&#xff1a;​​​​​​​https://download.csdn.net/download/qq_50…

从零开始写ChatGLM大模型的微调代码

cursor 的下载及安装&#xff08;免费版每月100次&#xff0c;升级pro 20刀/月&#xff09; cursor是一款与openai合作的&#xff0c;使用gpt-4的一款编程工具&#xff0c;它可以让你通过gpt-4进行辅助编程&#xff0c;以此提高效率。 下载地址&#xff1a;https://www.curso…

USART串口协议和USART串口外设(USART串口发送串口发送和接收)

1、通信接口 • 通信的目的&#xff1a;将一个设备的数据传送到另一个设备&#xff0c;扩展硬件系统 • 通信协议&#xff1a;制定通信的规则&#xff0c;通信双方按照协议规则进行数据收发 异步&#xff1a;需要双方约定一个频率 2、 硬件电路 • 简单双向串口通信有两根通信…

【Unity-ML】Unity机器学习(一)

安装环境&#xff1a;Windows10 Anaconda3(64-bit)&#xff0c;网上很多教程&#xff0c;例如这个anaconda下载及安装(保姆级教程) - 知乎anaconda包管理器和环境管理器&#xff0c;强烈建议食用 1.下载官网下载太慢可选用镜像下载 官网下载&#xff1a; Anaconda | Individua…

〖ChatGPT实践指南 - 零基础扫盲篇④〗- OpenAI API 相关介绍、提示-Prompt 与 完成-Completion

文章目录 ⭐ OpenAI API介绍⭐ 提示-Prompt 与 完成-Completion 介绍 这一章节将为各位小伙伴介绍一下 OpenAI 的 API 相关内容&#xff0c;以及在 ChatGPT 中两个经常被用来比较的名词&#xff1a;“提示-prompt” 与 “完成-completion”。 ⭐ OpenAI API介绍 OpenAI API 概…

JavaScript常用方法整理

文章目录 前言1.栈方法&#xff1a;push()、pop()2.队列方法&#xff1a;unshift()、shift()3.indexof()、lastIndexOf()、includes()4.操作方法&#xff1a;concat()、slice()、splice()5.Array.isArray()6.排序方法:sort()、reverse()7.转换方法&#xff1a;toString()、join…

【Winform学习笔记(二)】TextBox文本框实现按回车键触发Button事件

TextBox文本框实现按回车键触发Button事件 前言正文1、实现方法2、具体代码3、实现效果 前言 在本文中主要介绍 如何基于 Winform 框架实现 TextBox 文本框实现按回车键触发 Button 事件&#xff0c;该功能可实现在文本框中输入密码后不需要按登录或确定按钮&#xff0c;直接回…

vue页面内嵌iframe使用postMessage进行数据交互(postMessage跨域通信)

什么是postMessage postMessage是html5引入的API,它允许来自不同源的脚本采用异步方式进行有效的通信,可以实现跨文本文档,多窗口,跨域消息传递.多用于窗口间数据通信,这也使它成为跨域通信的一种有效的解决方案. vue父页面&#xff08;嵌入iframe的页面&#xff09; 在vue中…

webAPI学习笔记2(DOM事件高级)

1. 注册事件&#xff08;绑定事件&#xff09; 1.1 注册事件概述 给元素添加事件&#xff0c;称为注册事件或者绑定事件。 注册事件有两种方式&#xff1a;传统方式和方法监听注册方式 传统注册方式 利用 on 开头的事件 onclick <button οnclick“alert(hi~)”><…

如何构建可靠的台账数据——详解台账管理系统的使用方法

随着数字化的发展&#xff0c;越来越多的企业开始采用电子台账管理&#xff0c;实现了对各项业务数据的及时准确保存和管理。而在台账管理应用中&#xff0c;发票管理、工单管理和库房台账是三大重要方面。下面我将详细介绍一下台账管理系统。 一、发票管理 1.收票台账报表 …

【Python小技巧】使用Gradio构建基于ChatGPT的 Web 应用(附源码)

文章目录 前言一、Gradio是什么&#xff1f;二、使用Gradio构建基于ChatGPT的 Web 应用1. 安装gradio库2. 安装openai库&#xff08;ChatGPT的python库&#xff09;3. Web 应用示例&#xff08;源代码&#xff09; 总结 前言 随着人工智能的不断发展&#xff0c;各种智能算法越…

UE4架构初识(五)

UE4仿真引擎学习 一、架构基础 1. GameInstance UE提供的方案是一以贯之的&#xff0c;为我们提供了一个GameInstance类。为了受益于UObject的反射创建能力&#xff0c;直接继承于UObject&#xff0c;这样就可以依据一个Class直接动态创建出来具体的GameInstance子类。 UGam…

【Golang项目实战】手把手教你写一个备忘录程序|附源码——建议收藏

博主简介&#xff1a;努力学习的大一在校计算机专业学生&#xff0c;热爱学习和创作。目前在学习和分享&#xff1a;数据结构、Go&#xff0c;Java等相关知识。博主主页&#xff1a; 是瑶瑶子啦所属专栏: Go语言核心编程近期目标&#xff1a;写好专栏的每一篇文章 前几天瑶瑶子…

blender 制作城市建筑模型

我不是很会用blender 但是他可以直接制作一篇区域的建筑模型 BlenderGIS插件 城市建筑3D模型自动生成 教程_Zhichao_97的博客-CSDN博客 学习了两种 一种是通过geo.json自己加了一堆mesh 或者geometry 自己用three 做的模型 另一种是用blender 做一个整个的模型直接导入进去 …

降低风险和最大化成功:如何解决项目管理中的成本差异

作为项目经理&#xff0c;你知道让项目按计划进行并按预算进行对于项目管理的成功至关重要。你可以使用的关键工具之一是成本差异分析。但成本差异到底是什么&#xff0c;如何利用它来发挥优势呢&#xff1f; 定义成本差异 成本差异是项目实际成本与预算或计划成本之间的差异…

企业本地文档如何实现规范在线管理?

随着企业数字化生产方式的不断推进&#xff0c;网络办公和在线协作越来越普遍&#xff0c;企业内部可能出现大量的文件和文档&#xff0c;这些文档多存在于不同的设备和存储介质上&#xff0c;这给企业的信息管理带来了一定程度的困难。为了提高企业的知识管理效率&#xff0c;…

【大数据之Hadoop】二十、Yarn基础框架及工作机制

1、Yarn基础框架 Yarn是一个资源调度平台&#xff0c;负责为运算程序提供服务器运算资源&#xff0c;相当于一个分布式的操作系统平台&#xff0c;而MapReduce等运算程序则相当于运行于操作系统之上的应用程序。 YARN主要由ResourceManager、NodeManager、ApplicationMaster和…

修炼汇编语言第二章:内存地址空间(概述)

目录 前言 一、主板和接口卡 二、存储器各类芯片 三&#xff1a;内存地址空间 总结 前言 什么是内存地址空间呢&#xff1f;如果地址线为10&#xff0c;那么可以寻址1024个地址空间&#xff0c;这1024个地址空间就构成这个CPU的内存地址空间&#xff0c;下面本文将会介绍…

Python如何连接Mysql及基本操作

1.什么要做python连接mysql&#xff0c;一般是解决什么问题的 做自动化测试时候&#xff0c;注册了一个新用户&#xff0c;产生了多余的数据&#xff0c;下次同一个账号就无法注册了&#xff0c;这种情况怎么办呢&#xff1f;自动化测试都有数据准备和数据清理的操作&#xff…

代码在洛谷上跑得慢怎么办?

前言 你有没有试过以下几种情况&#xff1a; 代码在别的OJ上能过&#xff0c;在洛谷上就T了你的代码和同学的几乎相同&#xff0c;但他的AC了&#xff0c;你的却TLE了 遇到这些情况&#xff0c;你可能要花上一个多小时才能解决&#xff0c;甚至难以解决&#xff0c;将问题一…