COBOL COBOL 2014 (ISO/IEC 1989:2014), built with GnuCOBOL 3.x ยท
โ verified by execution on 2026-08-16
When working with complex data, a single list of items is often not enough. You might need to represent a grid, a coordinate system, or a matrix. In many modern programming languages, you would create a 2D array by defining an array of arrays or using syntax like int[][] grid. COBOL approaches this differently due to its hierarchical memory structure.
To create a multi-dimensional table in COBOL, you do not define multiple dimensions on a single line. Instead, you nest OCCURS clauses across different group levels.
Defining a Multi-Dimensional Table
In COBOL, you create a 2D table by defining a group item with an OCCURS clause, and then placing another OCCURS clause on a subordinate item within that group. When the compiler sees this, it multiplies the occurrences to reserve a single, contiguous block of memory.
If you look closely at the data division, T-COL is nested inside T-ROW. Since T-ROW occurs 2 times, and T-COL occurs 2 times within each row, the compiler reserves memory for a total of 4 CELL items.
Because OCCURS cannot be used on an 01 level item, the multi-dimensional structure must always begin at a subordinate level (like 05). You can nest up to 7 dimensions in standard COBOL, though anything beyond 3 dimensions is rarely seen in practice.
Memory Layout
Under the hood, COBOL stores this 2D table sequentially. There are no pointers or separate objects. The data is laid out strictly row-by-row in memory.
When you access CELL(2 1), the compiler simply calculates the offset: it jumps past the entire first T-ROW, then accesses the first T-COL within the second row. If you try to access a boundary outside the declared OCCURS (such as CELL(3 1)), COBOL calculates the offset as if the third row existed. Without boundary checks enabled during compilation, this will silently read or corrupt the adjacent memory immediately following the table.
Accessing Data with Subscripts
In C-family languages, you might access a 2D array by chaining brackets, like array[1][2]. In COBOL, all subscripts for a multi-dimensional table are grouped together inside a single set of parentheses.
The subscripts correspond directly to the nested OCCURS levels, reading from the outermost group to the innermost.
Predict the outputcobol
Read the code. What exactly will it print? Commit to an answer before you look.
IDENTIFICATION DIVISION. PROGRAM-ID. INDEX-2D. DATA DIVISION. WORKING-STORAGE SECTION. 01 GRID. 05 T-ROW OCCURS 2 TIMES INDEXED BY R-IDX. 10 T-COL OCCURS 2 TIMES INDEXED BY C-IDX. 15 CELL PIC 9. PROCEDURE DIVISION. MOVE 5 TO CELL(1 1). MOVE 6 TO CELL(1 2). MOVE 7 TO CELL(2 1). MOVE 8 TO CELL(2 2). SET R-IDX TO 2 SET C-IDX TO 1 DISPLAY "VAL: " CELL(R-IDX C-IDX) STOP RUN.
Output
VAL: 7
You predicted
Notice that the subscripts must be separated by at least one space, for example: CELL(1 2). Modern compilers might forgive a comma (CELL(1, 2)), but standard COBOL syntax dictates the space. You can use numeric literals, variables, or indexes (via INDEXED BY) just as you would with a 1-dimensional table.
Iterating Over Multi-Dimensional Tables
To process every element in a multi-dimensional table, you simply nest PERFORM VARYING loops. The outer loop will iterate through the rows, while the inner loop iterates through the columns.
cobolโ verified output
IDENTIFICATION DIVISION. PROGRAM-ID. SUM-2D. DATA DIVISION. WORKING-STORAGE SECTION. 01 GRID. 05 T-ROW OCCURS 2 TIMES. 10 T-COL OCCURS 2 TIMES. 15 CELL PIC 9. 01 I PIC 9 VALUE 1. 01 J PIC 9 VALUE 1. 01 TOTAL PIC 99 VALUE 0. PROCEDURE DIVISION. MOVE 1 TO CELL(1 1). MOVE 2 TO CELL(1 2). MOVE 3 TO CELL(2 1). MOVE 4 TO CELL(2 2). PERFORM VARYING I FROM 1 BY 1 UNTIL I > 2 PERFORM VARYING J FROM 1 BY 1 UNTIL J > 2 ADD CELL(I J) TO TOTAL END-PERFORM END-PERFORM DISPLAY "TOTAL: " TOTAL STOP RUN.
Output
TOTAL: 10
Your output
Because the memory is completely contiguous, iterating row-by-row perfectly matches the way the data lies in memory. This is generally the most cache-friendly and performant way to traverse large COBOL tables.
Check yourself
How do you declare a multi-dimensional table in COBOL?
Reveal answer
By nesting OCCURS clauses within subordinate group levels. โ COBOL requires you to nest OCCURS clauses. A subordinate level (e.g., 10) with an OCCURS clause inside a group level (e.g., 05) that also has an OCCURS clause creates a multi-dimensional table.
Which of the following is the correct syntax for accessing an element in a 2D COBOL table?
Reveal answer
CELL(1 2) โ COBOL requires subscripts to be inside a single set of parentheses and separated by spaces, like CELL(1 2). While some modern compilers allow commas followed by spaces, the standard format is space-separated.
What happens in GnuCOBOL by default (without boundary check flags) if you access a table element outside of its declared OCCURS size?
Reveal answer
It silently corrupts adjacent memory. โ By default, COBOL allocates a contiguous block of memory for tables. Out-of-bounds access simply calculates an offset into adjacent memory, silently reading from or overwriting it.
Challenges
๐ Bug Hunt+20 XP
Fix the table definition so that it correctly defines a 2-dimensional grid. Currently, both dimensions are defined at the same level.
This code runs. It just does the wrong thing. Read it, find the defect,
fix it โ the tests below decide when you are right.
cobolโ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real โ it came from compiling the solution with GnuCOBOL when this page
was built.
Fix the subscript syntax used to access the 2D table. The program currently fails to compile.
This code runs. It just does the wrong thing. Read it, find the defect,
fix it โ the tests below decide when you are right.
cobolโ solution verified at build time
COBOL has no in-browser runtime, so this one is pen-and-paper: work out what the
fixed code should be, then open the solution and compare. The expected output
below is real โ it came from compiling the solution with GnuCOBOL when this page
was built.