The data structure used to enable efficient access to non-local variables in block-structured languages that support nested procedures (such as Pascal or Ada) is the display. A display is an array of pointers to activation records, where each entry corresponds to a static nesting level. If the maximum static depth of nesting in a program is $ d $, then the display is an array $ \text{display}[0 \ldots d] $ such that:
$$
\text{display}[i] = \text{pointer to the activation record of the most recent invocation at static level } i.
$$
When a procedure executing at static level $ k $ needs to access a variable defined at an outer static level $ i < k $, it retrieves the variable using:
$$
\text{display}[i] + \text{offset of variable}.
$$
This mechanism provides $ O(1) $ access time to non-local variables, regardless of how deeply nested the current procedure is in the call chain.
Consider the following program structure:
- Program $ \text{Main} $ (static level 0) declares variable $ a $.
- Procedure $ P $ (static level 1) declares variable $ b $.
- Procedure $ Q $, nested inside $ P $ (static level 2), executes the statement $ a := a + b $.
During execution of $ Q $, the display contains:
- $ \text{display}[0] $ pointing to $ \text{Main} $'s activation record,
- $ \text{display}[1] $ pointing to $ P $'s activation record,
- $ \text{display}[2] $ pointing to $ Q $'s own activation record.
Thus, $ Q $ accesses $ a $ via $ \text{display}[0] $ and $ b $ via $ \text{display}[1] $, without traversing a static link chain.
Other options are unsuitable:
- The stack holds activation records but does not by itself support direct indexed access to outer scopes.
- The heap is used for dynamically allocated data, not for lexical scoping.
- The activation tree is a conceptual model of procedure calls, not a runtime data structure.
Therefore, the correct answer is:
$$
\color{hotpink} \boxed{\text{C. display}}
$$