> 文档中心 > 【C语言进阶】经典笔试题详解之指针篇

【C语言进阶】经典笔试题详解之指针篇


一、题目:

代码块①:

int a[3][4] = { 0 };printf("①%d\n", sizeof(a));printf("②%d\n", sizeof(a[0][0]));printf("③%d\n", sizeof(a[0]));printf("④%d\n", sizeof(a[0] + 1));printf("⑤%d\n", sizeof(*(a[0] + 1)));printf("⑥%d\n", sizeof(a + 1));printf("⑦%d\n", sizeof(*(a + 1)));printf("⑧%d\n", sizeof(&a[0] + 1));printf("⑨%d\n", sizeof(*(&a[0] + 1)));printf("⑩%d\n", sizeof(*a));printf("11%d\n", sizeof(a[3]));

结果:

在这里插入图片描述

解析:
请看此时二维数组在内存中的存放形式:
在这里插入图片描述

  • int a[3][4]={0};
  1. printf(“%d\n”,sizeof(a));
    解:sizeof(a)表示计算整个数组的大小,为344=48
  2. printf(“%d\n”,sizeof(a[0][0]));
    解:a[0][0]表示数组a中的第一个元素,sizeof(a[0][0])计算数组a中第二个元素所占空间大小;
  3. printf(“%d\n”,sizeof(a[0]));
    解:a[0],相当于第一行的地址,表示第一行所有元素。为:4*4=16;
  4. printf(“%d\n”,sizeof(a[0]+1));
    解:a[0]没有单独放在sizeof()内部,也没有取地址,所以它现在表示第一行第一个元素的地址,a[0]+1表示第一行第二个元素的地址;sizeof()计算地址为:4/8;
  5. printf(“%d\n”,sizeof(*(a[0]+1)));
    解:对第一行第二个元素解引用,表示计算第二个元素所占空间的大小,为4;
  6. printf(“%d\n”,sizeof(a+1));
    解:a是二维数组的数组名,并没有取地址,也没有单独放在sizeof()内部,所以a表示二维数组首元素地址,即第一行的地址,a+1就表示第二行的地址;计算地址为:4/8;
  7. printf(“%d\n”,sizeof(*(a+1)));
    解:对第二行解引用,计算第二行所有元素大小,为16;
  8. printf(“%d\n”,sizeof(&a[0]+1));
    解:&a[0]+1表示取出第二行的地址,计算地址大小为4/8;
  9. printf(“%d\n”,sizeof((&a[0]+1));
    解:16,
    (&a[0]+1)表示对第二行解引用,求第二行所有元素所占空间的大小;
  10. printf(“%d\n”,sizeof(*a));
    解:16;a没有单独放在sizeof()内部,所以a表示二维数组首地址即:第一行的地址,*a对第一行解引用,求第一行所有元素所占空间的大小;
  11. printf(“%d\n”,sizeof(a[3]));
    解:16;a[3]其实是第四行的地址(如果存在的话),其实在内存中并不存在a[3],但是sizeof并不会计算表达式的值,它也会通过表达的类型计算它所占空间大小;我们知道,一个表达式:int a= 3+5;a有两个属性,一个值属性:8,一个类型属性:int,而size of()是计算变量所占空间大小,即表达式的类型所占空间大小,它并不会计算表达式的值。

代码块②:

int main(){short s=5;int a = 3;printf("%d\n",sizeof(s=s+3));printf("%d\n",s);//5 sizeof并不计算表达式的值;}

结果为:

在这里插入图片描述
解析:

  1. sizeof(s=s+3)的值为:2;表示 sizeof只看它的类型大小,short类型大小为2,而不会具体去看表达式的值;
  2. printf(“%d\n”,s)的值还是5,表示sizeof并不计算表达式的值;

代码块③:

int main(){int a[5]={1,2,3,4,5};int* ptr=(int*)(&a+1);整个数组地址+1,强制转换成int*printf("%d%d",*(a+1),*(ptr-1));//2  5return 0;}

图解:
在这里插入图片描述

代码块④:

struct Test{int Num;char* pcName;short sDate;char cha[2];short sBa[4];}*p;//假设p的值为0x1000000。如下表达式的值分别是多少?//已知,结构体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;}

结果:

在这里插入图片描述

解析:
●考察的是:指针类型决定了指针的运算。

  1. 在题目中①指针+1表示跳过一个结构体,而结构体大小为20字节,所以①打印为:0x100014(十六进制数字)
  2. 在②中,先把指针p强制转换成了无符号长整型,整型变量+1表示的就是值+1为:0x100001
  3. 在③中,把结构体指针p强制转换成了整型指针,所以它加一,表示加一个整型,结果为:0x100004;

代码块⑤:

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. a数组在内存中储存形式为:
    01 00 00 00 | 02 00 00 00 | 03 00 00 00 | 04 00 00 00 |
    这是数组a在内存中存放形式:
    这是数组a在内存中存放形式
  2. ①语句:表示整个数组a+1,即跳过a数组,指向下一个数组首地址;然后把这个地址强制转换成int*,类型改变,但地址没变,赋值给ptr1;>3. ②语句:先把数组a的首元素地址强制转换成int类型,然后+1;而整型+1表示值+1,在内存中它表示跳过一个字节(两个比特位)从01就指向了00;然后又把这个值强制转换成int*类型,此刻这个值又变回成了地址;而此时的地址与原来的地址相比,在原来地址的基础上加了一个字节;
  3. ③语句:ptr1[-1]表示指针ptr1指向的地址,往前跳过四个字节指向04 00 00 00处,以十六进制打印则为:4
  4. *ptr2表示对指针ptr2所指向的地址解引用,而指针是指向四个字节的数据,所以数值为:00 00 00 02;以十六进制打印则为:2000000

代码块⑥:

int main(){int a[5][5]={0};int (*p)[4];p = a;printf("%p,%d\n",&p[4][2]-&a[4][2],  &p[4][2]-&a[4][2])return 0;}

结果:

在这里插入图片描述

解:

  1. ①a为一个二维数组五行五列,p为一个int类型指针,它指向的是一个含有四个元素的数组,p里面存放的是数组的地址;
  2. ②请看此时内存中,数组a和指针p的位置关系图解:
    在这里插入图片描述
    两个指针相减等于两个变量地址相减表示:两个变量中间所包含的元素个数!
    %p是打印地址
    %d是打印整型数值

二、总结

  • 指针往往和数组一同考察,我们在做这类题时,可以把数组在内存中的存放形式画出来,把指针所指向的位置标明,这样就很容易得出答案;
  • 最后,感谢大家的支持🤞,我们下次见!