指针相关笔试题解析(详解)
在这之前让我们科普一关于指针加减整数的规则, 以免下面看起来懵逼
如果下面你怀疑了人生, 那一定上来看看这个
好了那我们就开始吧…这次一共有八个问题
// 问题 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个问题逐一解释
注意下面的自加运算会改变指针指向
我就不文字说明了
不说了, 上图
呼~ 终于结束了…
大家
都是
勇士
!!!
拜拜啦~