源码不长,只一个过程。如下:
unit Unit1;interfaceuses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls;type
  TForm1 = class(TForm)
    Button1: TButton;
    OpenDialog1: TOpenDialog;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;var
  Form1: TForm1;implementation{$R *.DFM}procedure TForm1.Button1Click(Sender: TObject);
type
  ByteRa = array[0..0] of byte;
  Bytep0 = ^ByteRa;
var
  F: file;
  buff: Bytep0;
  i, Fsz: integer;
begin
  if OpenDialog1.Execute then begin
      AssignFile(F, OpenDialog1.FileName);
      Reset(F, 1);
      Fsz := FileSize(F);
      GetMem(buff, Fsz);
      BlockRead(F, buff^, Fsz);
      i := 900;
      ShowMessage(IntToStr(buff[i]));
      FreeMem(buff);
      CloseFile(F);
  end;
end;这段代码是我写的,可是我有几点不明白:
第一:位图应该是二进制的,可是buff却是一个指针数组,而且这个数组又是byte类型的,这样为什么可以???第二:buff应该是指向byte数组的第0个元素,而ByteRa = array[0..0] of byte;ByteRA只有一个元素呀,为什么i := 900;而这样buff[i]不会越界,而且有返回值,是211,一个整数。???很是奇怪,请大家指点一二。谢谢了。

