zoukankan      html  css  js  c++  java
  • Delphi 数组 详解

    技术交流,DH讲解.

    首先我们要知道什么是数组?数组是一堆相同特性数据的一个集合,也就是每个元素的类型必须是一样的,当然在其他一些弱语法的语言里面,数组的元素可以千奇百怪.
    例子:

    Var
      A: Array[ 0..2 ] Of Integer ;
    Begin
      A[ 0 ] := 1 ;
      A[ 1 ] := 1.0 ; //这里是错的,因为每个元素都必须是Integer类型
    End ;

    Delphi中数组分类:
    1 定长和不定长.
    定长数组:也就是长度在声明的时候就确定了,后面是不能改变的,而在定长数组中,起始序号不必从0开始,可以自己定.例如:

    Var
      A: Array[ 2..3 ] Of Integer ;
    Begin
      A[ 2 ] := 1 ;
      SetLength(A,3);//这里会出错,定长数组不能再分配
    End ;

    从上面我们可以看到起始序号是2,但是步长是1,是不能改变的.为什么我们看到很多数组的起始序号都是0呢?习惯而已.大家都习惯在厕所里面去嘘嘘,而你一个人习惯在广场上面嘘嘘,那么大家都会说你不文明了.但是如果大家一开始都是在广场上面嘘嘘的话,不说了太恶心了.
    来看一个特殊的用法:

    type
      THuangJacky = (hjA,hjB,hjC);
    const
      //用法1
      B:array[0..2] of string= ('A','B','C');
      //用法2
      C:array[THuangJacky] of string= ('A','B','C');
    Var
      H:THuangJacky;
      S:string;
    Begin
      S:=B[Ord(H)];
      S:=C[H];
      //B[H] 和 C[1]都会出错
    End ;

    用法1 和用法2你觉得那种用着爽一些?
    从上面例子可以看出来只要是序数类型都可以当数组的序号.但是我们用的时候序号就必须是声明的那种序数类型,所以上面代码注释中才会写出2种错误的情况.
    不定长数组:动态数组,也就是声明的时候没有说长度是多少,在使用前必须声明,长度可以再分配.序号必须从0开始.看个简单的例子

    Var
      A: Array Of Integer ;
    Begin
      SetLength( A, 3 ) ; //数组一共有3个元素
      A[ 0 ] := 1 ;
      A[ 1 ] := 2 ;
      A[ 2 ] := 3 ;
      //A[3]没有它,有它的话,你数一下几个了?不会数数,那我推荐你去街道口小学看一下
      SetLength( A, 4 ) ; //如果变长长度,直接增加后面的元素
      A[ 3 ] := 4 ; //现在有它了.
      SetLength( A, 3 ) ; //如果长度变短,超出部分会被去掉
      // A[3]又没有它了
    End ;

    有时候大家这样要先设定长度,然后再赋值,是不是很麻烦?没有一气呵成的感觉.好吧,再说一招:

    Type
      TA = Array Of Integer ;
    Var
      A: TA ;
    Begin
      A := TA.Create( 1, 2, 3 ) ;
      //此招请勿在D7上面使用
      //这样A[0]:=1,A[1]:=2,A[2]:=3
    End ;

    2 一维和多维.
    前面所有例子,我们都只是说了一维数组,要是现在我们想弄一个矩阵(多维数组)怎么办?

    Var
      A: Array [0.. 2, 0.. 2] Of Integer;
      B: Array [0.. 2] Of Array [0.. 2] Of Integer;
    Begin
      A[0, 0]:= 1;
      A[0][0]:= 1;
    End;

    两种方法都可以的.

    Var
      B: Array Of Array Of Integer;
    Begin
      SetLength(B, 3, 3); // 3*3矩阵
      // 如果要实现齿状数组,必须这么做
      SetLength(B, 3);
      SetLength(B[0], 1); // *
      SetLength(B[1], 2); // **
      SetLength(B[2], 3); // ***
    End;

    接下来我们说说几个关于数组中常用的函数:
    第一个 复制数组

    Var
      A, B: Array [0.. 1] Of Integer;
    Begin
      A[0]:= 1;
      A[1]:= 2;
      B:= A;
      B[0]:= 2;
      ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:1,B0:2
    End;

    这个效果就是我们想要的,貌似没有什么好说的.如果是动态数组呢?

    Var
      A, B: Array Of Integer;
    Begin
      SetLength(A, 2);
      SetLength(B, 2);
      A[0]:= 1;
      A[1]:= 2;
      B:= A;
      B[0]:= 2;
      ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:2,B0:2
    End;

    现在怎么办?A和B被关联到了一个地址了,其实现在我们可以使用Copy函数,对就是复制字符串的那个函数:

    Var
      A, B: Array Of Integer;
    Begin
      SetLength(A, 2);
      SetLength(B, 2);
      A[0]:= 1;
      A[1]:= 2;
      B:= Copy(A); // 整个数组都复制过去
      B:= Copy(A, 0, 2); // 选择性复制
      B[0]:= 2;
      ShowMessageFmt('A0:%D,B0:%D', [A[0], B[0]]); // A0:1,B0:2
    End;

    第二个 序号相关
    函数Low()和High()值得信赖,不过我们需要注意的是,它们返回的类型是我们数组的序号的那个类型,并不都是Integer,如前面例子中的THuangJacky.

    var
      A : array of array of string;
      I, J : Integer;
    begin
      SetLength(A, 10);
      for I := Low(A) to High(A) do
      begin
        SetLength(A[I], I);
        for J := Low(A[I]) to High(A[I]) do
          A[I,J] := IntToStr(I) + ',' + IntToStr(J) + ' ';
        end;
      end;

    第三个 数组长度
    Length()函数返回的就一定是是Integer了,因为个数不是整数难道还有半个么?

    Var
      A: Array Of Integer;
    Begin
      SetLength(A, 2);
      Length(A); // 返回2
    End;
     

    最后说个问题我就不说了:
    从上面那个复制的例子我们可以看出来什么东西?
    定长数组变量就是一个变量,所以可以直接用:=来赋值,而动态数组变量就是一个指针,如果用了:=来赋值2个变量就关联在一起了.

    Var
      A: Array [0.. 2] Of Integer;
      B: Array Of Integer;
    Begin
      ShowMessageFmt('A:%8x,A[0]:%8p', [Integer(@A), @A[0]]); // 一样,从地址来看这个数组空间在栈上面
      SetLength(B, 3);
      ShowMessageFmt('B:%8p,B[0]:%8p', [B, @B[0]]); // 一样,这个数据空间在堆上面
    End;

    我们看到A要取地址才和A[0]取地址一样,那么也就是说A就是A[0].
    而B直接就和B[0]取地址一样了,也就是说B就是B[0]的地址.

    数组在内存中的分布:连续分布的,间隔就是每个元素的大小.

    Var
      A: Array [0.. 2] Of Integer;
      B: Array Of Integer;
    Begin
      A[1]:= 123;
      // 从A也就是A[0]的地址上面 往下走4个直接 就是A[1]
      ShowMessageFmt('A[1]:%D,直接取值:%D', [A[1], PInteger(Integer(@A)+ 4)^]);
      // 一样,都是123
      SetLength(B, 3);
      B[2]:= 88;
      // 从B往下走8个字节就是B[2]
      ShowMessageFmt('B[2]:%D,直接取值:%D', [B[2], PInteger(Integer(B)+ 8)^]); // 一样,88
    End;

    但是动态数组的结构和字符的结构就很像了:

    偏移 -8 -4 0~Length*元素大小-1
    内容 32位引用次数 元素个数 实际内容

    好了只能说这么多了,我只理解了这么多.

    我是DH.

  • 相关阅读:
    C# 利用ffmpeg 对视频转换系类操作 (1) 基本分析
    对象的行为
    类、对象、包
    java中的程序流程控制
    季节
    好的博客网址
    大家好 希望大家多多帮助
    Android 4.4 安卓系统突破限制让所有应用程序可操作外置SD卡
    STL笔记:函数配接器(Function adapters)
    STL中仿函数的简要回顾
  • 原文地址:https://www.cnblogs.com/huangjacky/p/1628833.html
Copyright © 2011-2022 走看看