跳转到内容

软件工程师手册/语言字典/PLI/数组

来自维基教科书,开放的书籍,开放的世界

注意: 本文需要对 PL/I 的基本了解,可以在软件工程师手册/语言字典/PLI中找到。

声明数组

[编辑 | 编辑源代码]

可以使用以下语法声明简单数组

DCL   name_of_array   (               higher_bound )   type_of_elements;
      or
DCL   name_of_array   ( lower_bound : higher_bound )   type_of_elements;

如果省略下界,它将获得默认值 1。

example: proc options ( main );
dcl   array_A (  5)   char (03);   /* array_A has 5 elements with index 1 to 5 */
dcl   array_B (0:5)   char (03);   /* array_B has 6 elements with index 0 to 5 */
   array_A ( 1 ) = 4711;           /* fill first element of array_A ...                  */
   array_B ( 0 ) = array_A ( 1 );  /* ... and copy its value to first element of array_B */
end example;

多维数组通过用逗号分隔维度来声明。

example: proc options ( main );
dcl   matrix ( 2 , 6:7 )   bin fixed (31);
/* defines a 2-dimensional array of 4 elements: matrix ( 1 , 6 ) , matrix ( 1 , 7 ) , */
/*                                              matrix ( 2 , 6 ) , matrix ( 2 , 7 )   */
   matrix ( 1 , 6 ) = 123;   /* store number into first matrix element */
   matrix ( 2 , 7 ) = 456;   /* store number into  last matrix element */
end example;

数组的元素不仅可以是数字、字符串或指针之类的简单类型,还可以是条目变量、文件、结构...

example: proc options ( main );
dcl   1 month ( 12 ),   /* means January ... December */
        2 income   dec fixed ( 7 , 2 ),
        2 outgo    dec fixed ( 7 , 2 );
   month ( 1 ) . income = 1234.56;   /* store income-value of January  */
   month . income ( 2 ) = 2345.67;   /* store income-value of February */
   month ( 3 ) . outgo  = 3456.78;   /* store  outgo-value of March    */
   month . outgo ( 4 )  = 4567.89;   /* store  outgo-value of April    */
end example;

 

example: proc options ( main );
dcl   1 year ( 1999 : 2019 ),
        2 month ( 12 ),
          3 value ( 3 , 3 )   bin fixed (15);
/* all of the following statements are equal */
   year ( 2009 ) . month ( 9 ) . value ( 1 , 2 ) = 32767;
   year . month ( 2009 , 9 ) . value ( 1 , 2 )   = 32767;
   year . month . value ( 2009 , 9 , 1 , 2 )     = 32767;
   year . month ( 2009 , 9 , 1 , 2 ) . value     = 32767;
   year ( 2009 , 9 , 1 , 2 ) . month . value     = 32767;
end example;

初始化数组

[编辑 | 编辑源代码]

可以使用 INITIAL(缩写:INIT)属性来初始化数组。
必须为每个数组元素分别进行初始化。
要指定一个未初始化的单个元素,可以使用星号。

在下面的示例中,程序 left 将等效于程序 right

left: proc options ( main );                    right: proc options ( main );
dcl   A ( 4 )   char (03)                       dcl   A ( 4 )   char (03);
                init ( 'ABC' , * , 'XYZ' );
                                                   A ( 1 ) = 'ABC';
                                                   A ( 3 ) = 'XYZ';
end left;                                       end right;

为了使初始化一个巨大的数组更加方便,可以使用迭代因子(前缀“(n)”表示:使用后面的值 n 次)。

left: proc options ( main );                           right: proc options ( main );
dcl   A ( 2 , 3 )   bin fixed (15)                     dcl   A ( 2 , 3 )   bin fixed (15);
                    init ( (2)5 , (2)* , (2)6 );
                                                          A ( 2 , 1 ) = 5;
                                                          A ( 2 , 2 ) = 5;
                                                       /* A ( 2 , 3 ) will be left uninitialised */
                                                       /* A ( 3 , 1 ) will be left uninitialised */
                                                          A ( 3 , 2 ) = 6;
                                                          A ( 3 , 3 ) = 6;
end left;                                              end right;
 
left: proc options ( main );                           right: proc options ( main );
dcl   A ( 2 , 3 )   bin fixed (15)                     dcl   A ( 2 , 3 )   bin fixed (15);
                    init ( (2)(-3,7) , 99 );
                                                          A ( 2 , 1 ) = -3;
                                                          A ( 2 , 2 ) =  7;
                                                          A ( 2 , 3 ) = -3;
                                                          A ( 3 , 1 ) =  7;
                                                          A ( 3 , 2 ) = 99;
end left;                                              end right;

注意:PL/I 也为字符串提供迭代因子,例如表达式“(4)X”等效于“XXXX”。
因此,如果初始化一个字符串数组,则必须明确迭代因子是针对字符串还是针对初始化。

init ( (2) (3)   'X'   )   ... means   use twice:     'XXX'
init (     (6)   'X'   )   ... means   use once-only: 'XXXXXX'
init (     (6) ( 'X' ) )   ... means   use 6 times:   'X'

数组表达式的求值

