目录
1.第一题
//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;
}
输出结果为2,5
分析:(&a+1)表示为取整个数组a的地址,因此加一指的是加上&a整个数组的字节数(可以理解为加int [5]类型的字节数)。prt指针指向的地址为a[5]的后4字节地址。
(a+1)表示为取a数组的首地址,加一指的是加上int类型的字节数,得到a[1]的地址。*(a+1)就是对a[1]的地址解引用,得到a[1]的值为2。
(prt-1)表示为prt指针指向的地址减去int类型的字节数,得到a[4]的地址。*(prt-1)就是对a[4]的地址解引用,得到a[4]中的值为5。
(注意,地址后面加1或者其他数值,其字节数与地址的类型有关,地址是int型就是加int类型的字节数乘上对应数值)
2.第二题
//2.
#include<stdio.h>
struct Test
{
int Num;//4字节
char* pcName;//4字节
short sDate;//2字节
char cha[2];//2字节
short sBa[4];//8字节
}*p;
int main()
{
p = (struct Test*)0x100000;
printf("%p\n", p + 0x1);
printf("%p\n", (unsigned long)p + 0x1);
printf("%p\n", (unsigned int*)p + 0x1);
return 0;
}
输出结果为:
0000000000100020
0000000000100001
0000000000100004
分析:
(1). p+0x1表示指针p指向的地址加上1个struct Test类型(p的类型)的字节数,struct Test结构体的字节为20(4+4+2+2+8)。
(2). (unsigned long)p 表示为将指针p强制转化为unsigned long类型变量,(unsigned long)p + 0x1就是在unsigned long类型p变量后加1。
(3). (unsigned int*)p 表示为将指针p强制转化为unsigned int类型的指针,(unsigned int*)p + 0x1就是在unsigned int类型的指针p指向的地址,加上1个unsigned int类型的字节数(4字节)。
3.第三题
//3.
#include<stdio.h>
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;
}
输出结果为4,20000000
分析:
(1)&a的意思为取a整个数组的地址,&a+1就是对a这个数组的地址加上1个int [4]类型的字节数(4*4=16),得到a[4]后四个字节的地址。(int*)(&a+1)就是将a[4]后四个字节的地址强制类型转化为int*,也就是prt1指针指向的地址。prt1[-1]就是prt1指针指向的地址减去1个int类型的字节数,得到a[3]的地址。
(2)(int)a的意思是将a数组的首地址强制转化为int型,此时的(int)a是int型数值不是地址。(int)a+1就是取出a数值首地址数,将其转为int型数值,加上1。(int*)((int)a+1)就是将加上1的数组a首地址数强制转化为int*型,也就是prt2指针指向的地址。*prt2就是对指针prt解引用,从地址开始处取出4个字节也就是下图中的00 00 00 02,由于存储方式为小端存储,得到数就是0200000。
4.第四题
#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;
}
输出结果为:1
分析:(0,1)、 (2,3)、(4,5) 这三个式子都是逗号表达式,逗号表达式的结果为最后一位。因此,只会把1,3,5传进数组a中。a[0]的意思是取数组a[0]的首地址(a[0][0]的地址),所以p存进的是a[0][0]的地址。p[0]在编译时执行的其实是*(p+0),*(p+0)就是*p,就是对指针p解引用,得到a[0][0]中的值。
如有不当之处,请指正