指针进阶(四)(跑路人笔记)

前言

本次对为面试题题量不大有一些难大家可以试试.
废话: 写的有点累就不写废话了.

笔试题

答案我都放在了代码块里在最底部.

第一题

int main() 
{
    
    
int a[5] = {
    
     1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf( "%d,%d", *(a + 1), *(ptr - 1));
return 0;
}
//程序的结果是什么?
//答 2 5

第一个答案a为首元素地址+1后解引用是第二个元素的地址
第二个答案中&a+1是跳过了整个数组所以ptr指向的是5后的地址又因为ptr是int*类型-1回跳了4个字节就指向了5

第二题

//由于还没学习结构体,这里告知结构体的大小是20个字节 
struct Test
{
    
    
	int Num; 
	char *pcName;
	short sDate; 
	char cha[2]; short sBa[4]; 
}*p; 
//假设p 的值为0x100000。 如下表表达式的值分别为多少? 
//已知,结构体Test类型的变量大小是20个字节
int main()
{
    
    
	printf("%p\n", p + 0x1); 
	printf("%p\n", (unsigned long)p + 0x1);
	printf("%p\n", (unsigned int*)p + 0x1);
	return 0; 
}
//答案: 0x100014 0x100001 0x100004

第一个答案: 结构题的大小为20个字节我们创建的结构题可以类似于关键字在指针是也奏效我们的结构体指针可以直接跳过20个字节通过16进制打印就是答案
第二个答案: 因为对p强制类型转换成了整数(泛意)所以加上16进制的1就和正常整数加1一样通过地址的形式打印出来就是答案
第三个答案: 与第二个类似我们的指针是根据类型进行跳跃的我们unsigned int*类型的指针一次跳动四个字节如答案所示.
小结: 本次题目主要考察陌生类型的代码我们的处理能力.

第三题

//%x是对十六进制的打印   %#x可以在打印时增加前缀0x
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

第一个答案: 与第一题的相似我们只需知道解引用操作符[X]可以理解为*(ptr+X)所以ptr[-1]相当于*(ptr1-1) 所以为4
第二个答案: 比较复杂涉及到我们使用编译器的大小端储存问题俺使用的是VS2019为小端储存我们以小端储存(不知道大小端的下面有连接)为例:
https://blog.csdn.net/qq_61434711/article/details/121798086?spm=1001.2014.3001.5501

  1. 我们将a强制类型转换成int那么我们的(int)a+1也就是以我们a的储存地址加上了一个字节后赋给了ptr2
  2. 这里我们用图片讲解:
    ![[Pasted image 20220108165432.png]]

小端存储将1按照16进制存储成01000000 当我们读取的时候就反过来00000001来使用而ptr2这个指针因为只跳动了一个字节所以他指向的内容变成了00000002当我们读取的时候翻过来就出现了答案20000000.

第四题

#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 所以相当于
int a[3][2] = {1,3,5};因为a是二维数组a[0]表示a第一行的元素首元素的地址所以p[0]其实就是a数组首行首列的元素1.

第五题

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

俩地址相减的值为他俩之间的元素个数(可为负)
第一问: p为数组指针它指向4个元素的数组可作为二维数组使用相当于一行有四列的二维数组我们为了描述清晰我还是画图吧:
![[Pasted image 20220108184556.png]]

我把这两个元素对应的位置都画在了图上这两个内存指向头部(如下图)
![[Pasted image 20220108184959.png]]

扫描二维码关注公众号,回复: 13656092 查看本文章

两者之间的元素又因为&p[4][2]为小地址小地址减去大地址为负数及-4
答案一 : 是以地址的形式打印-4 我们储存-4以补码储存: 11111111111111111111111111111100
再以地址形势打印: FFFFFFFC
正常整形形势 : -4

第六题

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

第一个答案: &aa得到的是整个数组的地址+1就是跳过了整个数组所以ptr1指向数组后第一个元素-1后就指向10.
第二个答案: 我们对二维数组解引用时为了精准到元素是要两次解引用的, 如果只一次解引用就会得到行数组的首元素地址+1就跳过一行所以第二个答案是5

对第二个答案的详解: 对于二维数组来说哪aa举例我们要使用它时格式为aa[1][2] = 8其实aa[1][2]*(*(aa+1)+2) 而我们ptr2中*(aa+1)就是跳过了一行所以我们的ptr2就指向了第二行的首元素及指向6所以第二个答案为5.

第七题

#include <stdio.h>
int main() 
{
    
    
	char *a[] = {
    
    "work","at","alibaba"};//指针数组
	char**pa = a;
	pa++;
	printf("%s\n", *pa); 
	return 0;
}
//答案: at

解析: a作为指针数组每个元素都指向一个字符串二级指针pa指向a的首元素pa++后指向第二个元素及at.

第八题

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;
}
	//答案: POINT ER ST EW

这道题比较难大家要耐心看解析
解析
第一个答案: ++cpp指向c+2 为"POINT"(cpp值已经发生了改变)
第二个答案: 优先级和指针的重复考察首先优先级 : ++ * 和 – 为一个等级 +3是等级最低我们结合性是从左到右首先++ 我们的cpp就指向了cp数组中的c+1然后解引用就为c+1后–;c+1就成了c(注cp数组里的c+1就变成了c了)就指向首元素地址了然后再解引用为c首元素地址ENTER再+3 就指向ENTER中的E用字符串形势打印就成了ER.
第三个答案: 中cpp已经指向了cp中的第三个元素(现在是c而不是c+1),所以cpp[-2]就是cp中的首元素c+3 再次解引用后就是FIRST 再+3后指向了S打印后就是ST
(cpp[-2]等价与*(cpp-2)现在的cpp没有改变).
第四个答案: cpp[-1][-1]相当于*(*(cpp-1)-1) 原本cpp指向cp中的第三个元素-1后解引用就是第二个c+2再-1 后解引用就是c+1的元素指向NEW的指针最后再+1就是指向E用字符串打印后就是EW.

猜你喜欢

转载自blog.csdn.net/qq_61434711/article/details/122386464