[编辑 | 编辑源代码]
  • 数组表达式可以包含数组和单个值。
  • 表达式中的所有数组必须具有相同的结构,即它们必须具有相同的维度数,并且相应的维度必须具有相同的界限。
  • 表达式的结果具有与所包含数组相同的结构。
  • 表达式的结果可以分配给具有相同结构的数组变量。

在下面的示例中,程序 left 将等效于程序 right

left: proc options ( main );            right: proc options ( main );
dcl   A (2,6:7)   bin fixed (15);       dcl   A (2,6:7)   bin fixed (15);
dcl   B (2,6:7)   bin fixed (15);       dcl   B (2,6:7)   bin fixed (15);
dcl   C (2,6:7)   bin fixed (15);       dcl   B (2,6:7)   bin fixed (15);
   /* fill variable B */                   /* fill variable B */
   /* fill variable C */                   /* fill variable C */
   A = B + C * 5;                          A ( 1 , 6 ) = B ( 1 , 6 ) + C ( 1 , 6 ) * 5;
                                           A ( 1 , 7 ) = B ( 1 , 7 ) + C ( 1 , 7 ) * 5;
                                           A ( 2 , 6 ) = B ( 2 , 6 ) + C ( 2 , 6 ) * 5;
                                           A ( 2 , 7 ) = B ( 2 , 7 ) + C ( 2 , 7 ) * 5;
end left;                               end right;

对数组执行的所有操作都是按元素方式进行的,以从右到左的维度顺序进行。

left: proc options ( main );                 right: proc options ( main );
dcl   A (2,2)   init ( 1, 2, 10, 50 );       dcl   A (2,2)   init ( 1, 2, 10, 50 );
   A = A + A ( 2 , 1 );                         A ( 1 , 1 ) = A ( 1 , 1 ) +  A ( 2 , 1 );   /* =  1 + 10 = 11 */ 
                                                A ( 1 , 2 ) = A ( 1 , 2 ) +  A ( 2 , 1 );   /* =  2 + 10 = 11 */ 
                                                A ( 2 , 1 ) = A ( 2 , 1 ) +  A ( 2 , 1 );   /* = 10 + 10 = 20 */ 
                                                A ( 2 , 2 ) = A ( 2 , 2 ) +  A ( 2 , 1 );   /* = 50 + 20 = 70 */ 
end left;                                    end right;

使用星号进行数组的横截面

[编辑 | 编辑源代码]

使用星号表示法可以引用数组的横截面。
星号指定将使用此维度的整个范围。

If an array is declared as
   dcl   A ( 2 , 3 )   char (06);
the reference A ( * , 3 ) refers to a 1-dimensional array containing the elements
   A ( 1 , 3 ) and A ( 2 , 3 ),
the reference A ( 1 , * ) refers to a 1-dimensional array containing the elements
   A ( 1 , 1 ) and A ( 1 , 2 ) and A ( 1 , 3 ).

在下面的示例中,程序 left 将等效于程序 right

left: proc options ( main );            right: proc options ( main );
dcl   A ( 2 , 2 )   char (10);          dcl   A ( 2 , 2 )   char (10);
dcl   B ( 2 , 2 )   char (10);          dcl   B ( 2 , 2 )   char (10);
   A ( * , * ) = 'hello PL/I';             A = 'hello PL/I';   /* fill all elements of A */
   B ( * , 1 ) = A ( 2 , * );              B ( 1 , 1 ) = A ( 2 , 1 );
                                           B ( 2 , 1 ) = A ( 2 , 2 );
end left;                               end right;

重新定义现有数组

[编辑 | 编辑源代码]

可以使用 DEFINED(缩写:DEF)属性将声明的数组映射到现有的“旧”数组。

在下面的示例中,程序 left 将等效于程序 right

left: proc options ( main );            right: proc options ( main );
dcl   A ( 8 , 8 )   char (10);          dcl   A ( 8 , 8 )   char (10);
                                        dcl   B ( 6 , 6 )   char (10)   defined A;
                                        dcl   C ( 4 )       char (10)   def A ( * , 2 );
   A ( 6 , 6 ) = 'hello PL/I';             B ( 6 , 6 ) = 'hello PL/I';
   A ( 4 , 2 ) = 'hello PL/I';             C ( 4 )     = 'hello PL/I';
end left;                               end right;

要引用旧数组中指定的元素,新数组的声明可以包含iSUB 元素。

iSUB 表示
每当访问新数组时,该引用的第 i 个索引将用于计算旧数组的索引。

在下面的示例中,程序 left 将等效于程序 right

left: proc options ( main );            right: proc options ( main );
dcl   A ( 8 , 8 )   char (10);          dcl   A          ( 8 , 8 )   char (10);
                                        dcl   transposed ( 8 , 8 )   char (10)   DEF A ( 2sub , 1sub );
                                        dcl   centered   ( 4 , 4 )   char (10)   DEF A ( 1sub + 2 , 2sub + 2 );
                                        dcl   diagonal   ( 8 )       char (10)   DEF A ( 1sub , 1sub );
   A ( 2 , 5 ) = 'hello PL/I';             transposed ( 5 , 2 ) = 'hello PL/I';   /* swap indexes     */
   A ( 3 , 6 ) = 'hello PL/I';             centered   ( 1 , 4 ) = 'hello PL/I';   /* increase indexes */
   A ( 7 , 7 ) = 'hello PL/I';             diagonal   ( 7 )     = 'hello PL/I';   /* use index twice  */
