指针笔试题讲解

   日期:2021-02-06     浏览:86    评论:0    
核心提示:文章目录笔试题一笔试题二笔试题三笔试题四笔试题五笔试题六笔试题七笔试题八笔试题一#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; }// 程序的结果是什么?要想答对这道题,首先要知道 &数组名 和 数组名 的区别

文章目录

  • 笔试题一
  • 笔试题二
  • 笔试题三
  • 笔试题四
  • 笔试题五
  • 笔试题六
  • 笔试题七
  • 笔试题八

笔试题一

#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; 
}
// 程序的结果是什么?

要想答对这道题,首先要知道 &数组名数组名 的区别.

&数组名 : 这里的数组名表示整个数组,取出的是整个数组的地址,&数组名 + 1 跳过整个数组,&数组名为数组指针类型,在该题中即为 int (*)[5] 类型

数组名 : 数组名为首元素的地址,+ 1 跳过一个元素类型大小的字节,为 int *类型

虽然 &数组名 和 数组名 以 %p 的形式打印出来结果是一样的,但一定要注意它们之间的区别。


因此结果为 2,5

笔试题二

#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 = (struct Test*)0x100000;

	printf("%p\n", p + 0x1); // 0x100014
	printf("%p\n", (unsigned long)p + 0x1); // 0x100001
	printf("%p\n", (unsigned int*)p + 0x1); // 0x100004

	return 0;
}

这题考察的是 强制类型转换不同类型指针的区别.

不同类型指针的区别 :

1.加减整数所走的步长不一样.
2.解引用后访问的权限不一样.

第一个p是指向结构体的指针,加1跳过一个结构体,0x100000 + 20 = 0x100014
第二个p为无符号长整形,加1直接加1 0x100000 + 1 = 0x100001
第三个p是指向无符号整形的指针,加1跳过一个无符号整形,0x100000 + 4 = 0x100004

笔试题三

#include<stdio.h>
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;
}
// 输出结果是什么?

如果有读者对大小端的存储模式不清楚的话,可以去看一下这篇博客

数据在内存中的存储(整数)

笔试题四

#include <stdio.h>
int main()
{ 
	int a[3][2] = {  1, 3, 5 };
	int *p;
	p = a[0];
	printf("%d", p[0]);
	return 0;
}
// 输出结果是什么?

解决这道题,我们首先要理解二维数组.

对于 int[3][2],我们可以把它看作一个一维数组,一维数组里有三个元素,每个元素为一个数组(存放两个整形)

a[0],a[1],a[2] 分别是每一行的数组名,即每一行首元素的地址.

二维数组的数组名同样表示首元素的地址,首元素为a[0],即 &a[0],为数组指针类型.


结果为 1

笔试题五

#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 + 4) , 因为p为数组指针类型,+ 1 跳过 一个数组,解引用后得到首元素的地址,这里要理解 *(&数组名)数组名 是等价的

笔试题六

#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;
}
// 输出结果为多少?

该题和 第一题,第三题很相似,读者们可以放在一起加深理解
因此结果为 5,10

笔试题七

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

因此该题结果为 1

笔试题八

#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) 

1.++cpp后,cpp指向了cp[1] , 因为是前缀++ , 先++后使用 , 第一次解引用后得到cp[1]的内容,即c[2]的地址 .

2 第二次解引用后,拿到c[2]的内容 , 即字符串"POINT"的首地址,即 ‘p’ 的地址, 因此打印结果为 POINT

第一步进行完后,指向如下:
*-- *++cpp + 3 : 等价于 ( *( -- ( * (++cpp) ) ) ) + 3

1.++cpp后,cpp指向了cp[2] , 解引用后得到了cp[2]的内容,即c[1]的地址

2.前缀 - -后,cp[2]的内容被改成c[0]的地址

3.解引用后拿到c[0]的内容,即字符串"ENITR"的首元素地址,即字符 'E’的地址

4 . +3 后,得到第二个字符 'E’的地址,因此打印结果为 ER

第二步进行完后,指向如下:

 * cpp[-2]+3 : 等价于 *( *(cpp - 2) ) + 3

1 . cpp - 2指向了cp[0] , 解引用后得到cp[0]的内容,即c[3]的地址

2 .第二次解引用后得到c[3]的内容,即字符串" FIRST"首字符的地址,即字符 ’ F’的地址

3 .+3后,得到字符 'S '的地址,打印结果为 ST

第三步进行完后,指向如下:

注意喔 : cpp的指向可没有改变,一定要小心喔!!!

cpp[-1][-1]+1 : 等价于 *( *(cpp - 1) - 1) + 1

1 . cpp - 1指向cp[1] , 解引用得到cp[1]的内容,即c[2]的地址

2 .- 1 后得到c[1]的地址 ,解引用得到c[1]的内容,即字符 'N’的地址

3 . +1后得到字符 'E’的地址,打印结果为 EW

 
打赏
 本文转载自:网络 
所有权利归属于原作者,如文章来源标示错误或侵犯了您的权利请联系微信13520258486
更多>最近资讯中心
更多>最新资讯中心
0相关评论

推荐图文
推荐资讯中心
点击排行
最新信息
新手指南
采购商服务
供应商服务
交易安全
关注我们
手机网站:
新浪微博:
微信关注:

13520258486

周一至周五 9:00-18:00
(其他时间联系在线客服)

24小时在线客服