7.3 Arrays, Lookup Tables, and Strings
Section 7.2 built loops and state transitions without specifying what data they traverse. We now connect control flow to consecutive memory. The processor sees only addressed bytes; an array, table, or string exists because the program follows a layout contract.
An array is a base address plus equal-width elements
An array stores a fixed number of elements of the same width in consecutive memory. Its three essential facts are:
- The base address of element 0.
- The element width in bytes.
- The element count, which determines the valid index range.
For zero-based index , the byte address is:
An 8086 effective-address expression can add a base register, an index register, and a displacement, but it has no general scaled-index term. A byte array needs no scaling. A word-array index must first be doubled, often in a scratch register:
; SI is an element index from 0 through count-1
CMP SI,count
JAE out_of_bounds
MOV BX,SI
SHL BX,1
MOV AX,word_array[BX]If a word array begins at 1000H, index 3 begins at 1006H. A stored BEEFH occupies EFH at 1006H and BEH at 1007H; the processor reconstructs the word using little-endian order.
The address itself carries no boundary information. Reading index 8 from a six-element array does not trigger an “array error” in the 8086. It simply reads whatever bytes happen to follow. The program must compare the index with the element count before access.
A lookup table replaces repeated decisions with data
A lookup table stores precomputed outputs indexed by a small input. Instead of comparing a digit against ten cases, a display routine can use the digit directly to select a seven-segment code.
For a byte table at DS:BX, the 8086 XLAT instruction uses unsigned AL as an index, reads DS:[BX+AL], and replaces AL with that byte. The instruction is compact, but it performs no bounds check:
; AL must be a digit from 0 through 9
CMP AL,10
JAE invalid_digit
MOV BX,OFFSET seven_segment
XLATA table makes policy visible as data. Changing the code for digit 6 means changing one table entry, not repairing several branches. It also creates a clear test boundary: every legal index should map to its expected byte, while the first illegal index must take the rejection path.
A string needs a stopping contract
A string is a sequence of character codes. Chapter 2 introduced ASCII; here each ASCII character occupies one byte. Memory still does not record where the sequence ends, so the program needs one of two common contracts:
- A counted string carries a separate length. All byte values, including 00H, may be data.
- A terminated string reserves a special sentinel byte, often 00H, to mark the end. The sentinel cannot also represent an ordinary character inside that string.
A bounded search can use both a terminator and a maximum count:
; DS:BX points to bytes, AL is target, CX is maximum readable length
XOR SI,SI
search:
JCXZ not_found
MOV DL,[BX+SI]
CMP DL,0
JE not_found
CMP DL,AL
JE found
INC SI
DEC CX
JMP searchThe zero byte handles a normal shorter string. CX handles corrupted or untrusted data whose terminator is missing. Either condition can stop the loop before SI leaves the approved region.
Boundary cases define the contract:
- A counted empty string has length zero and must not read its first address.
- A terminated empty string begins with 00H and is finished after that one sentinel read.
- A missing target ends at the length or sentinel, not at an arbitrary later match in unrelated memory.
- A copy needs enough destination capacity, including the terminator if the format requires one.
Arrays and strings turn addresses into structured data only when code preserves width, count, and termination rules. Section 7.4 applies the same idea to another memory structure: the stack layout shared by callers and procedures.