解决方案 »

  1.   

    1.二进制和Byte并不矛盾,我想$0D和13以及0000 1101都表示同一个东西。
    2.象以下的type 声明
    type
      ByteRa = array[0..0] of byte;
    不会分配内存,Array的大小是动态的,BlockRead(F, buff^, Fsz);语句后它的大小就是900了。Pascal语言里没有规定数组下标从零开始,可以从1,也可以从5、13或别的数开始。所以数组的首元素可以是array[0]或array[-9]或array[3]等。
    我说得不好,你到Google上用"Dynamic array"搜索,有的外国网站说得比较透彻。
      

  2.   

    GetMem(buff, Fsz);你这句为他分配了Fsz大小的内存,所以后面就能用了
    FreeMem(buff);
      

  3.   

    谢谢lpa(lpa) 。
    1.二进制与byte并不矛盾,那么你说i := 900;而这样buff[i],读出的值是211,那么是blockread自动将二进制转换为byte吗?这样理解对吗?2.type
      ByteRa = array[0..0] of byte;
    不会分配内存,我想应该是对的。那么ByteRa = array[0..0] of byte;是动态数组吗?它与ByteRa = array of byte;有什么区别呢?》》》》》Array的大小是动态的,BlockRead(F, buff^, Fsz);语句后它的大小就是900了。
    应该不是900吧?应该是Fsz的大小吧?我只想把这个问题搞明白。谢谢了。
      

  4.   

    blockread自动将二进制转换为byte吗?
    是这样....
    BlockRead(F, buff^, Fsz);语句后它的大小就是900了。应该不是900吧?应该是Fsz的大小吧?我觉得如果是想看最后一个数据应该是FSZ吧,只要900不大于fsz这句话就没有问题,你可以取个大于fsz的数,看看会出现什么情况,我没有试,只是猜想。
    另外,array [0..0] of byte;就是动态的。
      

  5.   

    >>array [0..0] of byte;就是动态的
    那么怀array of byte有何区别。array of byte
    必须用setlength来分配内存并设置娄组的长度,而array [0..0] of byte;
    必须用GetMem来分配内存。(分配了内存,而又执行了blockread后,buff的长度是多少呀????)我这样理解对吗?
      

  6.   

    walterwl(弱智浩二) :
    还有
    我i := Fsz + 2000,这样都没有问题,程序不报错,有值显示,为0。真的奇怪,为什么呢?
    如果再是很大的话,就报地址错了,
      

  7.   

    有兴趣的朋友可以试试。这段代码可以直接运行,运行时选一个bmp文件就可以了。
      

  8.   

    我说错了,确实应该BlockRead(F, buff^, Fsz);语句后它的大小就是Fsz的大小。你说的疑惑我也有,希望看到高手的解释。
      

  9.   

    BlockRead(F, buff^, Fsz);的时候,怎么读呢?因为你的Buff是指向Byte的指针,所以读出来的当然是Byte了,Byte的值是0--255,好比读到值0110 0101(即65)时,因为位图是二进制的,而BlockRead函数也是以二进制方式读的,所以读出来的是数值65而不是字母A(ASCII表里第65个字符)。我估计你可能是习惯了C++里char和Byte混用,在Pascal里反而觉得混淆了。实际上C++里char和Byte混用才是混淆了,但C++内部有复杂的机制处理了这些差异,使得对程序员来说char和Byte都一样(我也是从书上知道这些名词,实际上具体机制如何我也不懂),但是C++Primer这本书上说这样才体现了C++的多态性,是它的优点。
      

  10.   

    lpa(lpa):
    谢谢你详细的解释,呵呵。。
    看来果然是BlockRead读的时候就转成了byte。另:
    我不熟悉C++,一直用Delphi,呵呵。
    虽然看了一段时间C++,可是觉得头大,看不懂。
      

  11.   

    个人理解:
        1.ByteRa = array[0..0] of byte;是动态数组吗?不是,它前面有关键字 Type,所以它
          成了一种类型,Integer类型应该很熟悉吧。ByteRa定义后和Integer一样,只不过是个
          类型而已。
        2.那么 Bytep0 = ^ByteRa; 这句话就可以理解成:指向ByteRa类型的一个指针,你可以
          定义一个 i=PIntege,那么i就是整数型的指针了。同样它是在Type关键字中的,所以
          ByteP0依然只是一个类型。它相当与这样一个类型: ^Integer;
        3.定义buff: Bytep0;这句话,说明Buff是一个ByteRa的指针类型。只是一个指向Byte类
          型的数组的地址(是个地址)。
        4.通过GetMem(buff, Fsz);来个分配空间,这个空间从Buff这个地址开始,大小
          为Fsz(Fsz是文件的大小)。BlockRead(F, buff^, Fsz);就将文件的内容以字节
         (byte)的形式装载到Buff开始的地址.
        5.ShowMessage(IntToStr(buff[i]));如果内存足够大,那么i多大都可以,i也可以是负
          数,buff[i]是从buff开始往后的第i个地址的内容(如果i为负数,那么buff[i]是从
          buff开始往前的第i个地址的内容)。
    总之,要先理解:
    type
      ByteRa = array[0..0] of byte;    //可以把这句话理解为定义一个新的类型。
      Bytep0 = ^ByteRa;                //这个新类型的指针表示形式。
    就象我们用Integer一样,只不过Integer是系统定义好的。^Integer是Integer的指针表示而已。
      

  12.   

    非常感谢lincanwen(密码错误)。>>>>>ByteRa = array[0..0] of byte;    //可以把这句话理解为定义一个新的类型。
    >>>>>Bytep0 = ^ByteRa;                //这个新类型的指针表示形式。
    >>>>>就象我们用Integer一样,只不过Integer是系统定义好的。^Integer是Integer的指针表>>>>>示而已。这我可以理解。1.2.3.4.5也可以理解。关键是buff:Bytep0;也就是说为什么要把buff定义成Bytep0,也就是指向数组的一个指针?
    定义成^integer不行吗?我的理解是定义成一个指向数组的指针有好处,就可以通过buff[i]来访问,而定义成^integer,就不能这样来访问。我的理解正确吗?
      

  13.   

    或者说buff定义成^integer,也可以,如果要访问buff指向的地址后面的内容,要增加P,
    这样操作较麻烦,是这样吗?我还有一点想不通
    >>>>>ByteRa = array[0..0] of byte;    //可以把这句话理解为定义一个新的类型。
    >>>>>Bytep0 = ^ByteRa;                //这个新类型的指针表示形式。
    为什么这样定义,就可以buff[i]来访问呢?
      

  14.   

    ---------------------------------------------------------------------------
    我的理解是定义成一个指向数组的指针有好处,就可以通过buff[i]来访问,而定义成^integer,就不能这样来访问。我的理解正确吗?
    ---------------------------------------------------------------------------
       BlockRead是以字节(Byte)的形式读取文件内容的,如果该函数是以Integer的形式来读
       取,那么就应该定义成 ^Integer了。------------------------------------------------
    我还有一点想不通
    >>>>>ByteRa = array[0..0] of byte;    //可以把这句话理解为定义一个新的类型。
    >>>>>Bytep0 = ^ByteRa;                //这个新类型的指针表示形式。
    为什么这样定义,就可以buff[i]来访问呢?
    ------------------------------------------------
    通过buff[i]来访问,因为定义成ByteRa = array[0..0] of byte;Buff就指向Byte类
          型的数组,数组自然可以用下标的方式来访问。
      

  15.   

    非常感谢 lincanwen(密码错误)。我的数组的指针理解不是很好。呵呵
    努力理解中。
      

  16.   

    内存中的数据:
    Buff的地址----> |___________|---->存放ByteRa类型的数据
                    |___________|---->存放ByteRa类型的数据
                    |___________|---->存放ByteRa类型的数据
                    |___________|---->存放ByteRa类型的数据
                    …
    如果定义改成:ByteRa = array[0..1] of byte,那么:
    Buff的地址----> |___________|---->存放ByteRa类型的数据下标[0]
                    |___________|---->存放ByteRa类型的数据下标[1]
                    |___________|---->存放ByteRa类型的数据下标[0]
                    |___________|---->存放ByteRa类型的数据下标[1]
                    …
      

  17.   

    懂了,非常感谢lincanwen。结了。