COBOL 表与数组
COBOL 用 OCCURS 子句定义数组(称为”表”,Table),支持一维、二维及变长表。
目录
一维表(OCCURS)
二维表(嵌套 OCCURS)
下标与索引
变长表(DEPENDING ON)
表的初始化
查找表(SEARCH)
实战: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.
分析:
先清空整个网格
在食物坐标处标记 2
遍历蛇身每一节,标记 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.
分析: 遍历蛇身(除尾节外),检查新蛇头坐标是否与身体重合。
上一章: 过程部与语句 下一章: 文件处理