当前位置: 首页 > news >正文

【C语言】——指针八:指针运算笔试题解析

【C语言】——指针八:指针运算笔试题解析

    • 一、题一
    • 二、题二
    • 三、题三
    • 四、题四
    • 五、题五
    • 六、题六
    • 七、题七

一、题一

//程序输出结果是什么
int main()
{int a[5] = { 1,2,3,4,5 };int* ptr = (int*)(&a + 1);printf("%d, %d", *(a + 1), *(ptr - 1));return 0;
}

  这道题 * (a + 1) 相信大家都没问题,它表示的是数组的第二个元素
  
我们来重点讲一下*(ptr - 1)

  • 先来看 &a。对数组名进行取地址操作, 取出的是整个数组的地址,虽然数值上与数组首元素相等,但他们是不同的类型。在这里,它类型为 i n t ( ∗ ) [ 5 ] int(*)[5] int[5]
      
  • 再看 &a + 1 ,这里取出的是整个数组的地址,+1 即跳过整个数组。最后,再强制类型转换成 i n t int int * 类型
      
  • ptr - 1 此时,指针已经跳过了整个数组,因为此时的 p t r ptr ptr 已经是 i n t int int* 类型, - 1,后退 4 个字节,即指向数组最后一个元素
      
  • *(ptr - 1) 最后再进行解引用,取出数组最后一个元素

在这里插入图片描述

运行结果:

图:

  
  

  
  
  

二、题二

//在x86环境下
//假设结构体大小20字节
//程序输出结果是啥
struct Test
{int Num;char* pcName;short sDate;char cha[3];short sBa[4];
}*p = (struct Test*)0x100000;int main()
{printf("%p\n", p + 0x1);printf("%p\n", (unsigned long)p + 0x1);printf("%p\n", (unsigned int*)p + 0x1);return 0;
}

  

  • 首先我们来理解(定义的结构体类型)*p = (struct Test*)0x100000; 什么意思呢?即定义了一个结构体类型,创建了该类型的指针变量 p p p 。同时,将0x100000这个十六进制数强制类型转换成该结构体指针类型(整数默认 i n t int int 类型)后,将其赋值指针变量 p p p
      
  • printf("%p\n", p + 0x1); 指针类型 +1,跳过的是该指针所指向元素的类型的大小个字节。这里定义的结构体大小为 20 字节,即跳过 20 字节,因为是十六进制表示,即:0x100000 + 0x14,答案:0x100014
      
  • printf("%p\n", (unsigned long)p + 0x1); 第二个 p r i n t f printf printf 语句,先将 p p p 强制类型转换成 u n s i g n e d unsigned unsigned l o n g long long 类型,此时0x100000 仅仅是 一个普通的数字而已,再加 0x1,是单纯的数学上的相加。答案:0x100001
      
  • printf("%p\n", (unsigned int*)p + 0x1); 第三个 p r i n t f printf printf 语句,先将 p p p 强制类型转换成 u n s i g n e d unsigned unsigned i n t int int *类型, u n s i g n e d unsigned unsigned i n t int int 大小为 4 个字节,所以 +1 跳过 4 个字节,十六进制表示。答案:0x100004

  
运行结果:
图

  
  
  
  
  

三、题三

int main()
{int a[3][2] = { (0,1),(2,3),(4,5) };int* p;p = a[0];printf("%d\n", p[0]);return 0;
}

  

  • int a[3][2] = { (0,1),(2,3),(4,5) };先来看对数组的初始化。这里有个小坑点 { (0,1 ), (2,3 ), (4,5 ) }大括号内是三个小括号,表示的是逗号表达式,并不是三个大括号,按行初始化。逗号表达式,从左到右一次执行,整个表达式的结果是最后一个表达式的结果

  因此数组中存放的数据是:

在这里插入图片描述

  

  • p = a[0]; a [ 0 ] 可以看做是二维数组中,第一行数组的数组名,数组名表示的是数组首元素的地址,即 p p p 中存放的是 1 的地址
      
  • printf("%d\n", p[0]); p [ 0 ] 相当于*(p + 0) == *p,即打印 1
      

运行结果:
图:

  
  
  
  
  

四、题四

