【指针训练——八道题】

简介: 【指针训练——八道题】

每一个不曾起舞的日子,都是对生命的辜负。



八道笔试题解析



题目:


笔试题1


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

微信图片_20230221141054.png


a表示这个数组的首地址,&a则是整个数组的地址,故在进行(&a+1)操作的过程中,+1操作跳过了a整个数组,由于a是数组,&a代表数组指针,在赋值ptr的过程,左面是整形指针,右面是数组指针,两边类型有所差异,故用(int*)将(&a+1)强转成整形指针类型,否则会产生警告。故对于*(a+1),a+1为2的地址,(a+1)就是2,ptr-1为5的地址,(ptr-1)就是5。


笔试题2


struct Test
{
  int Num;
  char* pcName;
  short sDate;
  char cha[2];
  short sBa[4];
}*p;//即p = (struct Test*)0x100000
//假设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;
}


0x表示16进制,0x1代表1,由于p是指针类型,指针+1或者减1代表跳过这个类型的大小,即:

(1)一个整形指针+1代表跳过一个整型

(2)一个结构体指针+1代表跳过一个结构体

(3)一个字符指针+1代表跳过一个字符

(单位:字节)

故p+0x1代表跳过这个结构体(20字节),化成16进制就是14,故p+0x1 为0x100014;(unsigned int)p代表普通整形类型,故+1就代表这个整形数字+1,并不是地址之间的运算,(unsigned int)p+0x1 为0x100001;(unsigned int*)p把结构体类型指针强转成无符号整型的指针,故+1所跳过的步长从20变成了4,即(unsigned int*)p+0x1为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;
}


微信图片_20230221141318.png


对于ptr1的操作与笔试题1操作相同,ptr1[-1]表示*(ptr1-1),即为4;

对于ptr2的操作,假设a的地址为0x0012ff40,当强转成int类型时,即表示整数0x0012ff40故(int)a+1就代表数字0x0012ff41,再强转成(int*)类型,又变成了地址,即在a原来的地址上向右移动了一个字节大小,故ptr2指向位置如图所示,由于是int*,故解引用时需从ptr2指向的位置开始数直到第四个字节00 00 00 02,,由于是小端存储模式(上篇提到过),故读数需从高地址然后低地址,02 00 00 00,由于地址本是16进制,%x打印即为20000000


笔试题4


int main()
{
  int a[3][2] = { (0, 1), (2, 3), (4, 5) };
  int* p;
  p = a[0];
  printf("%d", p[0]);
  return 0;
}


在此之前,我们需要注意的是逗号表达式的结果为最后面的数字,即a[3][2]的内部数字为:{

1,3,

5,0,

0,0}

a[0],表示矩阵第一行的数组名,故p代表第一行数组名,p[0] = a[0][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;
}


微信图片_20230221141555.png


由以上代码我们看到,a为int [5[[5],p为int(*)[4],由于类型不匹配,故赋值时会发生警告,但仍然可以运行,通过绘图,我们可以看出p[4][2]与a[4][2]的具体位置,地址-地址等于地址之间相差元素的个数,故以%d形式打印时结果为-4;当以%p打印时,根据-4的原码:10000000000000000000000000000100,

求出反码:111111111111111111111111111111111011,再求出补码:111111111111111111111111111111111100,可化为ff ff ff fc


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


微信图片_20230221141724.png


经过几道题的讲解,这道题与前几道类似,主要就是将图化成一行,而不是两行,故得到的结果为10 5


笔试题7


int main()
{
  char* a[] = { "work","at","alibaba" };
  char** pa = a;
  pa++;
  printf("%s\n", *pa);
  return 0;
}


微信图片_20230221141835.png


数组名表示首元素地址,当把a赋值给pa时,pa指向了a的地址,由于pa为char**即pa++移动的大小为一个char*大小,故表示如图,pa指向(a+1),*pa代表:

*(a+1)即a[1],即以%s打印a[1],结果为at。


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

微信图片_20230221141954.png

作为最后一题出现,势必会很麻烦,因此,我们需要弄清它们之间的关系,即前三行代码之间的关联,如上图。

1)当我们执行第一个printf时,++cpp,则cpp指向了cp[1],即:

微信图片_20230221142044.png

故**cpp就是将连线的一点一点解引用,*cpp找到cp[1],

**cpp找到c[2],最终打印POINT;

2)当我们执行第二个printf时,又++cpp,指向cp[2],再解引用,即通过连线找到下一级,即到达cp[2],–cp[2],即cp[2]从指向c[1]变成指向c[0],再解引用,到达ENTER的首地址,再+3,到达ER,即:


微信图片_20230221142133.png


3)当我们执行第三个printf时,可变成:

微信图片_20230221142224.png即cpp-2为cp[0]的地址,解引用变成cp[0],再解引用为c[3],c[3]看成数组名,为FIRST首元素F的地址,+3为S的地址,故结果为ST;

微信图片_20230221142234.png

4)当我们执行第四个printf时,按照上述找线段的方法,不难找到:

微信图片_20230221142344.png

即结果为EW。

微信图片_20230221142425.png


总结:



通过以上八道题的训练,囊括了指针核心的运算以及最难理解的部分,不难看出,画图并且画好图才是降伏一切指针关系的最终手段。

相关文章
|
5月前
|
算法 Java C语言
刷题训练之双指针问题
刷题训练之双指针问题
33 0
|
存储 算法 安全
04-📝C++核心语法|面向对象2【友元、内部类与局部类、强化训练(数组类封装)、运算符重载、仿函数、模板、类型转换、 C++标准、错误&&异常、智能指针】
复习`C++核心语法`,且适当进行汇编探索底层实现原理,进一步夯实基础,为以后的`底层开发`、`音视频开发`、`跨平台开发`、`算法`等方向的进一步学习埋下伏笔。
04-📝C++核心语法|面向对象2【友元、内部类与局部类、强化训练(数组类封装)、运算符重载、仿函数、模板、类型转换、 C++标准、错误&&异常、智能指针】
|
存储 C语言
进阶C语言:指针和数组训练题
进阶C对指针专门总结的练习题,你也快来试试吧!
53 0
|
算法 C++
【基础算法训练】——双指针
【基础算法训练】——双指针
127 0
【基础算法训练】——双指针
|
6月前
|
C语言
指针进阶(C语言终)
指针进阶(C语言终)
|
2月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
28 0
|
3月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
4月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
|
4月前
|
C语言
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
【C初阶——指针4】鹏哥C语言系列文章,基本语法知识全面讲解——指针(4)
|
4月前
|
存储 编译器 C语言
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)
【C初阶——指针3】鹏哥C语言系列文章,基本语法知识全面讲解——指针(3)