指针运算笔试题解析(1)

题目一

#include<stdio.h>
int main()
{
	int a[5]={1,2,3,4,5};
	int *p=(int*)(&a+1);
	printf("%d %d",*(a+1),*(p-1));
	return 0;
} 

答案:2 5

解析

int a[5]={1,2,3,4,5};

先定义一个arr[5]整型数组,将1,2,3,4,5放置arr[5]中。

int *p=(int*)(&a+1);

取arr数组的地址再加1,使得p指向arr整个数组之后的第一个地址,再强制类型转化为int*类型,使得p的指向就是arr[4]即5之后的第一个地址。

printf("%d %d",*(a+1),*(p-1));

*(a+1)指的是arr首元素地址+1,相当于arr[1],所以*(a+1) == 2
*(p-1)指的是5之后的第一个地址-1,相当于又变为了5,所以*(p-1) = 5

题目二

//x86环境下,结构体的大小为20
#include<stdio.h>
struct Test
{
	int num;
	char* pch;
	short data;
	char cha[2]; 
	short arr[4];
}*p=(struct Test*)0x100000;

int main()
{
	printf("0x%x\n",p+0x1);
	printf("0x%x\n",(unsigned long)p+0x1);
	printf("0x%x\n",(unsigned int*)p+0x1);
	return 0;
}

答案:

0x100014
0x100001
0x100004

解析

printf("0x%x\n",p+0x1);

这里的pstruct Test*类型指向的是struct Test类型,所以p+1的时候就跳过了一整个结构体,所以p的地址要加20,而地址的存储是以16进制打印的,所以答案就是0x100014

printf("0x%x\n",(unsigned long)p+0x1);

这里的p被强制类型转化为了unsigned long,所以p就变成了一个长整型的整数,故(unsigned long)p+1就是0x100001

printf("0x%x\n",(unsigned int*)p+0x1);

同理,p被强制类型转化为了unsigned int*他指向的是unsigned int类型,p+1的时候就跳过了一整个结构体,所以p的地址要加4,所以答案就是0x100004

题目三

//x86环境下
//编译器为小端存储
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 2000000

解析

int a[4]={1,2,3,4};

先定义一个arr[5]整型数组,将1,2,3,4放置arr[4]中。

int* ptr1=(int*)(&a+1);

与第一题考法一样,取arr数组的地址再加1,使得p指向arr整个数组之后的第一个地址,再强制类型转化为int*类型,使得p的指向就是arr[3]即4之后的第一个地址。

	int* ptr2=(int*)((int)a+1);

这个比较复杂,需要根据编译器中内存存储的大小端来判断
(大小端不理解可参考数据在内存中的存储
在这里以VS2022的x86环境为例。
我们先假设数组a的地址为0x00EFF904,a先被(int)强制类型转换为了整型,此时a+1就是地址的整型数字加一,之后a+1又被(int*)强制类型转换为了指针类型,所以ptr2所指向的地址就是0x00EFF905,我们再回到编译器中,如图:
在这里插入图片描述

小端编译器中1的储存为01 00 00 00,翻译过来就是00 00 00 01
所以,我们可以推出存储为00 00 00 02*ptr2,所以*ptr2 == 02 00 00 00,注意:这里的*ptr2是以16进制所表示的。
在这里插入图片描述

	printf("%x  %x",ptr1[-1],*ptr2);

综上,ptr1[-1] == arr[3] == 4,*ptr2 == 2000000

题目四

#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)在数组中只表示1,所以这里的arr就表示为{ {1,3},{5,0},{0,0} },而p指向arr[0] == {1,3}的地址,所以p[0]就表示1

题目五

//假设环境是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;
}

答案:FFFFFFFC -4

解析

int(*p)[4];我们可以知道p是一个指针指向4个整型元素,又因为int a[5][5];所以我们可以推出下图,而指针与指针的相减就是两指针之间的元素个数,所以我们可以得到:&p[4][2] - &a[4][2] == -4
在这里插入图片描述
不过需要注意的是用%p表示-4的时候要转化为相应的16进制表达式,推到过程如下:

-4
原码:10000000 00000000 00000000 00000100
反码:11111111 11111111 11111111 11111011
补码:11111111 11111111 11111111 11111100
16进制:FF FF FF FC

所以答案为FFFFFFFC -4

请添加图片描述

以上就是本期的全部内容了,喜欢请多多关照吧!!!

  • 29
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 15
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 15
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

蒋志昂

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值