文章目录
- 代码1
- 代码2
- 代码3
- 代码4
- 代码5
- 代码6
- 代码7
本篇内容接上一篇,对指针进行一个更深入的理解
建议没看过 上一篇的可以看看上一篇,当然不看也可以。
建议先自行完成再看答案哟
代码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+1)
中的a是首元素地址,a+1
之后则是第二个元素的地址,再进行解引用,那么得到的就是第二个元素。
而*(ptr - 1)
中,int* ptr = (int*)(&a + 1);
,这里的&a 取的是整个数组的地址,虽然地址也是首元素地址,但是+1后跳过的是一整个数组,指向数组之后的位置,然后对ptr-1
,那就回退一个空间,就指向了元素5的地址,再解引用得到的就是元素5啦。
如下图所示:
代码2
//在X86环境下
//假设结构体的⼤⼩是20个字节
//程序输出的结构是啥?
#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;
}
输出结果为:
解析:
这里已经知道结构体的大小是20个字节,这个结构体初始化了一个指针p,并且初始化指向了0x100000。
那么p+1
,即结构体指针+1,就要跳过一个结构体,由于这个是16进制的形式,所以1 * 16^1 + 4 * 16^0 = 20,所以结果为 0x100014。
(unsigned long)p + 0x1;
这里将p强制转换成了长整形,整形+1,就是+1。
(unsigned int*)p + 0x1;
将p强制转换成了int* 类型 ,所以+1 跳过4个字节。
代码3
#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;
}
输出结果为:
解析:
我们可能会有点懵, p = a[0]; 而a[0]是第一行的数组名,数组名表示首元素,所以这里的a[0] 就相当于 &a[0][0],那结果不就是0吗?
这是我们认为的:
事实上是这样的
这是因为:
二维数组的初始化应该用{}进行初始化,而不是圆括号(),否则就成了逗号表达式
代码4
//假设环境是x86环境,程序输出的结果是啥?
#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;
}
输出结果为:
解析:
p是一个数组指针,指向有4个整形元素的数组
p = a;
a是首元素地址,这是将a的地址给p,让他们指向同一块地址
在这里a的类型是 int ( * ) [5] , p的类型是 int ( * )[4]
p[4][2] = *( * (p+4) + 2)
我们已知两个指针相减就是两个指针之间的元素个数
所以如图所示:
首先这是数组a
他们之间的关系
所以%d的打印结果是-4
而%p的结果如下:
代码5
#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即跳过这个二维数组后,指向这个二维数组的后一个位置,所以打印结果时,*(ptr1 - 1)
-1后到达10的位置,解引用即元素10,所以结果为10.
而*(aa + 1)
,这就相当于aa[1],aa[1]是第二行的数组名,所以代表的是第二行的首元素地址,即&aa[1][0],所以指向的就是元素6的位置,打印时-1后指向的就是元素5的位置了
代码6
#include <stdio.h>
int main()
{
char* a[] = { "study","at","guangdong" };
char** pa = a;
pa++;
printf("%s\n", *pa);
return 0;
}
输出结果为:
解析:
首先我们要知道a是一个字符指针数组
char** pa = a;
这是将数组a的地址给二级指针pa
所以现在的情况如图所示:
接着pa++,那么就跳过一个字节
就变成了这样
所以打印结果就为 at
代码7
#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;
}
输出结果为:
解析:
不得不承认,一开始看到这题的时候觉得天塌了,但是其实画图理解还是很好解决的。
首先,做这题之前,我们先要明白:
++,- -会真正改变值,会真正改变cpp的指向,即影响到后面的指向位置。
但是cpp[-2] = *(cpp-2)
这样的不会使cpp发生真正改变,即在后面的语句中,cpp的指向会恢复到cpp[-2] = *(cpp-2)
执行前的cpp的指向。
这是他们之间的关系图:
第一条打印:
第二条打印:
第三条打印:
第四条打印:
以上就是相关例题,如有讲解错误还请指出。