【C语言】指针笔试题解析

上篇文章我们介绍了一系列字符数组和指针在sizeof和strlen函数中的不同应用,下面我们再来通过几道笔试题加深指针在数组中的应用吧。

笔试题1:

int main()
{
	int a[5] = { 1, 2, 3, 4, 5 };
	int* ptr = (int*)(&a + 1);//ptr指向的地址在a[4]的后面
	printf("%d,%d", *(a + 1), *(ptr - 1));
	//a+1 这里的a表示数组名,也就是数组的地址,也就是数组首元素的地址,再+1,指向a[1]
	//*(a+1) 值为2
	//ptr - 1 指向a[4]
	return 0;
}
答案:

2,5

解析:

指针ptr指向的地址是a[4]也就是数字5的后面的地址,而ptr-1,也就是ptr指向的地址向低地址移动一个int大小,这时指向了a[3]的地址

 笔试题2:

struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?(在x86环境下编译)
//已知,结构体Test类型的变量大小是20个字节
//0x开头的数字是16进制的数字
//
int main()
{
	p = (struct Test*)0x100000;
	printf("%p\n", p + 0x1);//跳过20Byte 0x100000 --> 0x100014
	printf("%p\n", (unsigned long)p + 0x1);//整型+1就是+1  0x100000 --> 0x100001
	printf("%p\n", (unsigned int*)p + 0x1);//跳过4Byte 0x100000 --> 0x100004
	return 0;
}
答案:

解析:

1.p指针为结构体指针,而结构体大小是20字节,那么p加1,也就是跳过20个字节,得到的地址用十六进制表示就是0x100014

2.而将p强制转换类型为unsigned long也就是无符号长整型,整型加1得到的地址就是0x100001

3.将p强制转换类型为unsigned int*,整形指针加1,加了4字节,得到的地址就是0x100004

 笔试题3:

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;
}

答案:

解析:

1.&a+1取到的是整个数组的地址,再向后移动一个数组的大小,因此ptr指向的是a[3]后面的地址,因此ptr[-1]指向的就是a[3]的地址

2.a本来是代表整个数组的地址也就是数组首元素的地址,而将它强制转换成int类型,再加+1,也就是地址加了1,假设a的地址是0x0012ff40,那么(int)a+1的地址就是0x0012ff41

因此ptr2指向的就是a的地址往后移动1字节,而为什么会得到这么大的十六进制数,则是由于VS编译器采用的是小端存储方式,不了解的可以去查一下大小端存储

 

 笔试题4:

int main()
{
	int a[3][2] = { (0, 1), (2, 3), (4, 5) };
	int* p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}
答案:

1

解析:

二维数组的初始化里面为逗号表达式,是从左到右依次计算,但是只取最后一个表达式的值,因此二维数组的值如下,而p[0]就等于a[0][0]

 

笔试题5:

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是一个一维数组指针,指向的一维数组应该只有四个元素,而这里让p指向二维数组a,在后续如果用p+1,则跳过4个int变量的大小,因此p[4][2]指向的地址如下图所示

而地址-地址,得到的就是数组的元素个数,也就是4,在这里是低地址-高地址,所以是-4

而-4在内存中是以补码的形式存在的,先转化为二进制为

10000000000000000000000000000100  //原码

11111111111111111111111111111100   //补码

转换为十六进制为FFFFFFFC

笔试题6:

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;
}
答案:

解析:

1.&aa+1取出二维数组的地址,然后往后走aa数组的大小的地址,指向的就是10的后面,再用强制类型转换为int*,最终指针ptr1-1是ptr往前走一个int大小,此时指向的就是aa[1][3]的地址

2.*(aa+1)指向的是第二个一维数组的地址,ptr2指向就是a[1]的地址

笔试题7:

int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%s\n", *pa);
	return 0;
}
答案:

解析:

char* a[]是指针数组,存放三个指针,分别指向一个字符串

pa是二级指针,指向指针数组的指针,也称数组指针

而pa++,也就是pa从指向数组a[]的首元素地址,跳转到第二个元素的地址,而第二个元素指向的字符串为"at",对二级指针解应用也就是a[1]地址,用%s输出字符串,打印出来的就是at

笔试题8:

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;
}
答案:

解析:

数组c是指针数组,有4个元素,分别指向一个字符串 - 一级指针

数组cp是指针数组,有4个元素,分别指向c数组元素的一个地址 - 二级指针

cpp是指针,指向数组cp的地址 - 三级指针

  •  **++cpp

 ++cpp指向的是cp[1]的地址,在对其二次解应用,也就是POINT\0的首地址

  •  *-- * ++cpp + 3

 --*++cpp指向的是c[1]的地址,解应用后也就是字符串的首地址,再+3指向的就是‘W’的地址

  •  *cpp[-2] + 3

 

  •  cpp[-1][-1] + 1

 

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值