int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
system("pause");
return 0;
}
首先我们看到,a是一个存放五个整形元素的数组,&a这个操作得到的是一个指向整个数组a的数组指针,它+1后跨越了整个数组,来到了5的后面,此时这个指针类型是int(*)[5],每走一步跨越20个字节,紧接着将它强制类型转换成int*指针依然指向的是5后面的那块空间,但步长缩短为一个整形(四个字节),将这个地址赋给同为int*的ptr;ptr-1向后来到了存放5的空间,解引用后拿到了5;a+1则是数组首元素地址+1来到了第二个元素的地址,解引用后拿到2;
所以这道题的运行结果是:
2 5
struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
int main()
{
p = (struct Test*)0x100000;
printf("%x\n", p + 0x1);//0x100014
printf("%x\n", (unsigned long)p + 0x1);//0x100001
printf("%x\n", (unsigned int*)p + 0x1);//0x100004
system("pause");
return 0;
}
首先我们需要求出一个Struct Test类型变量所占空间大小:int(4)+char*(4)+short(2)+char(1)*2+short(2)*4 = 20byte;
第一个输出语句:0x1换算成十进制就是1,因为p指向的元素大小是20个字节,所以+1后地址就加了20个字节,变成了0x100014;
第二个输出语句:将p强制类型转化为一个无符号长整形,此时p只是单纯的一个数组,加1那就是真+1了,所以结果是0x100001;
第三个输出语句:将p强制类型转换成无符号整形指针类型,这时加+1就是给地址加4个字节,所以输出就是0x100004
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);
system("pause");
return 0;
}
这里的a依然是一个存放了4个整形元素的数组,和第一题的操作一样,ptr1是一个步长为四个字节,存放a数组后面那块空间的地址,ptr[-1]就等价于*(ptr-1),拿到了4,而ptr2的操作是将a首元素地址强制类型转换为整形,再+1(整数运算哦,不是地址),再强制类型转换为int*(这意味着较a的首元素地址向后移动了1个字节)附给ptr2,这里解引用时就可要小心了:
因为笔者的电脑是小端存储,数据的低位储存在内存空间的低地址位,高位存储再内存空间的高地址位
从图上我们就可以看到*ptr2的值应该是0x2000000;
所以最终的输出结果为:
4 2000000
#include
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
system("pause");
return 0;
}
不知道你注意了到没有,a[3][2]里好像有点不对劲,初始化应该是{{0,1},{2,3},{4,5}}啊,对,这个(0,1)其实是逗号表达式,只输出最后一个逗号后面的结果,所以,正确的画风应该是这样的{1,3,5},
又因为在二维数组中a[0]是一个数组名,所以给p赋的是第零行首元素的地址,所以最终结果是1;
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]);
system("pause");
return 0;
}
这里我们看到a是一个5行5列的二维数组,p是一个指向存放4个整形字节的数组指针,所以p = a,就是将a的第0行地址付给了p,虽然存放的地址相同,但p与a[0]数组指针的步长并不相等,所以,我们在计算&p[4][2]-&a[4][2]时先将他们化成如下形式
&(*(*(p+4)+2) )-&(*(*(a+4)+2))
这表明是p数组指针先加4再访问第五组中的第2个元素,所以共跨越了*4+2=18个整形元素,a数组指针也是先加4再访问第5组的第二个元素,因为a数组指针的类型是int*[5],所以共跨越了4*5+2=22个整形元素,因为a和p都是从同一地址出发,所以p的最终地址和a的最终地址是连续的,相减得到的是有正负的元素个数,是-4;而-4作为地址输出的是无符号十六进制位-4在内存中存放的是补码:
11111111 11111111 11111111 11111100
转化成无符号十六进制就是0xFFFFFFFC
所以最终输出的结果是:
0xFFFFFFFC -4
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));
system("pause");
return 0;
}
首先&aa拿到的是整个二维数组的地址,+1后直接来到数组之后的那块空间,在强制类型转化成步长为4字节的整形数组赋给ptr1,-1
后就向前移动一个整形(4byte)指向了10的地址,解引用后拿到数字10;
接下来,aa+1代表的是二维数组首元素(整个a[0]行)+1,来到a[1]
行,此时解引用正相当于拿到了a[1]行首元素的地址赋给了ptr2,-1后来到了5的位置,解引用后得到5;
所以输出结果为:
10 5
int main()
{
char *a[] = {"work","at","alibaba"};
char**pa = a;
pa++;
printf("%s\n", *pa);
system("pause");
return 0;
}
首先a是一个字符指针数组,里面分别存放了指向"work"首字符的指针,指向"at"首字符的指针,指向"alibaba"首字符的指针;char**pa = a则是将a数组的首元素地址(存放了指向“work”首字符的指针)传给了pa,pa++后来到了a的第二个元素,也就是存放指向"at"首字符的指针的空间,进行一次解引用后拿到了这个指针,%s直接输出这个指针指针指向的字符串;所以最终结果是:
at
#include
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);
//POINT ER ST EW-4
system("pause");
return 0;
}
要想顺利的做对这道题,我们需要先画图,看清楚在内存空间上c,cp,cpp有怎样的联系:
在对c,cp,cpp进行初始化,根据上面的题目,我们不难画出这样的图。
第一句printf语句中cpp第一次++后指向cp1的位置,解引用后,拿到了c2的位置,再次解引用后得到了POINT的首字符地址,输出POINT;
第二句printf语句中cpp第二次++后指向cp2的位置,解引用后拿到c1的位置,–后(红线)指向了c0的位置,解引用后拿到ENTER首字符地址+3后指向E输出ER;
第三句printf语句中cpp[-2]等价于*(cpp-2)拿到cp0储存的c3地址,解引用拿到FRISR首字符地址+3后指向S,输出ST;
第四句printf语句中cpp[-1]等价于*(cpp-1)拿到cp1储存的c2地址,
c2[-1]拿到c1中储存的NEW首字符地址,+1指向E输出EW;
所以最后输出结果为:
POINT
ER
ST
EW