【C语言】指针练习篇(下),深入理解指针---指针练习题【图文讲解,详细解答】

 欢迎来CILMY23的博客喔,本期系列为【C语言】指针练习篇(下),深入理解指针---指针练习题【图文讲解,详细解答】,图文讲解指针练习题,带大家更深刻理解指针的应用,感谢观看,支持的可以给个赞哇。

前言

作为指针系列的番外练习篇,本篇主要以指针练习题为主,本期博客将上期未写的二维数组开头,并且以做题的视角带入,进行深刻理解指针练习题中不同用法区别。 

二、指针,数组笔试题 

 2.3二维数组

	int a[3][4] = { 0 };

	printf("%d\n", sizeof(a));
	printf("%d\n", sizeof(a[0][0]));
	printf("%d\n", sizeof(a[0]));
	printf("%d\n", sizeof(a[0] + 1));
	printf("%d\n", sizeof(*(a[0] + 1)));
	printf("%d\n", sizeof(a + 1));
	printf("%d\n", sizeof(*(a + 1)));
	printf("%d\n", sizeof(&a[0] + 1));
	printf("%d\n", sizeof(*(&a[0] + 1)));
	printf("%d\n", sizeof(*a));
	printf("%d\n", sizeof(a[3]));

x86环境结果如下:

x64环境结果如下:

2.3解析:

     printf("%d\n", sizeof(a));

a单独放在sizeof后面,计算的是整个数组的大小,大小3*4*4 = 48字节
    printf("%d\n", sizeof(a[0][0]));

a [0][0],表示的是数组第1行第1列元素,元素是0,计算大小是整型,大小为4字节
    printf("%d\n", sizeof(a[0]));

a[0] 表示的是数组第一行的数组名,单独放在sizeof后面,计算的是一个一维数组的大小,大小为4*4 = 16字节
    printf("%d\n", sizeof(a[0] + 1));

a[0] 表示的是数组第一行的数组名,因为并没有单独放在sizeof后面,所以数组名表示数组首元素的地址,也就是a[0][0]的地址, a[0] + 1  == *(a+0) + 1 是第一行第二个元素的地址,是地址,大小就为4/8字节
    printf("%d\n", sizeof(*(a[0] + 1)));

 根据上面解释,解引用后得到的解释第一行第二个元素,数据类型是整型,所以大小为4字节
    printf("%d\n", sizeof(a + 1));

 a并没有单独放在sizeof后面,没有&,所以表示数组首元素的地址,即a[0],+1后就表示a[1]的地址,是地址就为4/8字节
    printf("%d\n", sizeof(*(a + 1)));

根据上面所说,得到的就是a[1]所对应的元素,计算的是整个一维数组的大小,数据类型是int,所以大小为4*4 = 16字节
    printf("%d\n", sizeof(&a[0] + 1));

&a[0]表示将第一行的数组地址取出来,+1就是跳过整个数组,表示的是a[1]的地址,是地址大小为4/8字节
    printf("%d\n", sizeof(*(&a[0] + 1)));

同上所述,解引用后计算的是a[1]整个数组的大小,大小为4*4=16字节
    printf("%d\n", sizeof(*a));

a是数组首元素的地址,也就是数组第一行(a[0])的地址,解引用计算的是 a[0],计算的是一个一维数组的大小,大小为4*4 = 16。

*a == *(a+0) == a[0]
    printf("%d\n", sizeof(a[3]));

因为sizeof是根据类型推断的,所以它不会实际访问,在这里a[3]  == a[0],所以大小为4*4 = 16

三、指针运算笔试题

 3.1

#include<stdio.h>

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后表示指向五后面的地址,将其整体转换成int *类型存入,ptr指针变量中,所以ptr此刻指向的是五的末尾,(a+1),a是数组名,并没有单独放在sizeof后面,也没有&操作符,所以表示数组首元素地址,+1指向数组第二个元素的地址,解引用得到2,ptr - 1,跳过的是指针类型,ptr的指针类型是int * 类型,所以跳过4个字节,指向五的前面,解引用得到5,所以答案为2,5

