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

【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

图如下所示

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

相关文章:

  • Python循环语句——for循环的嵌套使用
  • Java学习第十六节之创建对象内存分析和小结类与对象
  • Java实现停车场收费系统 JAVA+Vue+SpringBoot+MySQL
  • Godot 游戏引擎个人评价和2024年规划(无代码)
  • QtApplets-线程池
  • MinGW/MSYS/GCC/GNU/MSVC/Clang/LLVM都是什么
  • 防火墙HA详解
  • 问题:内存时序参数 CASLatency 是() #学习方法#微信#微信
  • 防御保护--内容安全过滤
  • C++ 音视频原理
  • 跟着pink老师前端入门教程(JavaScript)-day02
  • OpenAl 视频生成模型 —— Sora技术报告解读
  • Excel模板2:进度条甘特图
  • 你逛过凌晨四点的校园吗?2023年终总结
  • 蓝桥杯刷题--python-7
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • Docker下部署自己的LNMP工作环境
  • Java|序列化异常StreamCorruptedException的解决方法
  • JavaScript中的对象个人分享
  • node学习系列之简单文件上传
  • Python 反序列化安全问题(二)
  • seaborn 安装成功 + ImportError: DLL load failed: 找不到指定的模块 问题解决
  • vue-loader 源码解析系列之 selector
  • Webpack入门之遇到的那些坑,系列示例Demo
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 基于游标的分页接口实现
  • 开源SQL-on-Hadoop系统一览
  • 在electron中实现跨域请求,无需更改服务器端设置
  • 怎么将电脑中的声音录制成WAV格式
  • 最简单的无缝轮播
  • [Shell 脚本] 备份网站文件至OSS服务(纯shell脚本无sdk) ...
  • 整理一些计算机基础知识!
  • #includecmath
  • #单片机(TB6600驱动42步进电机)
  • $Django python中使用redis, django中使用(封装了),redis开启事务(管道)
  • (ctrl.obj) : error LNK2038: 检测到“RuntimeLibrary”的不匹配项: 值“MDd_DynamicDebug”不匹配值“
  • (Forward) Music Player: From UI Proposal to Code
  • (Redis使用系列) Springboot 使用redis实现接口Api限流 十
  • (第一天)包装对象、作用域、创建对象
  • (附源码)apringboot计算机专业大学生就业指南 毕业设计061355
  • (十)【Jmeter】线程(Threads(Users))之jp@gc - Stepping Thread Group (deprecated)
  • (转)Groupon前传:从10个月的失败作品修改,1个月找到成功
  • (转)JVM内存分配 -Xms128m -Xmx512m -XX:PermSize=128m -XX:MaxPermSize=512m
  • (转载)hibernate缓存
  • (轉)JSON.stringify 语法实例讲解
  • ***利用Ms05002溢出找“肉鸡
  • .bat批处理(五):遍历指定目录下资源文件并更新
  • .Net Core/.Net6/.Net8 ,启动配置/Program.cs 配置
  • @RunWith注解作用
  • [【JSON2WEB】 13 基于REST2SQL 和 Amis 的 SQL 查询分析器
  • [20161214]如何确定dbid.txt
  • [Angular] 笔记 9:list/detail 页面以及@Output
  • [C#7] 1.Tuples(元组)
  • [C\C++]读入优化【技巧】
  • [C++] 多线程编程-thread::yield()-sleep_for()