【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

图如下所示

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

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

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

相关文章

文件操作详解

文章目录 目录1. 为什么使用文件2. 什么是文件2.1 程序文件2.2 数据文件2.3 文件名 3. 文件的打开和关闭3.1 文件指针3.2 文件的打开和关闭 4. 文件的顺序读写5. 通讯录的改造6. 文件的随机读写6.1 fseek6.2 ftell6.3 rewind 7. 文本文件和二进制文件8. 文件读取结束的判定9. 文…

『运维备忘录』之 Lsof 命令详解

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

Excel模板2:进度条甘特图

Excel模板2&#xff1a;进度条甘特图 ‍ 今天复刻B站up【名字叫麦兜的狗狗】的甘特图&#xff1a;还在买Excel模板吗&#xff1f;自己做漂亮简洁的甘特图吧&#xff01;_哔哩哔哩_bilibili 阿里网盘永久分享&#xff1a;https://www.alipan.com/s/cXhq1PNJfdm 当前效果&…

《剑指offer》--字符串左旋【超详细建议收藏】

字符串左旋的三种方法 1. 一个一个字符挪2. 库函数---strcpy和strncat3. 三段逆置法 1. 一个一个字符挪 代码实现如下&#xff1a; #include <stdio.h> #include <string.h>void Left_Reverse(char* str,int k) {int len strlen(str);//6int time 0;time k % …

react【六】 React-Router 路由

文章目录 1、Router1.1 路由1.2 认识React-Router1.3 Link和NavLink1.4 Navigate1.5 Not Found页面配置1.6 路由的嵌套1.7 手动路由的跳转1.7.1 在函数式组件中使用hook1.7.2 在类组件中封装高阶组件 1.8 动态路由传递参数1.9 路由的配置文件以及懒加载 1、Router 1.1 路由 1.…

【C语言】常见字符串函数的功能与模拟实现

目录 1.strlen() 模拟实现strlen() 2.strcpy() 模拟实现strcpy() 3.strcat() 模拟实现strcat() 4.strcmp() 模拟实现strcmp() 5.strncpy() 模拟实现strncpy() 6.strncat() 模拟实现strncat() 7.strncmp() 模拟实现strncmp() 8.strstr() 模拟实现strstr() 9.str…

几个经典金融理论

完整EA&#xff1a;Nerve Knife.ex4黄金交易策略_黄金趋势ea-CSDN博客 一、预期效用理论 预期效用理论是描述人们在做出决策时如何考虑风险和不确定性的一种理论。该理论最初由经济学家冯诺伊曼&#xff08;John von Neumann&#xff09;和奥斯卡摩根斯坦恩&#xff08;Oskar…

全栈笔记_工具篇(nvm免安装版配置)

免安装版配置 下载nvm包:选择免安装压缩包nvm-noinstall.zip 解压zip包:将压缩包解压到指定目录,如:C:\nvm 新增环境变量: NVM_HOME:nvm解压之后的文件路径,对应配置文件里的root值NVM_SYMLINK:nvm 文件夹里新建 nodejs文件夹,对应配置文件里的path值 修改环境变量Pat…

数解 transformer 之 self attention transformer 公式整理

千万不要从任何角度轻看 transformer&#xff0c;重要的话说四遍&#xff1a; 千万不要从任何角度轻看 transformer 千万不要从任何角度轻看 transformer 千万不要从任何角度轻看 transformer Attention is all you need 整个项目是鬼斧神工之作&#xff0c;巧夺天工之作&a…

Spring 用法学习总结(三)之 AOP

Spring学习 7 bean的生命周期8 AOP面向切面编程8.1 AOP相关术语8.2 AOP使用 7 bean的生命周期 bean的生命周期主要为bean实例化、bean属性赋值、bean初始化、销毁bean&#xff0c;其中在实例化和初始化前后都使用后置处理器方法&#xff0c;而InstantiationAwareBeanPostProce…

控制论与科学方法论

《控制论与科学方法论》&#xff0c;真心不错。 书籍原文电子版PDF&#xff1a;https://pan.quark.cn/s/00aa929e4433&#xff08;分类在学习目录下&#xff09; 备用链接&#xff1a;https://pan.xunlei.com/s/VNgj2vjW-Hf_543R2K8kbaifA1?pwd2sap# 控制论是一种让系统按照我…

CTF-web 之 burp suite 使用

burp suite 使用 一般其是作为一个辅助工具&#xff0c;直接使用来解题的部分是少数&#xff0c;我们可以使用它来观察请 求和响应&#xff0c;并且可以反复的提交&#xff0c;关键的是他还带有很多其他的功能&#xff0c;在我们做题的过程中&#xff0c; 使用的关键点包括&…

MyBatis篇----第六篇

系列文章目录 文章目录 系列文章目录前言一、什么是 MyBatis 的接口绑定?有哪些实现方式?二、使用 MyBatis 的 mapper 接口调用时有哪些要求?三、Mapper 编写有哪几种方式?前言 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳…

OpenGL-ES 学习(1)---- AlphaBlend

AlphaBlend OpenGL-ES 混合本质上是将 2 个片元的颜色进行调和(一般是求和操作)&#xff0c;产生一个新的颜色 OpenGL ES 混合发生在片元通过各项测试之后&#xff0c;准备进入帧缓冲区的片元和原有的片元按照特定比例加权计算出最终片元的颜色值&#xff0c;不再是新&#xf…

书生浦语大模型实战营-课程笔记(2)

介绍了一下InternLm的总体情况。 InternLm是训练框架&#xff0c;Lagent是智能体框架。 这个预训练需要这么多算力&#xff0c;大模型确实花钱。 Lagent是智能体框架&#xff0c;相当于LLM的应用。 pip设置 开发机的配置 pip install transformers4.33.1 timm0.4.12 sente…

vue项目搭建测试

5&#xff0c;项目测试 导入elementplus以及样式 import ElementPlus from element-plus import element-plus/dist/index.csscreateApp(App).use(store).use(router).use(ElementPlus).mount(#app)<template><el-row class"mb-4"><el-button>De…

MATLAB|基于改进二进制粒子群算法的含需求响应机组组合问题研究(含文献和源码)

目录 主要内容 模型研究 1.改进二进制粒子群算法&#xff08;BPSO&#xff09; 2.模型分析 结果一览 下载链接 主要内容 该程序复现《A Modified Binary PSO to solve the Thermal Unit Commitment Problem》&#xff0c;主要做的是一个考虑需求响应的机组组合…

投资银行在网络安全生态中的作用

文章目录 一、投资银行的含义(一)并购买方。(二)并购卖方。(三)IPO辅助。(四)投资银行业务的另一方面是帮助这些交易融资。二、从投资银行角度看网络安全产业(一)行业的短期前景三、复杂的网络安全并购(一)行业知识对投资银行业务很重要(二)在网络安全领域,技术…

HDFS的超级用户

一. 解释原因 HDFS(Hadoop Distributed File System)和linux文件系统管理一样&#xff0c;也是存在权限控制的。 但是很不一样的是&#xff0c; 在Linux文件系统中&#xff0c;超级用户Superuser是root而在HDFS中&#xff0c;超级用户Superuser是启动了namenode的用户&#x…

neo4j下载安装最新教程 2024.02

文章目录 neo4j简介下载地址配置环境变量命令行启动验证安装结果 neo4j简介 Neo4j 是一个高性能的 NoSQL 图形数据库&#xff0c;它将结构化数据存储在网络&#xff08;从数学角度叫做图&#xff09;上而不是表中。Neo4j 也可以被看作是一个高性能的图引擎&#xff0c;该引擎具…