# Lecture 3

To review the elements of Pascal that we learned in this lecture (enumerated types, procedures, functions, recursions, variable scope), read the following sections of our Pascal Made Simple textbook:

• in chapter 3: “Defining types”

• chapter 4 (all sections)

In this lecture we mentioned bases other than 10, and one of our homework exercises uses them as well. If you are not familiar with writing numbers in different bases, please read this page:

At the end of the lecture I reviewed some basic properties of logarithms. We will be using logarithms a lot in this course. If you need to review them, you can do so here:

We will also soon be using limits, especially limits at infinity. If you need to review your knowledge of limits, please read these pages:

Here are a few more notes on various topics.

## array bounds

Remember that all dynamic arrays have indices starting with 0! If you call setLength(a, 100), you will end up with an array with indices from 0 to 99. A write to a[100] writes to unallocated memory, which could corrupt other program variables or cause a crash.

To guard against this, you can use the `{\$r+}` directive, which enables range checking. This has two consequences:

• On every array access a[i], the runtime checks that the index i is within the bounds of the array a. If it isn't, the program will terminate with an error.

• On every assignment to a variable whose type is a range (e.g. `var x: 5 .. 15`), the runtime checks that the value being assigned is in the range. If it isn't, the program will terminate with an error.

I recommend that you put this directive at the top of every program that uses arrays.

## random cards

This program prints five random cards, using an enumerated type to represent suits:

```type
suit = (club, diamond, heart, spade);

var
names: array[11..14] of string = ('jack', 'queen', 'king', 'ace');

rank: 2..14;
s: suit;
i: integer;

begin
randomize;

for i := 1 to 5 do
begin
rank := random(13) + 2;
s := suit(random(4));

case rank of
2..10: write(rank);
else write(names[rank]);
end;

writeln(' of ', s, 's');
end;
end.```

## ordinal types

Certain types are considered to be ordinal types: these include `boolean`, all integer types, `char`, and enumerated types. Values of ordinal types can be converted to/from integers. They can be used

• with comparison operators such as < and >

• as array indices

• in `case` statements

• as `for` loop variables

• with the `in` operator, which is used as follows:

`if c in ['A'..'Z'] then …`

## exit

The `exit` statement immediately exits the nearest enclosing procedure or function:

`exit;`

If there is no enclosing procedure or function, the program exits.

In a function, exit can take a parameter indicating a value to be returned from the function:

`exit(4);`

## recursion

A function can call itself; this is called recursion. Here is the factorial function, written recursively:

```function factorial(n: integer): integer;
begin
if n = 0 then
factorial := 1
else
factorial := n * factorial(n - 1);
end;```

We will take a deeper look at solving problems using recursion a bit later on in this course.

## working with digits

The last digit in the decimal number d is `d mod 10`. All digits except the last are `d div 10`. To retrieve digits in any other base b, use b instead of 10.

This program adds up all the decimal digits in a number:

```var
n: integer;
digits: integer = 0;

begin
readln(n);

while n > 0 do
begin
digits := digits + (n mod 10);
n := n div 10;
end;

writeln(digits);
end.```

### characters and digits

As we saw in the lecture 1, the `ord` function converts a character to its ASCII value, and the corresponding function `chr` converts an ASCII value to a character.

The ASCII code for ‘0’ is not zero, so if c is a character holding a digit, you cannot convert it to the corresponding numeric value by simply calling the `ord` function. Instead, you need to subtract the value of `ord('0')`:

`d := ord(c) – ord('0');`

Similarly, to convert a numeric value `d` to the corresponding digit character:

`c := chr(ord('0') + d);`

### converting an integer to a string

This program converts a number to binary (base 2) by retrieving one digit at a time and prepending the digits to a string:

```var
n: integer;
s: string = '';

begin
readln(n);
repeat
s := chr(ord('0') + (n mod 2)) + s;
n := n div 2;
until n = 0;
writeln(s);
end.```

### converting a string to an integer

The function below parses an integer n from a string s (just like the library function `strToInt`). It generates the integer using a technique known as Horner’s method, which works as follows. We use a variable n to store the value of the digits we have seen so far, initializing n to 0. We pass over the digits in the string from left to right, and each time we see a new digit, we multiply n by 10 (the decimal base) and add the value of the new digit.

For example, if the string s = “347”, the number n is generated as follows:

• 0 * 10 + 3 = 3

• 3 * 10 + 4 = 34

• 34 * 10 + 7 = 347

Here is the code:

```function toInt(s: string): integer;
var
n: integer = 0;
i: integer;

begin
for i := 1 to length(s) do
n := n * 10 + ord(s[i]) - ord('0');
toInt := n;
end;```

## searching in sorted arrays

In a sorted array of length n, all elements are in order:

a[0] ≤ a[1] ≤ a[2] ≤ … ≤ a[n]

Consider the problem of searching for an integer (called the “key”) in a sorted array a. Here is a naive sequential search:

```function iterative_search(const a: array of integer; key: integer): boolean;
var
i: integer;
begin
for i := low(a) to high(a) do
if a[i] = key then
exit(true);
exit(false);
end;```

A binary search will perform much better:

```function binary_search(const a: array of integer; key: integer): boolean;
var
lo, hi, mid: integer;
begin
lo := -1;
hi := length;
while hi – lo > 1 do
begin
mid := (lo + hi) div 2;
if a[mid] = key then
exit(true);
if a[mid] < key then
lo := mid;
else  // a[mid] > key
hi := mid;
end;
exit(false);
end;```

In a binary search, we use two variables lo and hi to keep track of the range of indices where the key might be found. To see how this function works, consider the following compound condition:

1. For all jlo, a[j] < key

2. For all jhi, a[j] > key

This condition is called a loop invariant. It is not written in code; it is a mathematical statement that helps us show that the program is correct. The invariant is true at the beginning, and remains true after each loop iteration:

• At the beginning, there are no array elements a[j] with jlo or jhi, so the condition is certainly true.

• If a[mid] < key, then we know that a[j] < key for any jmid. So we set lo := mid, and subcondition (1) remains true.

• Similarly, if a[mid] > key, then we know that a[j] > key for any jmid. So we set hi := mid, and subcondition (2) remains true.

Whenever hi – lo > 1 we keep looping, since we might have a[j] = key for some j in the range lo < j < hi. Eventually the loop may terminate with hi = lo + 1: at that point we can return false, since for all j either jlo or jhi, so by the loop invariant we have a[j] <> key for all j.