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

news2024/10/7 8:32:09

如题,本篇博客主要解决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.coloradmin.cn/o/461248.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

AI看图说话,MiniGPT-4已经开源

MiniGPT-4 是一个人工智能工具&#xff0c;​最大的飞跃是增加了识图能力&#xff0c;​并且回答准确性也得到显著提高。​它可以识别图片并回答关于图片的问题&#xff0c;​例如图片内容、​颜色等等。 ​此外&#xff0c;​它还可以进行图像对话&#xff0c;​即通过图片和…

MFC之CRect详解

2023年4月25日&#xff0c;周二晚上。 今天查了不少关于CRect类及其相关内容的资料&#xff0c;学到了不少东西&#xff0c;所以我决定写一篇详细的关于CRect类及其相关内容的文章&#xff0c;以记录今天所学。 CRect类 在 MFC 中&#xff0c;CRect 类表示一个矩形区域。它是…

【Vue 移动端开发】适配百分之99的屏幕方案

之前提起移动端适配&#xff0c;都是一些视口的概念&#xff0c;包括物理像素和逻辑像素&#xff0c;理想视口&#xff0c;dpr等等等。利用 media query 和 rem 是最常见的移动端适配方案。如下代码&#xff1a; const deviceWidth document.documentElement.clientWidth || …

Axure RP 9 for Mac 原型设计软件安装,Mac软件打开提示:已损坏,无法打开。您应该将它移到废纸篓。怎么解决?

Axure RP 9 for Mac 原型设计软件安装&#xff0c;Mac软件打开提示&#xff1a;已损坏&#xff0c;无法打开。您应该将它移到废纸篓。怎么解决? 安装过程很简单&#xff1a; 1、下载后先将软件拖入应用程序中&#xff1b; 2、打开软件&#xff0c;弹出登录界面&#xff0c;点…

网络编程代码实例:用户数据报协议(UDP)简单版

文章目录 前言代码仓库内容代码&#xff08;有详细注释&#xff09;server.cclient.cMakefile 结果总结参考资料作者的话 前言 网络编程代码实例&#xff1a;用户数据报协议&#xff08;UDP&#xff09;简单版。 代码仓库 yezhening/Environment-and-network-programming-exa…

[ICLR 2020] Reducing Transformer Depth on Demand with Structured Dropout

Contents IntroductionTraining Transformers with Random Structured PruningRandomly Dropping Structures at Training TimePruning at Inference Time ExperimentsReferences Introduction 作者提出了一种新的 structural pruning 方法 LayerDrop&#xff0c;通过在训练时…

FastDFS集群搭建

简介 FastDFS是什么&#xff1f;我们这里可以看一下度娘的解释。FastDFS是一个开源的轻量级分布式文件系统&#xff0c;它对文件进行管理&#xff0c;功能包括&#xff1a;文件存储、文件同步、文件访问&#xff08;文件上传、文件下载&#xff09;等&#xff0c;解决了大容量…

Python base64模块加密解密

一、为何使用base64加密解密 为了安全机制的系统&#xff0c;在用户登录的时候&#xff0c;会采用一系列措施保护用户信息&#xff0c;防止程序被攻击&#xff0c;比如&#xff1a;将用户输入的密码加密处理&#xff0c;在控制台看请求接口看到的密码是加密过的密码&#xff0c…

前端 Chrome 插件推荐

1.Ajax Interceptor 场景&#xff1a; 1.前端本地在开发&#xff0c;后端接口还没好&#xff0c;可以提前mock数据&#xff0c;并且真实的模拟网络请求。可以对代码不侵入的方式&#xff0c;提高编码效率。后面真实联调速度就会快很多。 2.当你参与项目的一部分开发的时候&a…

WPF实现PasswordBox切换明密功能

✅作者简介&#xff1a;2022年博客新星 第八。热爱国学的Java后端开发者&#xff0c;修心和技术同步精进。 &#x1f34e;个人主页&#xff1a;Java Fans的博客 &#x1f34a;个人信条&#xff1a;不迁怒&#xff0c;不贰过。小知识&#xff0c;大智慧。 &#x1f49e;当前专栏…

