C语言 之 理解指针(9)与指针相关的理解题


本篇内容接上一篇,对指针进行一个更深入的理解
建议没看过 上一篇的可以看看上一篇,当然不看也可以。
建议先自行完成再看答案哟

代码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的指向。
这是他们之间的关系图:
在这里插入图片描述
第一条打印:
在这里插入图片描述
第二条打印:
在这里插入图片描述
第三条打印:
在这里插入图片描述
第四条打印:
在这里插入图片描述


以上就是相关例题,如有讲解错误还请指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值