int main()
{int a[5][5];int(*p)[4];p = a;printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);return 0;
}
  • 理解这题,关键的是理解&p[4][2]&a[4][2]分别指向哪个元素。
      
  • 首先来看&a[4][2]
    • & a [ 4 ] [ 2 ] a[4][2] a[4][2] 等价于 & * ( * (a + 4)+ 2),& 和 * 相互抵消,即等价于 * (a + 4)+ 2。这里 a a a 是什么呢? a a a 是第一行这个一维数组的地址,类型为 i n t ( ∗ ) [ 5 ] int(*)[5] int()[5] a a a + 4,指向第五行。再对其进行解引用,得到的是第五行这个数组,即第五行的数组名,即第五行数组首元素的地址,对其 +2,指向第五行第三个元素

  

图:

  

  • 接着我们来看&p[4][2]
    • p p p 的类型为 i n t ( ∗ ) [ 4 ] int(* )[4] int()[4] ,题目中将 a a a 的地址给 p p p ,其实会报警告,因为 a a a i n t ( ∗ ) [ 5 ] int( * )[5] int()[5] 类型,类型不匹配,但程序能运行。
    • &p[4][2] 等价于* (p + 4)+ 2。首先,我们要理解 p p p + 1 跳过几个字节。因为 p p p 的类型为 i n t ( ∗ ) [ 4 ] int(* )[4] int()[4] ,所以在 p p p 眼里,二维数组 a a a 是一个每行有 4 个元素的数组+1 跳过的是 4 个整型,即 16 个字节。而 p p p + 4 则是过了 16 个整型,即 64 个字节
        
        
  • * (p + 4) + 2:对 p p p 进行解引用,再 +2,这个过程与 * (a + 4)+ 2 相同,即指针移动了两个整型大小的字节,指向第三个元素
      

-

  

  • 可以看到,&p[4][2]&a[4][2]之间相差了 4 个元素,因为&p[4][2]是小地址,所以 &p[4][2] - &a[4][2] = -4
      

  • printf("%p,%d\n", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]); &p[4][2] - &a[4][2]的结果是 - 4,因此以%d的形式打印没问题。那以%p形式打印呢?%p是打印地址,地址肯定是无符号类型。- 4 的补码是11111111 11111111 11111111 11111100,转为十六进制为 FF FF FF FC
      

运行结果:

在这里插入图片描述

  
  
  
  
  

五、题五

int main()
{int aa[2][5] = { 1,2,3,4,5,6,7,8,9,10 };int* ptr1 = (int*)(&aa + 1);int* ptr2 = (int*)(*(aa + 1));printf("%d %d\n", *(ptr1 - 1), *(ptr2 - 1));return 0;
}

  

  • 这道题的数组初始化没有坑啊,不用担心。
      
  • int* ptr1 = (int*)(&aa + 1); & a a aa aa:& + 数组名,取出的是整个数组的地址,+1 跳过整个数组,再将其强制类型转换成 i n t int int* 类型。
      
  • int* ptr2 = (int*)(*(aa + 1)); a a aa aa数组首元素的地址,即第一行的地址,+1 跳过第一行,指向第二行。对其进行解引用,得到的是第二行的数组名,即第二行首元素的地址。其实这里强制类型转换成 i n t int int *是多余的,第二行首元素的地址本来就是 i n t int int *类型。
      
  • printf("%d %d", *(ptr1 - 1), *(ptr2 - 1)); 此时 * ( p t r 1 − 1 ) (ptr1 - 1) (ptr11) 与 * ( p t r 2 − 1 ) (ptr2 - 1) (ptr21) 都是 i n t int int *类型,- 1 后退 4 个字节,即一个整型元素。
      

图:

  
运行结果:
在这里插入图片描述

  
  
  
  
  

六、题六

int main()
{char* a[] = { "work","at","alibaba" };char** pa = a;pa++;printf("%s\n", *pa);return 0;
}

  

  • char* a[ ] = { "work","at","alibaba" }; 这是一个指针数组,数组中每个元素都放着指向对应字符串的首元素的地址。
      
  • char** pa = a; 这里取出数组首元素的地址,因为数组首元素原本类型为指针类型,所以这里 p a pa pa二级指针
      
  • pa++; p a pa pa = p a pa pa + 1,指向数组第二个元素的地址。
      
  • printf("%s\n", *pa); p a pa pa 解引用,得到指向 “ a t at at” 的地址,打印 a t at at
      

