返回首页

COBOL 表与数组

COBOL 表与数组

COBOL 用 OCCURS 子句定义数组(称为”表”,Table),支持一维、二维及变长表。

目录

  1. 一维表(OCCURS)
  2. 二维表(嵌套 OCCURS)
  3. 下标与索引
  4. 变长表(DEPENDING ON)
  5. 表的初始化
  6. 查找表(SEARCH)
  7. 实战:snake.cob 的网格与蛇身

1. 一维表(OCCURS)

用 OCCURS n TIMES 定义重复元素:

1
2
01 WS-SCORES.
05 WS-SCORE OCCURS 10 TIMES PIC 9(3).

这定义了一个包含 10 个元素的数组,每个元素是 3 位数字。

带子项的表

1
2
3
4
5
01 WS-STUDENTS.
05 WS-STUDENT OCCURS 30 TIMES.
10 WS-STU-NAME PIC X(20).
10 WS-STU-AGE PIC 9(2).
10 WS-STU-GRADE PIC 9(3).

每个 WS-STUDENT 是一个组合项,包含姓名、年龄、成绩。

访问元素

1
2
3
MOVE 95 TO WS-SCORE(1).        *> 第 1 个元素
MOVE 88 TO WS-SCORE(5). *> 第 5 个元素
DISPLAY WS-STU-NAME(3). *> 第 3 个学生的姓名

注意: COBOL 数组下标从 1 开始,不是 0!


2. 二维表(嵌套 OCCURS)

通过嵌套 OCCURS 实现多维数组:

1
2
3
01 WS-GRID.
05 WS-ROW OCCURS 12 TIMES.
10 WS-CELL OCCURS 20 TIMES PIC 9.

这定义了一个 12 行 × 20 列的二维表。

访问二维元素

1
2
MOVE 1 TO WS-CELL(3, 5).       *> 第 3 行第 5 列
MOVE 2 TO WS-CELL(WS-FOOD-Y, WS-FOOD-X).

下标顺序: WS-CELL(行, 列),即外层 OCCURS 在前,内层在后。

遍历二维表

1
2
3
4
5
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 12
PERFORM VARYING WS-J FROM 1 BY 1 UNTIL WS-J > 20
MOVE 0 TO WS-CELL(WS-I, WS-J)
END-PERFORM
END-PERFORM.

3. 下标与索引

下标(Subscript)

用普通数值变量或字面量作为下标:

1
2
3
01 WS-IDX PIC 9(3).
MOVE 5 TO WS-IDX.
DISPLAY WS-SCORE(WS-IDX).

索引(Index)

用 INDEXED BY 声明专用索引,性能更好:

1
2
3
01 WS-TABLE.
05 WS-ITEM OCCURS 100 TIMES
INDEXED BY WS-IDX PIC X(10).

索引操作:

1
2
3
4
SET WS-IDX TO 1.
PERFORM VARYING WS-IDX FROM 1 BY 1 UNTIL WS-IDX > 100
DISPLAY WS-ITEM(WS-IDX)
END-PERFORM.
  • SET 索引 TO 值:设置索引
  • SET 索引 UP BY 1:递增
  • SET 索引 DOWN BY 1:递减

下标 vs 索引

特性 下标 索引
声明 普通数值变量 INDEXED BY
赋值 MOVE SET
性能 需计算偏移 直接偏移,更快
适用 简单场景 大表、频繁访问

4. 变长表(DEPENDING ON)

用 OCCURS n TIMES DEPENDING ON 变量 定义长度可变的表:

1
2
3
4
5
01 WS-SNAKE.
05 WS-SEG OCCURS 240 TIMES.
10 WS-SX PIC 9(2).
10 WS-SY PIC 9(2).
01 WS-SNAKE-LEN PIC 9(3) VALUE 3.

虽然 snake.cob 用的是固定长度,但变长表写法如下:

1
2
3
4
5
01 WS-DATA.
05 WS-ITEM OCCURS 1 TO 100 TIMES
DEPENDING ON WS-COUNT.
10 WS-VALUE PIC 9(5).
01 WS-COUNT PIC 9(3).

要点:

  • DEPENDING ON 变量必须在表之前声明
  • 实际有效元素数为 WS-COUNT
  • 遍历时用 UNTIL WS-K > WS-COUNT

5. 表的初始化

用 VALUE 初始化(仅限单元素)

1
2
3
 01 WS-FLAGS.
05 WS-FLAG OCCURS 5 TIMES PIC X VALUE "N".
*> 所有 5 个元素都初始化为 "N"

用循环初始化

1
2
3
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 10
MOVE 0 TO WS-SCORE(WS-I)
END-PERFORM.

用 INITIALIZE 语句