生产mysql遇到kill不掉的sql的解决方法

一、问题描述 今天上线&#xff0c;生产mysql有个2700万数据的大表lt_integral_detail_info&#xff0c;准备给这个表加字段、加索引&#xff1b; 执行加字段加索引的命令比较费时&#xff0c;结果这时有人对这个表执行了多个select count(*)操作&#xff0c;导致直接把Navic…

SQL优化(5):limit优化

在数据量比较大时&#xff0c;如果进行limit分页查询&#xff0c;在查询时&#xff0c;越往后&#xff0c;分页查询效率越低。 我们一起来看看执行limit分页查询耗时对比&#xff1a; 找一个有1000W数据量的表进行测试分析 查询前10条数据分页&#xff0c;耗时0.03秒 查询100…

【力扣】二叉树的分层遍历1和2

二叉树的分层遍历1 链接&#xff1a;二叉树的分层遍历1&#xff1a; 首先&#xff0c;我们需要知道什么是二叉树的层序遍历。二叉树的层序遍历是一种按照树的层次从上到下&#xff0c;从左到右访问每个节点的方法。例如&#xff0c;对于下面这棵二叉树&#xff1a; 1/ \2 3…

Linux_红帽8学习笔记分享_7(Crontab计划任务+NTP时间同步服务器)

Linux_红帽8学习笔记分享_7(Crontab计划任务NTP时间同步服务器) 文章目录 Linux_红帽8学习笔记分享_7(Crontab计划任务NTP时间同步服务器)1. 系统时间1.1查看系统时间1.2设置系统时间 2.周期性计划任务2.1认识周期性任务服务2.2寻找定时文件的配置文件2.3用户定时任务的格式2.4…

行业方案|智能网联汽车数据安全治理框架

近年来&#xff0c;信息技术的快速发展&#xff0c;加快了汽车产业的变革。与此同时&#xff0c;随着智能化、网联化的推进&#xff0c;汽车的数据安全问题也日益凸显。当下&#xff0c;如何保障数据安全&#xff0c;成为影响智能汽车产业健康发展的关键问题。 4月18日&#x…

Linux Ansible创建任务并执行

目录 通过add-hoc执行anbise任务 通过Playbook剧本方式执行任务 Playbook包含的常用对象 Yaml语法 对Yaml格式自动对齐 Playbook语法检测与执行 Playbook任务实施 Playbook特权升级 Playbook常用模块 软件包管理模块 用户管理模块 存储模块管理 文件操作相关模块 …

GPT-3 论文阅读笔记

GPT-3模型出自论文《Language Models are Few-Shot Learners》是OpenAI在2020年5月发布的。 论文摘要翻译&#xff1a;最近的工作表明&#xff0c;通过对大量文本进行预训练&#xff0c;然后对特定任务进行微调&#xff08;fine-tuning)&#xff0c;在许多NLP任务和基准测试上…

TYPE-C口是怎么样的接口?它有什么功能强大的地方?

C口指的是USBType-C接口。USBType-C&#xff0c;又称USB-C&#xff0c;是一种通用串行总线(USB)的硬件接口形式&#xff0c;外观上最大特点在于其上下端完全一致与Micro-USB相比不再区分USB正反面。 认识了Type-C的外观之后&#xff0c;我们来一起看一下它是怎么产生的。早在20…

QT with OpenGL(IBL-镜面反射)

文章目录 预滤波generate Mipmap获取每一层级的预滤波图prefilterMap Shader重要性采样效果展示 预过滤卷积的亮点解决方法代码解析首先得确保我们被采样的环境贴图有mipmap贴图通过计算决定使用那一层mipmap值 效果 预计算BRFD生成LUT图 IBL Shading渲染结果与教材的不同最终结…

(C语言版)力扣(LeetCode)189. 轮转数组官方3种解法分析

轮转数组 题目第一种解法&#xff1a;额外数组第二种解法&#xff1a;环状替换第三种解法&#xff1a;翻转数组结语 题目 题目链接&#xff1a;轮转数组 给定一个整数数组 nums&#xff0c;将数组中的元素向右轮转 k 个位置&#xff0c;其中 k 是非负数。 示例 1: 输入: num…