作为萌新的小周末,指针的问题一直让我很头疼
特意找了几道关于指针的面试题,一起来做一下
第一题:
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)
我把他分解成 *和(a+1)两部分
(a+1)为数组加一,隐式转成了数组指针,在进行解引用操作,得到a[1]上的元素
即为2。
接着我们来看一下这个操作
int *ptr = (int *)(&a + 1);
首先是(&a+1):跳过一个数组,指向数组外边了(5右边的数)
再进行强制转换成 int星类型,并传到变量ptr中
*(ptr-1)即为指针的加减运算,向左移一个int整形即得到5
第二题
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
这里结构体的大小是20字节
初始时p=NULL;
p+0x1,即为空指针加1,跳过一个元素的字节 为20
将20用16进制位打印 位 0000 0014
看一下第二个
(unsigned long)p + 0x1
先把p强制转成 unsigner long ,变成一个long ,变成一个数字了,0+1即为1
//0000 0001
(unsigned int*)p + 0x1
把p强转成int*类型,此时p的大小位4个字节,
输出结果// 0000 0004
接着是第三题
int main()
{
int a[4] = { 1, 2, 3, 4 };
int *ptr1 = (int *)(&a + 1);
int *ptr2 = (int *)((int)a + 1);
printf( "%x,%x", ptr1[-1], *ptr2);
return 0;
}
int *ptr1 = (int *)(&a + 1);
和第一题有点类似,&a+1跳过整个数组,取到数组外面的地址,即4右边的那个数,再转成int星变量,传给指针变量ptr1。
ptr1[-1]等价于*(ptr-1),即为4
int *ptr2 = (int *)((int)a + 1);
a为数组的首元素地址,我们将他强制转成int型,变为一个数字,这里设为0x100
(int)a + 1=> 0x101 再将其转成int*类型传到变量prt2中
prt2=>0x101,0x102,0x103,0x104 四个字节// 00 00 00 02
这四个字节的内容
当我们对ptr2进行解引用,*ptr2,0x104被当成高位了,最终的打印结果2000000
这里我们稍微介绍一下字节序
大端字节序 0x 00 00 00 01
小端字节序 0x 01 00 00 00 地位放在低地址上
这里0x104为高位,以小端字节序存储,输出的就是02 00 00 00
接着第四题
#include <stdio.h>
int main(int argc, char * argv[])
{
int a[3][2] = { (0, 1), (2, 3), (4, 5) };
int *p;
p = a[0];
printf( "%d", p[0]);
}
很多人都认为数组的值是{0,1,2,3,4,5}
其实不是,这里有一个陷阱,有三个括号表达式,实际的数组是a[3][2]={1,3,5}
1 3
5 0
0 0
这样一个二维数组
p[0]相当于 (*a)[0]即为1