end left;                               end right;

连接和非连接存储

[编辑 | 编辑源代码]

数组将以元素方式进行连接存储,以从右到左的维度顺序进行。

dcl   A ( 2 , 2 , 2 )   char (10);
allocates adjacent storage in the following order:
   +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+
   | A (1,1,1) | A (1,1,2) | A (1,2,1) | A (1,2,2) | A (2,1,1) | A (2,1,2) | A (2,2,1) | A (2,2,2) |
   +-----------+-----------+-----------+-----------+-----------+-----------+-----------+-----------+

数组的横截面的引用可能指向非连接存储。

dcl A ( 2 , 2 )   will allocates storage in the following order:
   +-------------+-------------+-------------+-------------+
   | A ( 1 , 1 ) | A ( 1 , 2 ) | A ( 2 , 1 ) | A ( 2 , 2 ) |
   +-------------+-------------+-------------+-------------+
 
the reference   A ( 1 , * )   refers to connected storage.
   +-------------+-------------+
   | A ( 1 , 1 ) | A ( 1 , 2 ) |
   +-------------+-------------+
 
the reference   A ( * , 1 )   refers to unconnected storage.
   +-------------+ - - - - - - +-------------+
   | A ( 1 , 1 ) |     gap     | A ( 2 , 1 ) |
   +-------------+ - - - - - - +-------------+

数组内部的结构化元素的引用将指向非连接存储。

dcl 1 A ( 2 ),
         2 B ... ,
         2 C ... ;   will allocates storage in the following order:
   +-------------+-------------+-------------+-------------+
   | A ( 1 ) . B | A ( 1 ) . C | A ( 2 ) . B | A ( 2 ) . C |
   +-------------+-------------+-------------+-------------+
 
the reference   A . B   refers to unconnected storage.
   +-------------+ - - - - - - +-------------+
   | A ( 1 ) . B |     gap     | A ( 2 ) . B |
   +-------------+ - - - - - - +-------------+

定义数组的引用可能指向非连接存储。

dcl A ( 2 , 2 )   will allocates storage in the following order:
   +-------------+-------------+-------------+-------------+
   | A ( 1 , 1 ) | A ( 1 , 2 ) | A ( 2 , 1 ) | A ( 2 , 2 ) |
   +-------------+-------------+-------------+-------------+
 
dcl B ( 2 ) def A ( 1sub , 1sub )   refers to unconnected storage.
   +-------------+ - - - - - - + - - - - - - +-------------+
   | B ( 1 )     |                           | B ( 2 )     |
   | refers to   |            gap            | refers to   |
   | A ( 1 , 1 ) |                           | A ( 2 , 2 ) |
   +-------------+ - - - - - - + - - - - - - +-------------+

内置数组函数

[编辑 | 编辑源代码]

常用函数

  • LBOUND ( A , i ) 返回数组 A 的第 i 维度的下界。
  • HBOUND ( A , i ) 返回数组 A 的第 i 维度的上界。
  • DIM ( A , i ) 返回数组 A 的第 i 维度的范围,即 DIM ( A , i ) = HBOUND ( A , i ) - LBOUND ( A , i ) + 1。

数组 A 必须不是结构数组。

example: proc options ( main );
dcl   matrix ( 15 , -4:4 );
   put skip list ( LBOUND ( matrix , 1 ) );   /* output:  1 */
   put skip list ( HBOUND ( matrix , 1 ) );   /* output: 15 */
   put skip list (    DIM ( matrix , 1 ) );   /* output: 15 */
   put skip list ( LBOUND ( matrix , 2 ) );   /* output: -4 */
   put skip list ( HBOUND ( matrix , 2 ) );   /* output:  4 */
   put skip list (    DIM ( matrix , 2 ) );   /* output:  9 */
end example;

数学函数

  • SUM ( A ) 返回数组 A 中所有元素的总和。
  • PROD ( A ) 返回数组 A 中所有元素的乘积。
example: proc options ( main );
dcl   A ( 4 )   bin fixed (31)   init ( 1 , 2 , 3 , 4 );
   put skip list (  SUM ( A ) );   /* output: 10 = 1 + 2 + 3 + 4 */
   put skip list ( PROD ( A ) );   /* output: 24 = 1 × 2 × 3 × 4 */
end example;

逻辑函数
内置函数 ANY 和 ALL 需要位字符串数组作为参数。
它们将在Software_Engineers_Handbook/Language_Dictionary/PLI/bit_strings中解释。

在 PL/I for MVS 中,数组受到以下限制

  • 维度的最大数量为 15。
  • 最小下界为 - 2,147,483,648 = - 231
  • 最大上界为 + 2,147,483,647 = + 231 - 1。
  • 最大内存大小为 2,147,483,648 字节 = 231 字节。
华夏公益教科书