当前位置:C++技术网 > 资讯 > 编程变态题目--指针运算考题的详细分析

编程变态题目--指针运算考题的详细分析

更新时间:2015-06-27 01:12:27浏览次数:1+次

题目:

int a[]={1,2,3,4,5,};
int * p = a;
int * q = &a[5];
printf("%d",q-p);

在sizeof(int)为4的情况下,选项哪个正确:
A:编译报错
B:编译不报错,但是运行崩溃
C:输出5
D:输出20

-----------------------------------------
    下面我对这个题目详细分析一番。
    题目还原成一个完整的程序,可以供大家

#include "stdio.h"
void main()
{
    int a[]={1,2,3,4,5,};
    int * p = a;
    int * q = &a[5];
    printf("%d",q-p);
}
     通过运行,发现结果是5。但是你用q的值减去p的值,却发现是20.
    a数组的定义初始化,以这种形式自动确定数组大小。这个做法,在编程里,确实也经常用到。不该的是,里面多一个逗号。我就想问一下这个出题的老师,你脑残了吗?你这个是想考什么呢?还是你手一贱,多加了一个逗号?第一次见到这种题目,我也是醉了。你是要彰显你的自己装逼的本能,我能理解,可惜你装漏。就因为这个,A选项给你一个编译不通过。事实上,是可以编译通过的。
    实际上,如果把a的初始化,出在编译原理课程题目里,确实不错。这个可以考编译器如何处理。放在这里就不合适了。你说这个对初学编程的人来说,有什么意义呢?
    然后p的值就是数组的起始地址。且指针的类型为指向整型变量的指针。然后就是q的定义和初始化。&a[5]与前面a的定义一搭配,那绝对是一个装逼的好料子。绝对是绝大多数人为之崩溃。如果单纯说&a[5]还情有可原,但是这两个一搭配,就是有多年编程经验的人,一看,都不知道什么情况,更何况一个刚学编程的人呢。
    根据前面的分析,a数组就只有五个元素,因此a[5]已经是越界了的。因此这里,就是第二个选项了。是不是会运行崩溃,如果越界,理论上是会崩溃的。然而事实上,并非如此。
    越界的情况,应该是通过越界的下标,去读写这个越界的下标所指的数组元素。因为它不存在于数组,因此就算是越界了。但是如果你不读写,根本就不会引起越界崩溃的问题。因为这里只是计算一个地址而已。
    下面来说说数组元素计算地址的方法。通过汇编代码和逻辑推理都可以得到,数组元素地址的计算,有一个公式:数组元素的起始地址 = 第多少个元素(以0开始)*每个元素所占字节大小(sizeof(数据类型)得到的字节大小)+数组起始地址。这样就计算出了元素的起始地址。而第多少个元素,就是[]里面的数字,要取地址,就是&操作符。因此&a[5]只是启动计算数组第五个元素的起始地址,虽然这个a[5]实际上是第六个元素(以0作为第一个),在这个数组中并不存在,但是只是用来作为计数使用的,只是用来计算地址的。所以,也没有通过这个下标去读写这个元素,不管它存不存在,都没有问题。所以不会存在崩溃的可能。当然这里计算地址,只是一个公式计算,与访问读写数组没有半毛钱的关系,就算你写&a[1000]也是可以计算出地址的。这个公式的来源,是根据数组的内存是连续存放的原理做做的。
    这是计算地址,不会崩溃。而在实际的开发过程中,你会发现,就这样越界一个,就算是读写,也不一定会崩溃,甚至根本就不会崩溃。至于为什么,请参考《为什么栈中的数组越界后经常不崩溃,还可以正常的操作呢》,这篇文章中详细说明了原因。
    那么到此,这第二个选项,说崩溃的,仍然是漏洞百出。而这些,对于一些编程有经验的,都不一定能弄得清楚,况且还是刚学习的同学呢。老师也不一定讲的清楚。这里面牵扯的太多了,这也可以看到这个出题人考虑的不周到,装逼装漏了。你直接多给两个错误的输出项的选项不就可以了,no zuo no die!
    后面两个选项,才是此题目应该有的,这两个才是这个题目的真正的考点。
    q得到了根据数组规则计算出来的第5个元素(以0作为第一个,实际上是第六个元素)的地址,下面就是用q-p即得到指针相隔的距离。如果直接去用指针的值相减,那么得到20。结果很多人选了20 ,结果就错了。因为指针相减要考虑到指针所指的数据类型,来决定指针运算的基本单位。指针的自增自减加减,都是以指向的数据类型所占字节的大小作为基本单位的。这里的数据类型的大小,就是sizeof(int)得到的4.那么实际上,上面计算得到的20是两指针相隔的字节数,但不是真正的结果。指针运算得到的是相隔多远,以指向的数据类型大小作为逻辑单位,这里就是以4字节为一个基本单位,所以就是20/4=5.表示指针相隔五个单位,一个单位4字节。这就是正确的答案5了。可以通过运行程序得到是这个答案。
    如此看来,这个题目真正的考点就是指针运算,然而却搞了这么多杂来时,却没装好。老师也不会讲的这么细致。你觉得这个题目,刚开始学的同学能搞透吗?最多就是知道了指针是这么运算的,仅此而已。
    所以,最后,考试成绩好,工作时发现编程中的语法都是很简单的,没有那些晦涩难懂的语法。因为实际的程序,为了降低错误率,尽可能让语法清晰,一看不会产生纠结的语法。当然基础的你要清楚。