运行结果:
图:
  
  可能有些小伙伴对二级指针有点迷糊,这张图就一目了然啦(这里是 x86 环境下,x64 环境下指针变量大小 8 字节)
  

在这里插入图片描述

  
  这里我们可以把各个地址打印出来观察

int main()
{char* a[] = { "work","at","alibaba" };printf("%p\n", &a[0]);printf("%p\n", &a[1]);printf("%p\n", &a[2]);printf("\n");printf("%p\n", a[0]);printf("%p\n", a[1]);printf("%p\n", a[2]);return 0;
}

  
运行结果:
在这里插入图片描述
  
  
  
  
  

七、题七

int main()
{char* c[] = { "ENTER","NEW","POINT","FIRST" };char** cp[] = { c + 3,c + 2,c + 1,c };char*** cpp = cp;printf("%s\n", **++cpp);printf("%s\n", *-- * ++cpp + 3);printf("%s\n", *cpp[-2] + 3);printf("%s\n", cpp[-1][-1] + 1);return 0;
}

  
  要理解这道题,画图是必不可少的,我们先把图画出来

在这里插入图片描述

  

printf("%s\n", **++cpp);
  

  • 前置++ 与解引用操作符 ∗ * 的优先级一致,根据结合性从右往左运算
  • 先是 c p p cpp cpp 自增,自增后指向 c p [ 1 ] cp[1] cp[1]
  • 第一次解引用,找到 c p [ 1 ] cp[1] cp[1],第二次解引用找到 c [ 2 ] c[2] c[2]
  • 最终打印:POINT
      
      
    在这里插入图片描述

  

printf("%s\n", *-- * ++cpp + 3);
  

  • 首先 + 运算符优先级最小,因此 +3 最后才算
  • 其他四个操作符优先级一样,根据结合性从左到右计算
  • 先是 c p p cpp cpp 自增,自增后指向 c p [ 2 ] cp[2] cp[2]
  • c p p cpp cpp 解引用,找到 c p [ 2 ] cp[2] cp[2]
  • c p [ 2 ] cp[2] cp[2] 自减, c c c + 1 自减为 c c c ,原本指向 c [ 1 ] c[1] c[1],自减后指向 c [ 0 ] c[0] c[0]
  • c p [ 2 ] cp[2] cp[2] 解引用,找到 c [ 0 ] c[0] c[0]
  • c [ 0 ] c[0] c[0] 指向的是 “ENTER” 字符串的首元素 'E’+3 则指向 ‘E’
  • 答案:ER

  
  
在这里插入图片描述

  

printf("%s\n", *cpp[-2] + 3);
  

  • 首先来看 c p p [ − 2 ] cpp[-2] cpp[2],它等价于 * ( c p p − 2 ) (cpp - 2) (cpp2) c p p cpp cpp - 2 后再解引用(注: c p p cpp cpp 本身值没变),找到 c p [ 0 ] cp[0] cp[0]
  • 接着,再解引用,找到 c [ 3 ] c[3] c[3]
  • c [ 3 ] c[3] c[3] 指向 “FIRST” 字符串的首元素 'F’+3 则指向 ‘S’
  • 答案:ST

  在这里插入图片描述

  

printf("%s\n", cpp[-1][-1] + 1);
  

  • c p p [ − 1 ] [ − 1 ] cpp[-1][-1] cpp[1][1] 等价于 * ( * ( c p p cpp cpp - 1 ) - 1),先来看里面的 *( c p p cpp cpp - 1),将其解引用,找到 c p [ 1 ] cp[1] cp[1]
  • 接着,再看 * ( c p [ 1 ] − 1 ) (cp[1] - 1) (cp[1]1) c p [ 1 ] − 1 cp[1] - 1 cp[1]1,原本指向 c [ 2 ] c[2] c[2]- 1 后指向 c [ 1 ] c[1] c[1]
  • c [ 1 ] c[1] c[1] 指向 “NEW” 字符串的首元素 'N’+1 则指向 ‘E’
  • 答案:EW

  
  在这里插入图片描述

