今天给大家分享几道关于指针的好题,我觉得的只要是题,都是好题咯!下面来看看我们今天的题吧!
题目一:
#define _CRT_SECURE_NO_WARNINGS 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里面有5个元素,下面定义了一个整形指针变量指向了(int*)(&a+1),那么我们现在主要就是找到指针变量ptr所指向的位置:
如图所示,就是我们ptr所指向的位置,下面对其*(a + 1),那么此时就指向2的地址了,再对其简引用,那么就是我们的2了。 *(ptr - 1)指针ptr-1就指向了我们5的地址了。所以我们的最终结果为2,5!
题目二:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
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;
}
在X86环境下,假设结构体的⼤⼩是20个字节,程序输出的结构是啥?
p是我们的结构体指针,p+0x1这里就是我们的结构体指针加一了,那么此时加的就是一个结构体的大小,上面告诉我们了为20个字节,那么p+0x1 = 0x100000+20 = 0x100014(这里是十六进制)!
第二个被强制转换为无符号长整形了,那么此时就是就是整数的加减运算了,p+0x1 = 0x10000+1=0x100001!
第三个被强制转换为一个整型指针类型了,此时在X86的环境下,指针的大小为4个字节,那么p+0x1 = 0x100004!
我们来看看结果:
题目三:
#define _CRT_SECURE_NO_WARNINGS 1
#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;
}
可能大家在看见这道题是,想当然的就知道了数组的排列,
如果真的这样想的话,其实就错了,注意里面是()而不是{},那么我们就要先进行里面的”,“运算了,所以我们的数组a其实是这样的!
定义了一个整型指针类型指向我们的a[0],a[0]表示的是第一行的地址,此时就表示首元素的地址,那么p[0]就指向我们的1,所以结果为1!
题目四:
#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;
}
假设环境是x86环境,程序输出的结果是啥?
有一个数组a有25个元素(5行5列),下面定义了一个数组指针,里面有四个元素,然后p = a!把a的首元素地址给了p!因为二维数组在我们的内存中也是连续存放的,所以我们可以这样画:
那么此时我们就可以很好的找到位置进行计算了,
我们知道随着数组下标的增长,地址由低地址指向高地址,所以&p[4][2] - &a[4][2]是一个低地址减一个高地址,地址减地址的绝对值表示之间的元素个数,所以以%d打印时,结果是我们的-4!以%p打印时,以-4作为一个地址来打印,在内存中我们的数是以补码存储的,所以我们打印地址时就是打印-4的补码:
所以我们的结果为FFFFFFFC和-4!
题目五:
#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是取出的整个二维数组的地址,加一之后就指向了二维数组的后面了,而(aa+1),aa表示首元素的地址,而在二维数组中则表示第一行的地址,加一之后就指向了第二行元素:
所以ptr-1后指向了10的地址,ptr2-1后则指向了5的地址,所以我们的结果为:10,5
题目六:
#include <stdio.h>
int main()
{char *a[] = {"work","at","alibaba"};char**pa = a;pa++;printf("%s\n", *pa);return 0;
}
a是一个指针数组,里面存放的是char*类型的元素,下面是char** pa = a;表示将a的首元素地址传给了pa,pa指向的对象类型是char*的,我们可画图来作答:
pa++后指向了a[1],对其简引用之后那么就是打印我们的字符串at了!
题目七:
#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;
}
C是一个指针数组,数组C里面的元素为char*类型,数组CP里面存放的是char**类型,将C的首元素地址传到CP中,CPP中的元素为char***。我们画图来理解:
printf("%s\n", **++cpp); 加加cpp,那么之后就跳到了c+2,对其简引用后就指向了我们的c[2],再对其简引用之后便指向了我们的POINT的首地址,那么此时打印的就是我们的 POINT!
printf("%s\n", *--*++cpp+3); +3的优先级是最低的,所以我们最后算。上面我们的cpp跳到了我们的c+2,然后这里再加加之后就指向了c+1这个位置了,然后再对其简引用,此时就指向了我们的a[1],然后再减减,此时就变为了我们的a[0]了,此时再对其简引用就指向了我们ENTER的首地址,再加三后,指向了我们的E,所以这里我们就打印我们的 ER!
printf("%s\n", *cpp[-2]+3); cpp[-2]=*(cpp-2),所以此时指向了我们的c+3,对其简引用之后指向了我们的c[3],然后再对其简引用之后就指向了我们FIRST的首元素,之后再加三后就指向了S,所以我们这里打印的是 ST!
printf("%s\n", cpp[-1][-1]+1);cpp[-1][-1] = *(*(cpp-1)-1),cpp-1后指向了c+2了,然后再对其简引用后便指向了我们的c[2]了,之后再减一就就跳到我们的c[1]了,然后再对其简引用之后便指向了NEW的首地址,然后加一指向了E,所以最后打印的是我们的EW!
所以所做这类似的题时:画图对我们的帮助是非常大的,一定要多画图来看看!不知道你看完之后有没有些感触,哈哈,如果有的话,点个赞吧!
拜拜咯,我们下期再见!