指针相关笔试题解析(详解)

在这之前让我们科普一关于指针加减整数的规则, 以免下面看起来懵逼

如果下面你怀疑了人生, 那一定上来看看这个

在这里插入图片描述

好了那我们就开始吧…这次一共有八个问题

// 问题 1
 int a[5] = { 1, 2, 3, 4, 5 };
 // ptr 的指向应该是 5 后面的一个元素. 
 // &a 得到的是 int(*)[5]
 int* ptr = (int*)(&a + 1);
 // 2 5
 printf("%d,%d", *(a + 1), *(ptr - 1));  // ptr 已经在上面被强转成 int* 了

在这里插入图片描述

//问题 2
 struct Test* p = (struct Test*)0x100000;
 // 100020  这是错误的  
 printf("%p\n", p + 0x1);
 // 下面的强制类型转换, 导致 p 就变成了一个 unsigned long, 再去 + 1 , 就只是单纯的整数 + 1
 printf("%p\n", (unsigned long)p + 0x1);
 printf("%p\n", (unsigned int*)p + 0x1);

这里先不叙述结构体变量的字节数怎么计算
但是我们这里要用…直接printf 一下…得到 20

%p 是 打印地址 的格式化字符串 (地址一般都是十六进制表示 )
那我们知道 指针 + 1 就是跳过一个元素
这里+1 就是跳过整个结构体 也就是 20 字节
那结果是0x100020吗
那当然不是 这里十六进制表示 所以结果是 100014

然后是第二个printf 这里直接强转成一个 unsigned long 类型
这就是一个整数 + 1 就是 + 1 嘛…
结果是100001

最后是第三个printf 这里强转成一个 int* 类型
int* +1 跳过一个 int 类型 也就是4字节
所以结果是100004

// 问题3
 int a[4] = { 1, 2, 3, 4 };
 int *ptr1 = (int *)(&a + 1);
 int *ptr2 = (int *)((int)a + 1);
 printf("%x,%x", ptr1[-1], *ptr2);

在这里插入图片描述
在这里插入图片描述
这里第一个printf相信大家都没什么问题了吧, 要是有问题去看上面

不过这里值得一说的是指针运算
ptr1[-1] => *(ptr1 - 1) 这两者是等价的
所以第一个结果是4

扫描二维码关注公众号,回复: 10064529 查看本文章

第二个printf 比较复杂 直接上图吧

// 问题4
  //长度为 3 个元素的一维数组, 每个元素长度为 2  => 1
  //长度为 2 个元素的一维数组, 每个元素长度为 3  => 2
 //int a[3][2] = { {0, 1}, {2, 3}, {4, 5} };
 //上面这才是数组的写法

 int a[3][2] = { (0, 1), (2, 3), (4, 5) };
 int *p;
 // a[0] 取到了一个长度为 2 个元素的一维数组
 // p 是当前这个数组的首元素地址
 p = a[0];
 printf("%d", p[0]);

首先注意这里的数组写法, 里面用的是小括号 ( )
众所周知这是 逗号表达式 ( a, b, c,…,z) 结果取最后的值 z
所以这个数组的样子应该是这样的
a[3][2] = { {1, 3 } , { 5 , 0 } , { 0 , 0 } }
数组a 是一个有长度为3的一位数组 , 每个一位数组有2个元素

指针 p = a[0] 也就是指向了 { 1 , 3 }
在计算 p [0]
也就相当于 a[0][0] 结果为1

// 问题5
 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]);

在这里插入图片描述

接下来吧细节放大

在这里插入图片描述

//问题6
 int aa[2][5] = { 
  {1, 2, 3, 4, 5},
  {6, 7, 8, 9, 10 } 
 };
 // &aa 应该是一个数组指针 int(*)[2][5], 再 + 1 应该要跳过整个数组
 int *ptr1 = (int *)(&aa + 1);
 // aa 是二维数组名 再 + 1, 隐式转成 int(*)[5]
 // int *ptr2 = (int *)(*(aa + 1));
 int *ptr2 = (int *)(aa[1]);
 // 10   5
 printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));

相信大家看上面的注释已经能理解啦~~

// 问题 7
  //指针数组
 char *a[] = { "work","at","alibaba" };
 char**pa = a;
 pa++;
 printf("%s\n", *pa);

在这里插入图片描述

接下来就是最后一个压轴的了 ! ! !

来吧勇士

// 问题 8
 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);
 
 // cpp[-2] => *(cpp-2) 这个操作没有修改 cpp 的内容. 而上面的 ++ 操作修改 cpp 
 printf("%s\n", *cpp[-2] + 3);
 printf("%s\n", cpp[-1][-1] + 1);

这****** 的 …我都想***了
hhhh 言归正传

遇到这种的那势必是要先画出内存的示意图了

如果画出图…那这题他就完成了一大半了

话不多说, 直接上图

在这里插入图片描述
这大致就是这道题目中的内存示意图了

注意char*** cpp 中的初始值应该是 0x2000
因为中间有自加运算就直接改掉了

下面对4个问题逐一解释
注意下面的自加运算会改变指针指向
我就不文字说明了

不说了, 上图

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

呼~ 终于结束了…
大家
都是
勇士
!!!

拜拜啦~

发布了47 篇原创文章 · 获赞 4 · 访问量 484

猜你喜欢

转载自blog.csdn.net/weixin_45818891/article/details/104789184