指针笔试题讲解

笔试题一

#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

猜你喜欢

转载自blog.csdn.net/DR5200/article/details/113705406
今日推荐