3.2

#include<stdio.h>
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
struct Test
{
	int Num;
    char* pcName; 
    short sDate; 
    char cha[2];
    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;	
}

结果:

解析:考点是指针加减整数,不懂的可以看入门篇http://t.csdnimg.cn/n6szR

第一个,p+0x1 ,首先0x1,转换成十进制是加1,p是指针变量,加一跳过一个指针类型的大小,p的指针类型是结构体类型,大小为20,故答案是0x100014(原先的十六进制加二十)

第二个, p不是指针,所以p如果加1,就是简单的值相加,故原先的十六进制加1,答案为0x100001

第三个,p是unsigned int*类型的指针变量,指针变量+1,跳过一个unsigned int*类型大小,故加4,0x100004

3.3

#include <stdio.h>
int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) }; 
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}

解析:

因为数组中是有逗号表达式,所以从左到右依次计算,但是整个表达式的结果是最后一个一个表达式的结果,故数组中的值是{1,3,5};

所以 int a[3][2] = { 1,3,5} 

所以打印结果为1

3.4

//假设环境是x86环境,程序输出的结果是啥?
#include <stdio.h>
 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;
 }

结果如下:

解析:考点为指针减指针,不懂的可以看入门篇http://t.csdnimg.cn/n6szR

int (*p)[4]是一个数组指针,如果把a放入p中,就相当于用p给a数组划分区域了。

它们中间相差四个元素,相减完得到-4.

如果用%p打印-4,就打印地址,就是用二进制表示-4,%d就是直接打印-4

FFFFFFFC,-4

3.5

#include <stdio.h>
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", *(ptr1 - 1), *(ptr2 - 1));
	return 0;
}

结果如下: 

 解析:

&aa + 1,aa是数组名,放在&后面,表示取出整个数组的地址,+1表示指向10的末尾的地址,将其转换成int * 类型,放入ptr1

(aa + 1) aa是数组名,没有单独放在sizeof后面,也没有&操作符,所以表示数组首元素地址,aa[0]. +1后表示a[1]的地址。将其解引用后,就表示a[1]。将其存入ptr2 减一后指向的位置就是5.

所以答案就为10和5

aa分布图如下:

3.6

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" }; 
	char** pa = a;
	pa++;
	printf("%s\n", *pa); 
    return 0;
}

结果如下:

  

解析:

char* a[]  是一个指针数组,当中存放的是w a a的地址,我们用一个二级指针pa来指向a这个数组,pa++后指向的是中间区域,解引用后得到的就是at

3.7

#include <stdio.h>
 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);

**++cpp,此刻cpp先加后用,cpp指向cp的第二个元素,也就是c+2的位置,解引用第一层,获得p的地址,再解引用后,得到POINT

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

* -- *++ cpp + 3  首先看++cpp,指向C+2这个位置,++cpp后,指向c+1这个位置,解引用后,再--,指向E这个位置,解引用后+3,指向的是T后面E前面,所以打印ER

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

cpp[-2] == *(cpp-2),所以此刻cpp指向的位置是C+3,解引用后得到F所指向的位置,+3后指向S的前面,最后打印,得到ST
    printf("%s\n", cpp[-1][-1] + 1);

cpp[-1][-1] === *(*(cpp -1) -1), cpp指向的位置是c+1,减一后指向c+2,解引用后指向p,然后减一,指向N,最后解引用再+1,指向E前面,所以打印EW

图如下所示

感谢各位同伴的支持,本期指针练习篇(下)就讲解到这啦,如果你觉得写的不错的话,可以给个赞,若有不足,欢迎各位在评论区讨论。    

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

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

相关文章

人工智能专题:基础设施行业智能化的基础设施,自智网络双价值分析

今天分享的是人工智能系列深度研究报告&#xff1a;《人工智能专题&#xff1a;基础设施行业智能化的基础设施&#xff0c;自智网络双价值分析》。 &#xff08;报告出品方&#xff1a;埃森哲&#xff09; 报告共计&#xff1a;32页 自智网络驱动的电信产业变革 经过多年的…

