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


    大家好,我是苏貝,本篇博客带大家了解指针和数组笔试题解析,如果你觉得我写的还不错的话,可以给我一个赞👍吗,感谢❤️
    在这里插入图片描述


    1.

    下面程序的结果是什么?

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    结果:2,5
    &a表示取出整个数组a的地址,再+1表示跳过该数组,取出后面同类型的地址,即5个int型的地址即橙色区域,对&a+1进行强制类型转化后赋值给ptr,所以ptr指向的是数组后面的第一个地址。ptr-1表示数组a的最后一个元素的地址,对地址进行解引用找到最后一个元素5。a是首元素地址,a+1表示第二个元素的地址,对地址进行解引用找到第二个元素2
    在这里插入图片描述

    2.

    //这里告知结构体的大小是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);//1
    	printf("%p\n", (unsigned long)p + 0x1);//2
    	printf("%p\n", (unsigned int*)p + 0x1);//3
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    结果:0x100014 ;0x100001;0x100004
    1.0x是16进制的前缀,所以0x1也就是1,可知p是结构体指针,p+1即结构体指针+1表示跳过一个结构体的大小,所以p的地址要加20=0x14,所以结果为0x100014 ;
    2.p原本存储的是地址,但按题目要将p进行强制类型转化成unsigned long类型,即此时p里面存储的不再是地址而是数字0x100000,再+1得0x100001,再将数字0x100001作为地址打印
    3.p原本是结构体指针,现被强制类型转化为整型指针,所以p+1跳过4个字节,所以p的地址要加4=0x4,所以结果为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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:4,2000000
    由第1题知,ptr1指向的是数组后面的第一个地址,ptr1[-1]== * (ptr-1)即数组第四个元素4;
    数组名a原本是首元素地址,设首元素地址为0x11223300,后来将a强制类型转化为int型,所以此时的0x11223300为数字而非地址,+1变为0x11223301,再将(int)a + 1强制类型转化为int * 类型,即又把0x11223301当成地址赋值给指针变量ptr2,这个地址在首元素地址后1个,又因为数据以小端存储模式存储(数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中),画出数组第1、2个元素的内存图(如下),对ptr进行解引用找到从ptr指向的内容到后面的3个字节的内容(下图中有黄色线条区域),将内存图的数据转化为现实数据即0x02000000,以16进制输入得2000000
    在这里插入图片描述

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:1
    (0, 1), (2, 3), (4, 5)都是逗号表达式,所以数组a的元素为1,3,5,0,0,0,a[0]是一个一维数组,存储的是数组a第一行的元素,数组名是首元素地址,即将第一行第一个元素的地址传给p,p[0]= * (p+0)=1

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:0xFFFFFFFC,-4
    下图中橙色部分是&p[4][2],蓝色部分是&a[4][2],指针-指针的绝对值=两指针之间的元素个数=4,因为&p[4][2]<&a[4][2],所以 &p[4][2] - &a[4][2]= -4。-4在内存中以补码的形式存储,-4的原码:10000000 00000000 00000000 00000100;-4的反码:11111111 11111111 11111111 11111011;-4的补码:11111111 11111111 11111111 11111100;以地址的形式进行打印,得到FFFFFFFC;以十进制进行打印就是-4。
    但我们要知道,p的类型是int( * )[4],而数组名a即首元素地址的类型为int( * )[5],两者的类型不同,在编译时编辑器会报警告
    在这里插入图片描述

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:10,5
    由题目1知,ptr1-1指向的是数组最后一个元素的地址,对地址解引用找到最后一个元素10;* (aa+1) == aa[1],且前面没有sizeof和&,所以aa[1]表示第二行的首元素地址即第6个元素即元素6的地址,该地址本身就是int * 型的,所以强制类型转化无意义,ptr2指向的是第6个元素即元素6的地址。ptr2-1指向的是第5个元素的地址,对地址解引用找到第5个元素5

    7

    int main()
    {
    	char* a[] = { "work","at","alibaba" };
    	char** pa = a;
    	pa++;
    	printf("%s\n", *pa);
    	return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    结果:at
    未进行pa++操作前,a,pa的关系如图,pa指向的是数组a的首元素地址
    在这里插入图片描述
    pa++后,pa指向的是数组a的第二个元素的地址

    在这里插入图片描述
    对pa解引用找到第二个元素,类型为char * ,即第二个元素中存储的是字符串at中a的地址。要打印字符串,通过第二个元素找到字符串at,遇’\0’停止

    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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    结果:POINT; ER ;ST; EW

    阅读前3行代码,我们可以画出下面表示c、cp、cpp关系的图(修正:ENTRY改为ENTER)
    在这里插入图片描述
    在进行第四条语句时,因为++的优先级高于 * ,所以cpp先自增1,此时cpp指向的是数组cp的第二个元素,对cpp解引用找到数组cp的第二个元素,类型为char * * ,再对元素解引用找到数组c的第三个元素,类型为char * ,要打印字符串,通过第三个元素找到字符串POINT,遇’\0’停止
    在这里插入图片描述
    在进行第5条语句之前,c、cp、cpp关系的图如上(修正:ENTRY改为ENTER)。进行第5条语句,+的优先级在该语句中最低,所以最后再+3。cpp先自增1,此时cpp指向的是数组cp的第三个元素,对cpp解引用找到数组cp的第三个元素,类型为char * * ,内容为c+1,自减1后变成c,所以此时数组cp的第三个元素指向数组c的第一个元素,类型为char * ,要打印字符串,通过第一个元素找到字符串ENTER,+3后找到字符串ENTER的E,遇’\0’停止,所以结果为ER
    在这里插入图片描述
    在进行第6条语句之前,c、cp、cpp关系的图如上(修正:ENTRY改为ENTER)。cpp[-2]== * (cpp-2)找到数组cp的第一个元素,类型为char * * ,对元素解引用找到数组c的第四个元素,,类型为char * ,要打印字符串,通过第四个元素找到字符串FIRST,+3后找到字符串FIRST的S,遇’\0’停止,所以结果为ST

    第6条语句并没有改变c、cp、cpp的关系。进行第7条语句,cpp[-1][-1]== * (* (cpp-1)-1),cpp-1指向数组cp的第二个元素,对元素解引用找到数组cp的第二个元素,再-1指向数组c的第二个元素,对元素解引用找到数组c的第二个元素,要打印字符串,通过第二个元素找到字符串NEW,+1后找到字符串NEW的E,遇’\0’停止,所以结果为EW


    好了,那么本篇博客就到此结束了,如果你觉得本篇博客对你有些帮助,可以给个大大的赞👍吗,感谢看到这里,我们下篇博客见❤️

  • 相关阅读:
    SystemVerilog语言之约束的技巧和技术
    Linux终端操作-Xshell和Xftp(家庭版)
    tensorboard玩耍手册
    Python—argparse模块
    2.13每日一题(根号下的定积分及去绝对值的定积分)
    江湖再见,机器视觉兄弟们,我已经提离职了,聪明的机器视觉工程师,离职不亏本!
    矩阵蠕虫,陈欣出品
    Azure Machine Learning - Azure AI 搜索中的矢量搜索
    京东云开发者|mysql基于binlake同步ES积压解决方案
    表单提交是
  • 原文地址:https://blog.csdn.net/qq_75000174/article/details/133248790