指针相关笔试题(附解析)

目录

10. 指针相关的笔试题及解析

10.1 笔试题1

10.2 笔试题2

10.3 笔试题3

10.4 笔试题4

10.5 笔试题5

10.6 笔试题6 

10.7 笔试题7

10.8 笔试题8


10. 指针相关的笔试题及解析

10.1 笔试题1

题目:


    
    
  1. #include <stdio.h >
  2. int main()
  3. {
  4. int a[ 5] = { 1, 2, 3, 4, 5 };
  5. int * ptr = (int *)( &a + 1);
  6. printf( "%d,%d", *(a + 1), *(ptr - 1));
  7. return 0;
  8. }
  9. / /程序的结果是什么?

运行截图:

文字解析:

a是数组首元素的地址,类型为int *,数组首元素的地址+1,跳过一个整型元素,即数组第二个元素的地址,对其进行解引用就是a[1],所以输出结果为2。

&a是数组的地址,数组地址+1就是跳过一个数组大小的地址,此时类型为int (*)[5],对其进行强制类型转换后,类型变为了(int*),-1就回退一个整型元素的大小,此时指针指向的元素是5。

画图解析:

10.2 笔试题2

代码:


    
    
  1. 程序的结果是什么?
  2. #include <stdio.h >
  3. struct Test
  4. {
  5. int Num;
  6. char * pcName;
  7. short sDate;
  8. char cha[ 2];
  9. short sBa[ 4];
  10. } *p;
  11. / /假设p 的值为 0x 100000。 如下表表达式的值分别为多少?
  12. / /已知,结构体 Test类型的变量大小是 20个字节
  13. int main()
  14. {
  15. p = 0x 100000;
  16. printf( "%p\n", p + 0x 1);
  17. printf( "%p\n", (unsigned long)p + 0x 1);
  18. printf( "%p\n", (unsigned int *)p + 0x 1);
  19. return 0;
  20. }

运行截图:

代码解析:

p的类型为(struct Test*),所以+1后跳过12个字节,在进行(unsigned long)强制类型转换后,+1后跳过1个字节,在进行(unsigned int*)强制类型转换后,加1跳过一个整型的大小,即4个字节。

10.3 笔试题3

代码:


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

运行截图:

画图解析:

代码解析:

&a得到的是数组a的地址,+1即跳过一个数组的大小,对其进行强制类型转换后类型变成了int*,ptr[-1]=ptr+(-1),因为此时的类型是int*,所以回退的是一个整型的空间,因为其类型是int*,一次能够访问4个字节,所以对其进行输出后的结果是4。

对a进行强制类型转换后a的类型就变成了int,+1就是简单的加1,跳过一个字节,跳过一个字节在上图中体现的就是跳过两位数组,此时指向了00,因为其类型是int*,一次能够访问4个字节,所以取出的数组就是00 00 00 02,因为其是小端存储,并且是按照16进制形式进行打印,所以打印结果是20 00 00 00。

10.4 笔试题4

代码:


    
    
  1. #include <stdio.h >
  2. #include <stdio.h >
  3. int main()
  4. {
  5. int a[ 3][ 2] = { ( 0, 1), ( 2, 3), ( 4, 5) };
  6. int * p;
  7. p = a[ 0];
  8. printf( "%d", p[ 0]);
  9. return 0;
  10. }

运行截图:

代码解析:

此处有一个需要注意的点,就是{}中的()中的代码是逗号表达式,即代码等价于int a[3][2] = {1,3,5},即最终数组初始化的结果就像下方画的图一样!

a[0]是第一行的数组名,而此处的数组名代表的是第一行第一个元素的地址 ,即a的地址,p[0]代表的是*(p+0),p+0之后并未发生改变,仍然是第一行第一个元素的地址,且此时的类型也是int*,对其进行解引用之后就是数组第一行第一个元素,即1。

注意:

1、()中的内容是逗号表达式!

2、p[0] = *(p+0)。

10.5 笔试题5

代码:


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

运行截图:

代码解析:

10.6 笔试题6 

代码:


    
    
  1. #include <stdio.h >
  2. int main()
  3. {
  4. int aa[ 2][ 5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
  5. int * ptr 1 = (int *)( &aa + 1);
  6. int * ptr 2 = (int *)( *(aa + 1));
  7. printf( "%d,%d", *(ptr 1 - 1), *(ptr 2 - 1));
  8. return 0;
  9. }

运行截图:

代码解析:

&aa+1就是跳过一个二维数组,指向10的后面,此时的类型是int (*)[2][5],强制类型转换后类型变成int*。此时使ptr1-1就是回退一个整型元素,指向元素10,解引用之后得到元素10。

aa是二维数组的数组名,数组名是数组首元素的地址,即第一行的地址,aa+1跳过一行,此时是数组第二行的地址,对其进行解引用之后就是第二行的数组名,再进行请值类型转换后类型变成了int *(当然,此处就算不进行强制类型转换类型也是int*,因为第二行数组名是一维数组,数组名代表首元素的地址,其类型自然就是int*)。此时使ptr2-1就是回退一个元素,指向元素5,解引用之后得到元素5。

10.7 笔试题7

代码:


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

运行截图:

代码分析:

如何理解char *a = { "work","at","alibaba" };这行代码呢?

其实这行代码等价于下面的这三行代码:

a[0] = "work";

a[1] = "at";

a[2] = "alibaba";

其中a[0]、a[1]、a[2]的类型都是字符指针类型,都是存储的后面字符串常量的首地址。

a代表的是数组首元素的地址,即a[0]的地址,pa的类型是char**,即二级指针,+1后跳过一个char *类型,即pa++后pa指向的是a[1],即存储的是a[1]的地址,对其进行解引用之后得到的就是字符串常量中"at"中a的地址。

10.8 笔试题8

代码:


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

运行截图:

 

代码分析:

 对于**++cpp,这个表达式来说,*和++优先级相同,但是结合性是自右向左,所以先进行++操作,++后cpp指向cp[1],即图中的c+2,对其进行一次解引用之后可以得到cp[1]中存放的地址,二次解引用之后可以得到c[2]中存放的即"POINT"首元素即P的地址,所以打印结果应该是POINT。

对于*--*++cpp+3这个表达式来说,,首先是cpp自增1,cpp指向了图中的c+1(前一个表达式中已经自增过一次了),此时进行解引用之后得到了c+1,然后进行自减,此时就变成了c,然后再对其进行解引用之后得到了"ENTER"中字符E的地址 ,此时再进行加3,然后得到的就是E的地址,所以输出结果为ER。

对于*cpp[-2]+3这个表达式来说,这个表达式等价于**(cpp-2)+3,首先是cpp-2,因为之前cpp指向的是图中的c+1,-2之后指向的是c+3,对其进行解引用之后得到的是c[3]的地址,然后进行解引用之后就得到了FIRST的地址,然后对其进行+3,就得到了S的地址,所以打印结果为ST。

对于cpp[-1][-1]+1这个表达式来说,这个表达式等价于*(*(cpp-1)-1)+1,首先cpp-1,从指向c+1这个位置指向 了c+2这个位置,解引用得到的就是c+2,然后进行-1,变成了了c+1,然后解引用之后得到了c[1]的内容,其实是N的地址,N的地址+1得到的就是E的地址,所以输出的结果是EW。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值