飞天使-k8s知识点20-kubernetes实操5-pod更新与暂停-statefulset

文章目录 资源调度 Deployment&#xff1a;扩缩容资源调度 Deployment&#xff1a;更新的暂停与恢复资源调度 StatefulSet&#xff1a;定义一个有状态服务headless service 金丝雀发布 资源调度 Deployment&#xff1a;扩缩容 扩容和缩容&#xff0c;常用的功能 scale[rootkub…

Rust 学习笔记 - Hello world

前言 本文将讲解如何完成一个 Rust 项目的开发流程&#xff0c;从编写 “Hello, World!” 开始&#xff0c;到使用 Cargo 管理和运行项目。 编写 Hello world 开始一个新项目很简单&#xff0c;首先&#xff0c;创建一个包含 main.rs 文件的 hello_world 文件夹&#xff0c;…

持久化:Linux利用SUID、任务计划、vim进行权限维持

目录 利用Linux SUID进行权限维持 利用Linux计划任务进行权限维持 利用Vim创建后门 利用CVE-2019-12735进行权限维持 使用Vim运行Python后门程序 利用Linux SUID进行权限维持 在前面我们使用Linux的SUID权限进行了权限提升&#xff0c;然后SUID还可以用来进行持久化 利用…

什么是自编码器Auto-Encoder?

来源&#xff1a;https://www.bilibili.com/video/BV1Vx411j78H/?spm_id_from333.1007.0.0&vd_sourcef66cebc7ed6819c67fca9b4fa3785d39 为什么要压缩呢&#xff1f; 让神经网络直接从上千万个神经元中学习是一件很吃力的事情&#xff0c;因此通过压缩提取出原图片中最具代…

LabVIEW卫星电视接收仿真系统

LabVIEW卫星电视接收仿真系统 随着卫星电视数字化的加速&#xff0c;传统模拟信号接收系统已无法满足需求。设计一套船载数字卫星电视接收系统&#xff0c;通过LabVIEW环境进行仿真实验&#xff0c;验证系统设计的可行性与有效性&#xff0c;满足数字信号接收的高精度要求&…

mysql 2-15

书写规范 #单行注释 */多行注释 -- 单行注释 mysql导入数据 基本SELECT语句 列的别名 三种方式 查询去除重复行 空值参与运算 着重号&#xff0c;取消关键字 查询常数&#xff0c;向前面添加常数 显示表结构 过滤数据 不分大小写&#xff0c;SQL不严谨 数值运算符 号区别 …

7.JS里表达式,if条件判断,三元运算符,switch语句,断点调试

表达式和语句的区别 表达式就是可以被求值的代码比如什么a 1 语句就是一段可以执行的代码比如什么if else 直接给B站的黑马程序员的老师引流一波总结的真好 分支语句 就是基本上所有的语言都会有的if else 语句就是满足不同的条件执行不同的代码&#xff0c;让计算机有条件…

使用倒模耳机壳UV村脂胶液制作舞台监听耳返入耳式耳机壳有哪些优点?

使用倒模耳机壳UV树脂胶液制作舞台监听耳返入耳式耳机壳有很多优点&#xff0c;具体如下&#xff1a; 高音质表现&#xff1a;通过倒模工艺制作的耳机壳能够更好地贴合耳朵&#xff0c;减少声音散射和反射&#xff0c;提高声音的清晰度和质感。这对于舞台监听来说非常重要&…

智能传感器阅读笔记-物联网用智能传感器技术的发展重点

物联网用智能传感器技术的发展重点包含边缘计算算法优化、身份认证算法优化和能量采集技术。 图1 物联网用智能传感器技术的发展重点 边缘计算算法优化 边缘计算是指在靠近物或数据源头的一侧&#xff08;传感器侧&#xff09;&#xff0c;采用集检测、计算、存储、通信功能…

C语言从零实现贪吃蛇小游戏