相关文章:

【C语言】——指针八:指针运算笔试题解析

【C语言】——指针八:指针运算笔试题解析 一、题一二、题二三、题三四、题四五、题五六、题六七、题七 一、题一 //程序输出结果是什么 int main() {int a[5] { 1,2,3,4,5 };int* ptr (int*)(&a 1);printf("%d, %d", *(a 1), *(ptr - 1));return…...

JVM字节码与类的加载——class文件结构

文章目录 1、概述1.1、class文件的跨平台性1.2、编译器分类1.3、透过字节码指令看代码细节 2、虚拟机的基石:class文件2.1、字节码指令2.2、解读字节码方式 3、class文件结构3.1、魔数:class文件的标识3.2、class文件版本号3.3、常量池:存放所…...

小程序如何通过公众号发送新订单提醒

当客户在小程序上下单后,公众号会发送订单通知,这可以让管理员及时获知用户下单情况,方便及时处理订单和提供服务。下面是具体介绍如何设置公众号来发送订单服务通知。 方式一:通过采云公众号发送订单通知 此种方式是默认的通知…...

聊聊公众号最让我不爽的两个痛点

本文首发于 Python猫 微信公众号最让我不爽的地方有两个,而且有很多人虽然也不爽,却不知道原因。 本文想聊聊公众号的两个痛点,因为我经常收到私信问这两个问题,本文算是一次集中的回复吧。 第一个不爽的点是公众号会屏蔽外链&…...

【leetCode】2810. 故障键盘

