欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2022-05-12 16:14:32
...

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

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

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

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

// 问题 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

第二个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个问题逐一解释
注意下面的自加运算会改变指针指向
我就不文字说明了

不说了, 上图

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

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

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

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

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

拜拜啦~

相关标签: C 语言学习