1
2
 INITIALIZE WS-STUDENTS.
*> 将所有数值项置零,字符项置空格

用 MOVE 整体填充

1
2
 MOVE SPACES TO WS-STUDENTS.
*> 将整个组合项填充为空格

6. 查找表(SEARCH)

SEARCH 用于在表中查找满足条件的元素。

顺序查找(SEARCH)

1
2
3
4
5
6
7
8
9
10
11
12
13
01 WS-TABLE.
05 WS-ENTRY OCCURS 100 TIMES
INDEXED BY WS-IDX.
10 WS-KEY PIC X(10).
10 WS-VALUE PIC 9(5).
01 WS-TARGET PIC X(10).

SET WS-IDX TO 1
SEARCH WS-ENTRY
AT END DISPLAY "未找到"
WHEN WS-KEY(WS-IDX) = WS-TARGET
DISPLAY "找到: " WS-VALUE(WS-IDX)
END-SEARCH.

二分查找(SEARCH ALL)

要求表已排序,性能为 O(log n):

1
2
3
4
5
SEARCH ALL WS-ENTRY
AT END DISPLAY "未找到"
WHEN WS-KEY(WS-IDX) = WS-TARGET
DISPLAY "找到: " WS-VALUE(WS-IDX)
END-SEARCH.

注意: SEARCH ALL 要求表用 ASCENDING KEY 或 DESCENDING KEY 声明排序键。


7. 实战:snake.cob 的网格与蛇身

网格结构

1
2
3
4
*> ---- 网格: 0=空 1=蛇身 2=食物 ----
01 WS-GRID.
05 WS-ROW OCCURS 12 TIMES.
10 WS-CELL OCCURS 20 TIMES PIC 9.

用途: 12×20 的二维表,每个格子存储状态(0=空,1=蛇身,2=食物)。

构建网格

1
2
3
4
5
6
7
8
9
10
BUILD-GRID.
PERFORM VARYING WS-I FROM 1 BY 1 UNTIL WS-I > 12
PERFORM VARYING WS-J FROM 1 BY 1 UNTIL WS-J > 20
MOVE 0 TO WS-CELL(WS-I, WS-J)
END-PERFORM
END-PERFORM
MOVE 2 TO WS-CELL(WS-FOOD-Y, WS-FOOD-X)
PERFORM VARYING WS-K FROM 1 BY 1 UNTIL WS-K > WS-SNAKE-LEN
MOVE 1 TO WS-CELL(WS-SY(WS-K), WS-SX(WS-K))
END-PERFORM.

分析:

  1. 先清空整个网格
  2. 在食物坐标处标记 2
  3. 遍历蛇身每一节,标记 1

蛇身坐标数组

1
2
3
4
5
6
*> ---- 蛇的坐标数组 (最多 240 节, 索引1=头) ----
01 WS-SNAKE.
05 WS-SEG OCCURS 240 TIMES.
10 WS-SX PIC 9(2).
10 WS-SY PIC 9(2).
01 WS-SNAKE-LEN PIC 9(3) VALUE 3.

用途: 存储蛇每一节的 (x, y) 坐标,索引 1 是蛇头。

蛇身移动(数组平移)

1
2
3
4
5
6
7
8
9
10
11
*>    身体依次后移, 新坐标作为蛇头
MOVE 1 TO WS-I
PERFORM UNTIL WS-I >= WS-SNAKE-LEN
COMPUTE WS-K = WS-SNAKE-LEN - WS-I + 1
COMPUTE WS-J = WS-K - 1
MOVE WS-SX(WS-J) TO WS-SX(WS-K)
MOVE WS-SY(WS-J) TO WS-SY(WS-K)
ADD 1 TO WS-I
END-PERFORM
MOVE WS-NEW-X TO WS-SX(1)
MOVE WS-NEW-Y TO WS-SY(1).

分析: 从尾部向头部遍历,每节坐标后移一位(WS-SEG[k] = WS-SEG[k-1]),最后把新坐标写入蛇头 WS-SEG[1]。

碰撞检测(遍历数组)

1
2
3
4
5
6
7
8
*>    撞自己检测 (尾节将移走, 只查前 LEN-1 节)
PERFORM VARYING WS-K FROM 1 BY 1
UNTIL WS-K > WS-SNAKE-LEN - 1 OR WS-RUNNING = 0
IF WS-SX(WS-K) = WS-NEW-X AND WS-SY(WS-K) = WS-NEW-Y
MOVE "撞到自己" TO WS-END-REASON
MOVE 0 TO WS-RUNNING
END-IF
END-PERFORM.

分析: 遍历蛇身(除尾节外),检查新蛇头坐标是否与身体重合。


上一章: 过程部与语句
下一章: 文件处理