指针相关笔试题(附解析)—-史上最强C语言教程

目录

10. 指针相关的笔试题及解析

10.1 笔试题1

10.2 笔试题2

10.3 笔试题3

10.4 笔试题4

10.5 笔试题5

10.6 笔试题6 

10.7 笔试题7

10.8 笔试题8


10. 指针相关的笔试题及解析

10.1 笔试题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是数组首元素的地址,类型为int *,数组首元素的地址+1,跳过一个整型元素,即数组第二个元素的地址,对其进行解引用就是a[1],所以输出结果为2。

&a是数组的地址,数组地址+1就是跳过一个数组大小的地址,此时类型为int (*)[5],对其进行强制类型转换后,类型变为了(int*),-1就回退一个整型元素的大小,此时指针指向的元素是5。

画图解析:

10.2 笔试题2

代码:

程序的结果是什么?
#include<stdio.h>
struct Test
{
	int Num;
	char* pcName;
	short sDate;
	char cha[2];
	short sBa[4];
}*p;
//假设p 的值为0x100000。 如下表表达式的值分别为多少?
//已知,结构体Test类型的变量大小是20个字节
int main()
{
	p = 0x100000;
	printf("%pn", p + 0x1);
	printf("%pn", (unsigned long)p + 0x1);
	printf("%pn", (unsigned int*)p + 0x1);
	return 0;
}

运行截图:

代码解析:

p的类型为(struct Test*),所以+1后跳过12个字节,在进行(unsigned long)强制类型转换后,+1后跳过1个字节,在进行(unsigned int*)强制类型转换后,加1跳过一个整型的大小,即4个字节。

10.3 笔试题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;
}

运行截图:

画图解析:

代码解析:

&a得到的是数组a的地址,+1即跳过一个数组的大小,对其进行强制类型转换后类型变成了int*,ptr[-1]=ptr+(-1),因为此时的类型是int*,所以回退的是一个整型的空间,因为其类型是int*,一次能够访问4个字节,所以对其进行输出后的结果是4。

对a进行强制类型转换后a的类型就变成了int,+1就是简单的加1,跳过一个字节,跳过一个字节在上图中体现的就是跳过两位数组,此时指向了00,因为其类型是int*,一次能够访问4个字节,所以取出的数组就是00 00 00 02,因为其是小端存储,并且是按照16进制形式进行打印,所以打印结果是20 00 00 00。

10.4 笔试题4

代码:

#include<stdio.h>
#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;
}

运行截图:

代码解析:

此处有一个需要注意的点,就是{}中的()中的代码是逗号表达式,即代码等价于int a[3][2] = {1,3,5},即最终数组初始化的结果就像下方画的图一样!

a[0]是第一行的数组名,而此处的数组名代表的是第一行第一个元素的地址 ,即a的地址,p[0]代表的是*(p+0),p+0之后并未发生改变,仍然是第一行第一个元素的地址,且此时的类型也是int*,对其进行解引用之后就是数组第一行第一个元素,即1。

注意:

1、()中的内容是逗号表达式!

2、p[0] = *(p+0)。

10.5 笔试题5

代码:

int main()
{
	int a[5][5];
	int(*p)[4];
	p = a;
	printf("%p,%dn", &p[4][2] - &a[4][2], &p[4][2] - &a[4][2]);
	return 0;
}

运行截图:

代码解析:

10.6 笔试题6 

代码:

#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+1就是跳过一个二维数组,指向10的后面,此时的类型是int (*)[2][5],强制类型转换后类型变成int*。此时使ptr1-1就是回退一个整型元素,指向元素10,解引用之后得到元素10。

aa是二维数组的数组名,数组名是数组首元素的地址,即第一行的地址,aa+1跳过一行,此时是数组第二行的地址,对其进行解引用之后就是第二行的数组名,再进行请值类型转换后类型变成了int *(当然,此处就算不进行强制类型转换类型也是int*,因为第二行数组名是一维数组,数组名代表首元素的地址,其类型自然就是int*)。此时使ptr2-1就是回退一个元素,指向元素5,解引用之后得到元素5。

10.7 笔试题7

代码:

#include <stdio.h>
int main()
{
	char* a[] = { "work","at","alibaba" };
	char** pa = a;
	pa++;
	printf("%sn", *pa);
	return 0;
}

运行截图:

代码分析:

如何理解char *a = { "work","at","alibaba" };这行代码呢?

其实这行代码等价于下面的这三行代码:

a[0] = "work";

a[1] = "at";

a[2] = "alibaba";

其中a[0]、a[1]、a[2]的类型都是字符指针类型,都是存储的后面字符串常量的首地址。

a代表的是数组首元素的地址,即a[0]的地址,pa的类型是char**,即二级指针,+1后跳过一个char *类型,即pa++后pa指向的是a[1],即存储的是a[1]的地址,对其进行解引用之后得到的就是字符串常量中"at"中a的地址。

10.8 笔试题8

代码:

#include<stdio.h>
int main()
{
	char* c[] = { "ENTER","NEW","POINT","FIRST" };
	char** cp[] = { c + 3,c + 2,c + 1,c };
	char*** cpp = cp;
	printf("%sn", **++cpp);
	printf("%sn", *-- * ++cpp + 3);
	printf("%sn", *cpp[-2] + 3);
	printf("%sn", cpp[-1][-1] + 1);
	return 0;
}

运行截图:

 

代码分析:

 对于**++cpp,这个表达式来说,*和++优先级相同,但是结合性是自右向左,所以先进行++操作,++后cpp指向cp[1],即图中的c+2,对其进行一次解引用之后可以得到cp[1]中存放的地址,二次解引用之后可以得到c[2]中存放的即"POINT"首元素即P的地址,所以打印结果应该是POINT。

对于*--*++cpp+3这个表达式来说,,首先是cpp自增1,cpp指向了图中的c+1(前一个表达式中已经自增过一次了),此时进行解引用之后得到了c+1,然后进行自减,此时就变成了c,然后再对其进行解引用之后得到了"ENTER"中字符E的地址 ,此时再进行加3,然后得到的就是E的地址,所以输出结果为ER。

对于*cpp[-2]+3这个表达式来说,这个表达式等价于**(cpp-2)+3,首先是cpp-2,因为之前cpp指向的是图中的c+1,-2之后指向的是c+3,对其进行解引用之后得到的是c[3]的地址,然后进行解引用之后就得到了FIRST的地址,然后对其进行+3,就得到了S的地址,所以打印结果为ST。

对于cpp[-1][-1]+1这个表达式来说,这个表达式等价于*(*(cpp-1)-1)+1,首先cpp-1,从指向c+1这个位置指向 了c+2这个位置,解引用得到的就是c+2,然后进行-1,变成了了c+1,然后解引用之后得到了c[1]的内容,其实是N的地址,N的地址+1得到的就是E的地址,所以输出的结果是EW。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
THE END
分享
二维码
< <上一篇
下一篇>>