文章目录 [2810. 故障键盘](https://leetcode.cn/problems/faulty-keyboard/)思路一:模拟代码:思路二:双端队列代码: 2810. 故障键盘 思路一:模拟 用StringBuilder来拼贴字符遍历字符串,如果遇到i,对拼贴好…...

xshell7连接ubuntu18.04

🎡导航小助手🎡 1.查看ubuntu IP2.开启openssh-server3.静态IP设置4.Xshell连接 1.查看ubuntu IP 输入下面命令查看IP ifconfig -a可以看到网卡是ens33,IP为192.168.3.180。 2.开启openssh-server 1、执行下句,下载SSH服务 s…...

真正的力量:实力与人际关系的平衡艺术

在当今社会,人们常常在追求个人发展和建立良好人际关系之间寻找平衡。有一种观点认为,“没有实力,就不要对别人好。不然,很容易被定义为讨好。”这句话在一定程度上揭示了实力与人际关系之间的微妙联系。本文将探讨这一观点的深层…...

Acwing.1388 游戏(区间DP对抗思想)

题目 玩家一和玩家二共同玩一个小游戏。 给定一个包含 N个正整数的序列。 由玩家一开始,双方交替行动。 每次行动可以在数列的两端之中任选一个数字将其取走,并给自己增加相应数字的分数。(双初始分都是 0分) 当所有数字都被…...

Numpy数组转换为csv文件

参考:Converting Numpy Array to CSV 在数据分析和处理中,经常会涉及到将数据从一个形式转换为另一个形式的操作。 其中,将Numpy数组转换为csv文件是一种常见的操作,因为csv文件是一种通用的数据存储格式,方便与其他软…...

替代安全指标(Surrogate Safety Measures (SSM) )

替代安全措施(Surrogate Safety Measures (SSM) )用于从数据中寻找接近碰撞,或可能发生(但实际没有发生)的碰撞事件。 SSM的两个合格标准: (1)它应该来自与碰撞直接相关的交通冲突&…...

usb_camera传输视频流编码的问题记录!

前言: 大家好,今天给大家分享的内容是,一个vip课程付费的朋友,在学习过程中遇到了一个usb采集的视频数据流,经过ffmpeg编码,出现了问题: 问题分析: 其实这个问题不难,关键…...

Linux安装nginx保姆级教程

文章目录 前言一、nginx安装(保姆级教程)1.安装nginx依赖2.安装wget3.创建nginx安装目录4.下载nginx5.查看下载好的nginx6.解压缩7.查看当前目录下的文件→进入nginx-1.8.0目录→查看当前目录下的文件8.安装nginx9.查看nginx安装目录并启动nginx10.网络请…...

leetcode-判断二分图

. - 力扣(LeetCode) 存在一个 无向图 ,图中有 n 个节点。其中每个节点都有一个介于 0 到 n - 1 之间的唯一编号。给你一个二维数组 graph ,其中 graph[u] 是一个节点数组,由节点 u 的邻接节点组成。形式上&#xff0c…...

算法day30 回溯6

332 重新安排行程 给你一份航线列表 tickets ,其中 tickets[i] [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。 所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK …...

分享three.js实现乐高小汽车

前言 Web脚本语言JavaScript入门容易,但是想要熟练掌握却需要几年的学习与实践,还要在弱类型开发语言中习惯于使用模块来构建你的代码,就像小时候玩的乐高积木一样。 应用程序的模块化理念,通过将实现隐藏在一个简单的接口后面&a…...

gpt的构造和原理

gpt是序列预测模型。 问答是通过确定问答格式样本训练出来的!比如“Q:xxxx.A:xxx"本质还是根据前面的序列预测后面的序列。在自回归训练过程中,文本序列(可能包含问题和紧随其后的答案)被视为一个整体输入到模型…...

基于springboot实现教师人事档案管理系统项目【项目源码+论文说明】计算机毕业设计

基于springboot实现IT技术交流和分享平台系统演示 摘要 我国科学技术的不断发展,计算机的应用日渐成熟,其强大的功能给人们留下深刻的印象,它已经应用到了人类社会的各个层次的领域,发挥着重要的不可替换的作用。信息管理作为计算…...

K8S之Job和CronJob控制器

这里写目录标题 Job概念适用场景使用案例 CronJob概念适用场景使用案例 Job 概念 Job控制器用于管理Pod对象运行一次性任务,例如:对数据库备份,可以直接在k8s上启动一个mysqldump备份程序,也可以启动一个pod,这个pod…...

基于SSM的基于个人需求和地域特色的外卖推荐系统(有报告)。Javaee项目。ssm项目。

演示视频: 基于SSM的基于个人需求和地域特色的外卖推荐系统(有报告)。Javaee项目。ssm项目。 项目介绍: 采用M(model)V(view)C(controller)三层体系结构&…...

哈佛大学商业评论 --- 第三篇:真实世界中的增强现实

AR将全面融入公司发展战略! AR将成为人类和机器之间的新接口! AR将成为人类的关键技术之一! 请将此文转发给您的老板! --- 本文作者:Michael E.Porter和James E.Heppelmann 虽然物理世界是三维的,但大…...

华为ICT七力助推文化产业新质生产力发展

创新起主导作用的新质生产力由新劳动者、新劳动对象、新劳动工具、新基础设施等四大要素共同构成,符合新发展理念的先进生产力质态;具有高科技、高能效、高质量等三大突出特征。而通过壮大新产业、打造新模式、激发新动能,新质生产力能够摆脱…...

FastGpt流程

1.知识库 引入文本——>数据清洗 最好将pdf/ppt/xx转换成文本,在文本里面进行数据清洗(以防知识库删除后,数据清洗失效) 可以插图,将图片通过网页检查F12查看路径放进去 或者直接在csdn放,直接复制链接…...

怎么在UE游戏中加入原生振动效果

我是做振动触感的。人类的五感“视听嗅味触”,其中的“触”就是触觉,是指皮肤、毛发与物体接触时的感觉。触感可以带来更加逼真的沉浸式体验。但也许过于司空见惯,也是习以为常,很多人漠视了触感的价值。大家对触感的认知还远远不…...

【Hadoop技术框架-MapReduce和Yarn的详细描述和部署】

前言: 💞💞大家好,我是书生♡,今天的内容主要是Hadoop的后两个组件:MapReduce和yarn的相关内容。同时还有Hadoop的完整流程。希望对大家有所帮助。感谢大家关注点赞。 💞💞前路漫漫&…...

蓝桥杯刷题 前缀和与差分-[3507]异或和之和(C++)

题目描述 给定一个数组 Ai,分别求其每个子段的异或和,并求出它们的和。 或者说,对于每组满足 1≤L≤R≤n 的 L,R求出数组中第 L 至第 R 个元素的异或和。 然后输出每组 L,R 得到的结果加起来的值。 输入格式 输入…...

background背景图参数边渐变CSS中创建背景图像的渐变效果

效果:可以看到灰色边边很难受,希望和背景融为一体 原理: 可以使用线性渐变(linear-gradient)或径向渐变(radial-gradient)。以下是一个使用线性渐变作为背景图像 代码: background: linear-gradient(to top, rgba(255,255,255,0)…...

『大模型笔记』吴恩达:AI 智能体工作流引领人工智能新趋势

吴恩达:AI 智能体工作流引领人工智能新趋势 文章目录 一. 概述二. AI 智能体的设计模式2.1. 反思(Reflection)2.2. 使用工具(Tool use)2.3. 规划(Planning)2.4. 多智能体协作(Multi-agent collaboration)三. 最后总结四. 参考文献一. 概述 我期待与大家分享我在 AI 智能体方面…...

腾讯光子工作室群 一面 (30min)

问题: 你毕业是打算考研还是直接工作 深挖项目(介绍、剖析遇到问题如何解决): 你在进行攻击的时候会不会有穿模的情况,怎么解决 为什么会造成卡顿(多嘴说的) 说说行为树和状态机之间的差别 …...

Linux的信号栈的实现(1)

作者 pengdonglin137@163.com 环境 Linux 6.5 + ARM64 概述 在前一篇文章中介绍了Linux系统中的几种栈以及它们之间的切换,进程在用户态和内核态会使用不同的栈,在用户态的主线程和其他线程都有各自的栈,此外进程在执行信号处理程序时也需要栈,那么这个栈来自哪呢? …...

Python学习笔记——heapq

堆排序 思路 堆排序思路是: 将数组以二叉树的形式分析,令根节点索引值为0,索引值为index的节点,子节点索引值分别为index*21、index*22;对二叉树进行维护,使得每个非叶子节点的值,都大于或者…...

做染料的网站/最近的新闻摘抄

PHP - 一维数组的排序函数 在本节中,我们将学习如下 PHP 数组排序函数: sort() - 以升序对数组排序rsort() - 以降序对数组排序asort() - 根据值,以升序对关联数组进行排序ksort() - 根据键,以升序对关联数组进行排序arsort() - 根…...

深圳教育科技网站建设/香港旺道旺国际集团

电子科大ACM团队,在学校教务处、学工部和团委等部门的大力支持下,在去年第34届ACM-ICPC国际大学生程序设计竞赛亚洲区域赛中,数学科学学院负责并组织六支队伍出战了六个赛区的比赛,最终获得四金、四银、四铜的辉煌战绩&#xff0c…...

wordpress会员vip/淘宝客推广有效果吗

7天搞定生成对抗网络!百度高级工程师组队来袭原理实战|7天学会GAN课程大纲讲师介绍学习收获万元奖品池等你来战开课时间免费报名方式深度学习中最有趣的方法是什么?GAN!最近最火的AI技术是什么?GAN!&#x…...

网站改版 打造企业文化/百度站长工具怎么关闭教程视频

1 含义 HTTP来源地址(referer,或 HTTP referer)是HTTP表头的一个字段,用来表示从哪儿链接到目前的网页,采用的格式是URL。换句话说,借着HTTP来源地址,目前的网页可以检查访客从哪里而来&#xf…...

婚礼效果图网站/网络推广有哪些渠道

实现这一个功能主要用到了selenium、mitmproxy和wechatarticles,利用selenium可以实现脚本模拟浏览器访问,mitmproxy配合wechatarticles获取文章信息。 参考文章: python爬取微信公众号文章(包含文章内容和图片) 记一次…...

电子商务网站建设完整详细流程/爱站seo工具包下载

NFS介绍 NFS是Network File System的缩写 NFS最早由Sun公司开发,分2,3,4三个版本,2和3由Sun起草开发,4.0开始Netapp公司参与并主导开发,最新为4.1版本 NFS数据传输基于RPC协议,RPC为Remote Procedure Call的简写。 …...