制作不易&#xff0c;点赞关注一下呗&#xff01;&#xff01;&#xff01; 文章目录 前言一. 技术要点二、WIN32API介绍三、贪吃蛇游戏设计与分析 1.游戏开始前的初始化 2.游戏运行的逻辑 总结 前言 当我们掌握链表这样的数据结构之后&#xff0c;我们就可以用它来…

第12集《佛说四十二章经》

请大家打开讲议第十五面&#xff0c;第三十一章、心寂欲除。 这几章都是佛陀指导我们如何修出离心。前面的经文讲到修出离心&#xff0c;这有对外境与对内心的出离。对外境的出离是指一位初学者&#xff0c;选择一个如法清净的道场安住&#xff0c;这非常重要。唯识学对这个概…

紫微斗数双星组合:天机天梁在辰戌

文章目录 前言内容总结 前言 紫微斗数双星组合&#xff1a;天机天梁在辰戌 内容 紫微斗数双星组合&#xff1a;天机天梁在辰戌 性格分析 在紫微斗数命盘中&#xff0c;天梁星是一颗“荫星”&#xff0c;能够遇难呈祥&#xff0c;化解凶危&#xff0c;主寿&#xff0c;主贵。…

四、JMS规范

JMS规范 一、JMS是什么二、MQ中间件对比三、JMS组成1.JMS Provider2.JMS Producer3.JMS Consumer4.JSM Message4.1 消息头4.2 消息体4.2.1 生产者4.2.2 消费者 4.3 消息属性 四、JMS可靠性1.PERSISTENT - 持久化1.1 参数设置1.2 Queue持久化1.3 Topic持久化1.3.1 持久的发布主题…

开关式稳压电源的工作原理

随着全球对能源问题的重视&#xff0c;电子产品的耗能问题将愈来愈突出&#xff0c;如何降低其待机功耗&#xff0c;提高供电效率成为一个急待解决的问题。传统的线性稳压电源虽然电路结构简单、工作可靠&#xff0c;但它存在着效率低&#xff08;只有40% &#xff0d;50%&…

通过写代码学习AWS DynamoDB (3)- 一致性hash

简介 在本文中&#xff0c;我们将简单介绍一致性hash&#xff08;consistent hash&#xff09;的概念&#xff0c;以及一致性hash可以解决的问题。然后我们将在模拟的DDB实现中实现一个简单版本的基于一致性harsh实现的partition。 问题 在《通过写代码学习AWS DynamoDB &am…

.NET Core MongoDB数据仓储和工作单元模式实操

前言 上一章节我们主要讲解了MongoDB数据仓储和工作单元模式的封装&#xff0c;这一章节主要讲的是MongoDB用户管理相关操作实操。如&#xff1a;获取所有用户信息、获取用户分页数据、通过用户ID获取对应用户信息、添加用户信息、事务添加用户信息、用户信息修改、用户信息删除…

适合新手注册google谷歌账号详细步骤截图演示,记录解决 “此电话号码无法用于进行验证” 问题

目录 手机号码验证问题解决方法具体注册步骤演示1、谷歌浏览器改语言2、点击注册3、选择个人用途4、输入姓名5、输入年月日6、创建登录账号7、设置登录密码8、手机号码验证&#xff08;重点&#xff09;9、手机号码验证成功界面10、关联邮箱备用登录账号设置 手机号码验证问题 …

Java与JavaScript同源不同性

Java是目前编程领域使用非常广泛的编程语言&#xff0c;相较于JavaScript&#xff0c;Java更被人们熟知。很多Java程序员想学门脚本语言&#xff0c;一看JavaScript和Java这么像&#xff0c;很有亲切感&#xff0c;那干脆就学它了&#xff0c;这也间接的帮助了JavaScript的发展…

2.1.1 摄像头

摄像头 更多内容&#xff0c;请关注&#xff1a; github&#xff1a;https://github.com/gotonote/Autopilot-Notes.git 摄像头是目前自动驾驶车中应用和研究最广泛的传感器&#xff0c;其采集图像的过程最接近人类视觉系统。基于图像的物体检测和识别技术已经相当成熟&#…