指针八大经典题目(转载)

发布时间:2023-06-29 09:30

在此,我们将讲述C语言的精髓——指针的八道经典题目,这里我们主要以画图的方式解答。

提前说明:二维数组我们可以想象成由几个简单的一维数组组成。

题目一:


 
   
   
   
   
  1. int main()
  2. {
  3.      int a[ 5] = { 1, 2, 3, 4, 5 };
  4.      int *ptr = ( int *)(&a + 1);
  5.      printf( "%d,%d", *(a + 1), *(ptr - 1));
  6.      // 2, 5
  7.      system( "pause");
  8.      return 0;
  9. }

题目分析:数组名a表示数组首元素的地址,(&a+1)表示将整个数组的地址加一,(int*)(&a+1)表示将(&a+1)强制类型转换为int*类型。

所以本题的结果为:

题目二:


 
   
   
   
   
  1. struct Test
  2. {
  3. int mun;
  4. char *pcNmae;
  5. short sDate;
  6. char cha[ 2];
  7. short sBba[ 4];
  8. }*p;
  9. //假设p的值为0x100000
  10. int main()
  11. {
  12. p = (struct Test *) 0x100000;
  13. printf( "%p\n", p + 0x1);
  14. printf( "%p\n", ( unsigned long)p + 0x1);
  15. printf( "%p\n", ( unsigned int *)p + 0x1);
  16. printf( "%p\n", ( unsigned char*)p + 0x1);
  17. printf( "%p\n", ( unsigned char**)p + 0x1);
  18. system( "pause");
  19. return 0;
  20. }

题目分析:首先结构体为20个字节;


 
   
   
   
   
  1. printf( "%p\n", p + 0x1); //0x00 10 00 14
  2. //p是(struct Test *)类型,是指针,该结构体大小为20个字节
  3. //p:0x00 10 00 00
  4. //0x1:在十进制中为1
  5. //p+0x1=p+1=p+20个字节=0x00 10 00 14
  6. printf( "%p\n", ( unsigned long)p + 0x1); //0x00 10 00 01
  7. //p是(unsigned long)类型
  8. //p:0x00 10 00 00
  9. //0x1:0x00 00 00 01
  10. //p+0x1=0x00 10 00 01
  11. printf( "%p\n", ( unsigned int *)p + 0x1); //0x00 10 00 04
  12. //p是(unsigned int *)类型,是指针,32位平台下是4个字节,指向int类型的数据
  13. //p:0x00 10 00 00
  14. //0x1:在十进制中为1
  15. //p+0x1=p+1=p+4个字节=0x00 10 00 04
  16. printf( "%p\n", ( unsigned char*)p + 0x1); //0x00 10 00 01
  17. //p是(unsigned char*)类型,是指针,32位平台下是4个字节,指向char类型的数据
  18. //p:0x00 10 00 00
  19. //0x1:在十进制中为1
  20. //p+0x1=p+1=p+1个字节=0x00 10 00 01
  21. printf( "%p\n", ( unsigned char**)p + 0x1); //0x00 10 00 04
  22. //p是(unsigned char**)类型,是指针,32位平台下是4个字节,指向char*类型的数据
  23. //p:0x00 10 00 00
  24. //0x1:在十进制中为1
  25. //p+0x1=p+1=p+4个字节=0x00 10 00 04

所以,题目的运行结果为:

题目三:


 
   
   
   
   
  1. int main()
  2. {
  3. int a[ 4] = { 1, 2, 3, 4 };
  4. int *ptr1 = ( int *)(&a + 1);
  5. int *ptr2 = ( int *)(( int)a + 1);
  6. printf( "%x %x\n", ptr1[- 1], *ptr2);
  7. system( "pause");
  8. return 0;

题目分析:首先我们先介绍一下什么是大小端存储,大端:是指数据的高字节保存在内存的低地址中,而数据的低字节保存在内存的高地址中;小端:是指数据的高字节保存在内存的高地址中,而数据的低字节保存在内存的低地址中。而数组是在栈中存储的。题目中(int)a是把地址强制类型转换成数值,则+1加1个字节;(int *)((int)a+1)则把上一步转换得到数值强制类型转换成(int *)类型。小段存储,大端打印。

数组的存储方式:

题目中的指针指向:

数据的小端存储:

所以,题目的结果为:

题目四:


 
   
   
   
   
  1. int main()
  2. {
  3. int a[ 3][ 2] = { ( 0, 1 ), ( 2, 3 ), ( 4, 5 ) };
  4. int *p;
  5. p = a[ 0];
  6. printf( "%d\n", p[ 0]);
  7. system( "pause");
  8. return 0;
  9. }

题目分析:本题二维数组中蕴含着逗号表达式,在逗号表达式中,取每一个表达式中最后一个数据。

所以,指针P的指向以及数组a的存储我们可以想象成是这样的:

题目中的p[0]=*(p+0),所以本题的结果为:

题目五:


 
   
   
   
   
  1. int main()
  2. {
  3. int a[ 5][ 5];
  4. int(*p)[ 4];
  5. p = ( int(*)[ 4])a;
  6. printf( "%p,%d\n", &p[ 4][ 2] - &a[ 4][ 2],&p[ 4][ 2] - &a[ 4][ 2]);
  7. system( "pause");
  8. return 0;
  9. }

题目分析:在做本题之前首先需要搞清楚p[4][2]以及a[4][2]分别代表什么,题目中二维数组a为5行5列,而数组指针p指向一个为5行4列的二维数组,p[4][2]=*(*(p+4)+2),a[4][2]=*(*(a+4))。我们在开篇已经讲过,二维数组我们可以想象成由几个简单的一维数组组成,所以数组指针p指向的地址就是5行4列数组的第一行的地址,所以p+4加16个字节。如图所示:

由图可知:p[4][2]与a[4][2]之间差了4个字节

所以&p[4][2] - &a[4][2]以%d形式打印-4
而-4的二进制表示为:
原码:1000 0000 0000 0000 0000 0000 0000 0100
反码:1111 1111 1111 1111 1111 1111 1111 1011

在内存中是以补码存储:

补码:1111 1111 1111 1111 1111 1111 1111 1100

而地址是以16进制打印:
16进制:FF FF FF FC
所以&p[4][2] - &a[4][2]以%p形式打印FF FF FF FC

所以本题的结果为:

题目六:


 
   
   
   
   
  1. int main()
  2. {
  3. int a[ 2][ 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  4. int *ptr1 = ( int *)(&a + 1);
  5. int *ptr2 = ( int *)(*(a + 1));
  6. printf( "%d %d\n", *(ptr1 - 1), *(ptr2 - 1));
  7. system( "pause");
  8. return 0;
  9. }

题目分析:首先,需要明确&(a+1)表示整个数组+1,(int*)(*(a+1))表示将*(a+1)强制类型转换成为(int*)类型,其次在二维数组中数组名可以理解为第0行的地址,所以a+1表示第一行的地址。画图解题即可,如图所示:

所以,本题的结果为:

题目七:


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

题目分析:本题难度不大,只需找到指针pa初始指向的位置以及指针变量pa++以后所指向的字符串的首地址即可,如图所示:

所以,本题的结果为:

题目八:


 
   
   
   
   
  1. int main()
  2. {
  3. char *c[] = { "ENTER", "NEW", "POINT", "FIRST" };
  4. char **cp[] = { c + 3, c + 2, c + 1, c };
  5. char ***cpp = cp;
  6. printf( "%s\n", **++cpp);
  7. printf( "%s\n", *--*++cpp+ 3);
  8. printf( "%s\n", *cpp[- 2]+ 3);
  9. printf( "%s\n", cpp[- 1][- 1]+ 1);
  10. system( "pause");
  11. return 0;
  12. }

题目分析:在做题目之前,首先需要明确题目中出现的操作符的优先级以及结合性,题目中出现的操作符优先级以及结合性从高到低依次为下标引用[ ]、从左向右;前置++、从右向左;前置--、从右向左;解引用*、从右向左;加法+、从左向右。还要注意前置++与前置--运算后,cpp将会被改变,如果上一个语句中使用前置++或前置--运算后,下一条语句将使用改变后的cpp。

初始时指针数组c、cp以及指针cpp所指向的位置如图所示:

printf("%s\n", **++cpp):图示:

所以*(*++cpp)后得到POINT。

printf("%s\n", *--*++cpp+3):图示:

所以*--*++cpp运算后得到ENTER,+3得到ER。

printf("%s\n", *cpp[-2]+3):*cpp[-2]+3=*(*(p-2)+3)图示:

所以*cpp[-2]运算完后得到FIRST,+3得到ST。

printf("%s\n", cpp[-1][-1]+1):cpp[-1][-1]+1=*(*(cpp-1)-1)+1。图示:

所以cpp[-1][-1]运算完以后得到NEW,+1得到EW。

所以本题的运行结果为:

总结:这8道题考查了二维数组的访问、数组的存储、大端模式、小端模式、数组名与&数组名+1所代表的含义、操作符结束运算后变量是否发生改变以及指针的运算,画图更加便于理解数组与指针相结合的题目,希望大家可以加深理解。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号