Chapter 8 Exercises
Part A: Scope Tracing (Conceptual)
Exercise A.1 — What Will This Print?
Trace through the following program and predict the exact output.
program TraceA1;
var
A: Integer;
procedure Modify;
var
A: Integer;
begin
A := 99;
WriteLn('Modify: A = ', A);
end;
begin
A := 1;
WriteLn('Before: A = ', A);
Modify;
WriteLn('After: A = ', A);
end.
Exercise A.2 — Scope Levels
For each variable in the program below, state its scope level and list all the blocks where it is visible.
program ScopeExercise;
var
X: Integer;
procedure Alpha;
var
Y: Integer;
procedure Beta;
var
Z: Integer;
begin
{ Block Beta }
end;
begin
{ Block Alpha }
end;
procedure Gamma;
var
W: Integer;
begin
{ Block Gamma }
end;
begin
{ Main block }
end.
Exercise A.3 — Legal or Illegal?
For each statement below, state whether it would cause a compile error if placed at the indicated location. Explain why.
program LegalOrNot;
var
G: Integer;
procedure P;
var
L: Integer;
procedure Q;
var
M: Integer;
begin
{ Location 1: G := 10; }
{ Location 2: L := 20; }
{ Location 3: M := 30; }
end;
begin
{ Location 4: G := 10; }
{ Location 5: L := 20; }
{ Location 6: M := 30; }
end;
begin
{ Location 7: G := 10; }
{ Location 8: L := 20; }
{ Location 9: M := 30; }
end.
Exercise A.4 — Shadowing Detective
The following program compiles without error but produces surprising output. Identify every instance of shadowing and explain how each affects the output.
program ShadowDetective;
var
X: Integer;
Y: Integer;
procedure One;
var
X: Integer;
begin
X := 100;
Y := 200;
WriteLn('One: X=', X, ' Y=', Y);
end;
procedure Two;
var
Y: Integer;
begin
Y := 300;
WriteLn('Two: X=', X, ' Y=', Y);
end;
begin
X := 1;
Y := 2;
WriteLn('Start: X=', X, ' Y=', Y);
One;
WriteLn('After One: X=', X, ' Y=', Y);
Two;
WriteLn('After Two: X=', X, ' Y=', Y);
end.
Exercise A.5 — Nested Scope Chain
Trace the following program and show the value of every variable at each WriteLn statement. Draw the scope diagram.
program NestedTrace;
var
A: Integer;
procedure Level1;
var
B: Integer;
procedure Level2;
var
C: Integer;
begin
C := A + B;
WriteLn('Level2: A=', A, ' B=', B, ' C=', C);
A := A + 10;
end;
begin
B := A * 2;
WriteLn('Level1 before: A=', A, ' B=', B);
Level2;
WriteLn('Level1 after: A=', A, ' B=', B);
end;
begin
A := 5;
Level1;
WriteLn('Main: A=', A);
end.
Part B: Call Stack Tracing
Exercise B.1 — Stack Snapshots
For the following program, draw the call stack at the point marked { *** HERE *** }. Show every frame and the values of all local variables and parameters in each frame.
program StackExercise;
function Square(N: Integer): Integer;
begin
Square := N * N;
{ *** HERE *** }
end;
function SumOfSquares(A, B: Integer): Integer;
var
SA, SB: Integer;
begin
SA := Square(A);
SB := Square(B);
SumOfSquares := SA + SB;
end;
begin
WriteLn(SumOfSquares(3, 4));
end.
Note: Draw the stack for the first call to Square (when A = 3).
Exercise B.2 — Return Addresses
Using the program from B.1, explain in plain English where execution resumes after each of these returns:
1. The first call to Square returns.
2. The second call to Square returns.
3. SumOfSquares returns.
Exercise B.3 — Recursive Stack
Draw the complete call stack when the following program reaches the base case (when N = 1):
program RecursiveStack;
function Factorial(N: Integer): Integer;
begin
if N <= 1 then
Factorial := 1
else
Factorial := N * Factorial(N - 1);
end;
begin
WriteLn(Factorial(4));
end.
Show every frame, including the value of N in each.
Exercise B.4 — Stack Depth
A procedure A calls procedure B, which calls procedure C, which calls procedure D. What is the maximum number of stack frames on the stack at any point during execution (including main)? What is the minimum number of frames when D is executing?
Exercise B.5 — Stack Overflow Prediction
The following recursive function has no base case. How many stack frames would approximately be created before a stack overflow occurs if the default Free Pascal stack size is 8 MB and each frame uses approximately 32 bytes?
function Forever(N: Integer): Integer;
begin
Forever := Forever(N + 1);
end;
Part C: Parameter Passing
Exercise C.1 — Predict the Output
program ParamPredict;
procedure Mystery(A: Integer; var B: Integer; const C: Integer);
begin
A := A + 10;
B := B + 10;
{ C := C + 10; } { Would this compile? Why or why not? }
WriteLn('Inside: A=', A, ' B=', B, ' C=', C);
end;
var
X, Y, Z: Integer;
begin
X := 1;
Y := 2;
Z := 3;
Mystery(X, Y, Z);
WriteLn('Outside: X=', X, ' Y=', Y, ' Z=', Z);
end.
Exercise C.2 — Fix the Bug
This program is supposed to swap two integers, but it does not work. Fix it.
program BrokenSwap;
procedure Swap(A, B: Integer);
var
Temp: Integer;
begin
Temp := A;
A := B;
B := Temp;
end;
var
X, Y: Integer;
begin
X := 10;
Y := 20;
Swap(X, Y);
WriteLn('X = ', X, ' Y = ', Y);
end.
Exercise C.3 — Which Parameter Mode?
For each scenario, state which parameter mode (value, var, or const) is most appropriate and explain why.
- A procedure that prints a student's name (a string).
- A procedure that reads an integer from the user and stores it in a variable.
- A function that calculates the area of a rectangle given its width and height.
- A procedure that sorts an array in place.
- A procedure that counts the number of vowels in a string and returns the count.
Exercise C.4 — Memory Diagrams
Draw a memory diagram showing the stack frames for the following code at the point where Triple is executing. Show the parameter storage (copy vs. address) for each parameter.
program MemoryDiagram;
procedure Triple(const Input: Integer; var Output: Integer);
begin
Output := Input * 3;
end;
var
A, B: Integer;
begin
A := 7;
B := 0;
Triple(A, B);
end.
Exercise C.5 — Const Protection
Write a short program that demonstrates the compiler catching an attempt to modify a const parameter. Show the exact error message produced by Free Pascal.
Part D: Program Design
Exercise D.1 — Eliminate Globals
Rewrite the following program so that it uses NO global variables (except in the main block). All data must flow through parameters.
program GlobalHeavy;
var
Width, Height: Integer;
Area, Perimeter: Integer;
procedure ReadDimensions;
begin
Write('Width: ');
ReadLn(Width);
Write('Height: ');
ReadLn(Height);
end;
procedure Calculate;
begin
Area := Width * Height;
Perimeter := 2 * (Width + Height);
end;
procedure Display;
begin
WriteLn('Area: ', Area);
WriteLn('Perimeter: ', Perimeter);
end;
begin
ReadDimensions;
Calculate;
Display;
end.
Exercise D.2 — Nested Helper Design
Write a procedure called PrintReport that takes a student's name (string), three exam scores (integers), and displays the name, each score, the average, and the letter grade. The average calculation and grade determination should be nested helper functions inside PrintReport since they are not needed elsewhere.
Exercise D.3 — Parameter Mode Audit
For each procedure and function header below, identify any parameter mode mistakes and suggest corrections:
{ 1 } procedure ReadName(Name: String);
{ 2 } function ComputeMax(var A, B: Integer): Integer;
{ 3 } procedure PrintArray(var Arr: array of Integer; var Size: Integer);
{ 4 } procedure InitializeArray(const Arr: array of Integer; Size: Integer);
{ 5 } function IsPositive(var N: Integer): Boolean;
Exercise D.4 — Call Stack for Recursion
Write a recursive function Power(Base, Exp: Integer): Integer that computes Base raised to the Exp power. Then trace the call stack for Power(2, 4), showing every frame at maximum depth.
Exercise D.5 — Scope Architecture
Design the scope architecture (but do not implement) a small library catalog program. List all procedures/functions, their parameters (with modes), which should be nested inside others, and which variables (if any) should be global. Justify each decision.
Part E: Challenge Problems
Exercise E.1 — Mutual Recursion and Scope
Write two procedures, IsEven and IsOdd, that determine whether a non-negative integer is even or odd using mutual recursion (no use of mod). IsEven(0) returns True. IsOdd(0) returns False. IsEven(N) calls IsOdd(N-1). IsOdd(N) calls IsEven(N-1). You will need a forward declaration. Trace the call stack for IsEven(3).
Exercise E.2 — Stack Frame Size Estimation
Write a program with a recursive procedure that declares a local array of 1000 integers. Call it recursively and determine approximately how many recursive calls can be made before a stack overflow. Calculate the approximate stack frame size from your results.
Exercise E.3 — Scope Chain Depth
Write a program with four levels of procedure nesting (a procedure inside a procedure inside a procedure inside a procedure). Each level should declare one local variable and modify a variable from every enclosing level. Trace the execution and draw the complete scope chain diagram.
Exercise E.4 — Parameter Passing Benchmark
Write a program that passes a large array (10,000 integers) to a function, once as a value parameter and once as a const parameter. Use the GetTickCount64 function from the SysUtils unit to measure the time difference. Explain why one is faster.
Exercise E.5 — Call Stack Visualization
Write a program containing a recursive procedure that prints a visual representation of the call stack at each level of recursion. Use indentation to show depth. For example, for Recurse(3):
Entering Recurse(3) - Stack depth: 1
Entering Recurse(2) - Stack depth: 2
Entering Recurse(1) - Stack depth: 3
Leaving Recurse(1)
Leaving Recurse(2)
Leaving Recurse(3)
Part M: Mastery — Integrative Challenges
Exercise M.1 — Scope Refactoring
You are given the following 80-line program that works correctly but has terrible scope design (excessive globals, shadowing, hidden dependencies). Refactor it to use proper scope management without changing its visible behavior.
program MessyScope;
var
Items: array[1..100] of Integer;
Count: Integer;
Total: Integer;
Average: Real;
I: Integer;
procedure LoadData;
begin
Count := 5;
Items[1] := 10;
Items[2] := 20;
Items[3] := 30;
Items[4] := 40;
Items[5] := 50;
end;
procedure ComputeStats;
begin
Total := 0;
for I := 1 to Count do
Total := Total + Items[I];
Average := Total / Count;
end;
procedure PrintResults;
begin
WriteLn('Items: ');
for I := 1 to Count do
WriteLn(' ', Items[I]);
WriteLn('Count: ', Count);
WriteLn('Total: ', Total);
WriteLn('Average: ', Average:0:2);
end;
begin
LoadData;
ComputeStats;
PrintResults;
end.
Your refactored version must:
- Have no global variables except the array and count (which are shared program state)
- Pass all other data through parameters
- Use appropriate parameter modes (value, var, const)
- Declare loop variables locally
- Include at least one nested subprogram
Exercise M.2 — PennyWise Scope Report
Write a 200-word analysis of your PennyWise project checkpoint's scope design. For each procedure and function, state: 1. Why you chose the parameter mode you did 2. Whether any globals are accessed and whether that is justified 3. The maximum call stack depth during a typical user session
Exercise M.3 — Cross-Language Scope Comparison
Choose one of the following scope-related behaviors and write a short essay (300–500 words) explaining how it works in Pascal versus one other language of your choice: - Variable shadowing - Parameter passing by reference - Nested function scope access (closures) - Variable lifetime vs. scope