To review the material from this lecture, read the following sections of our Pascal Made Simple textbook:
in chapter 1 “Pascal essentials”: “Writing on screen”, “Constants”
in chapter 2 “Program flow”: “case branching”, “The unloved goto”
in chapter 3 “Arrays, strings, and sets”: “Arrays”, “Array dimensions”, “Defining types”
Here are a few more notes on various topics.
The program
element at the top of a Pascal program is
entirely optional in Free Pascal. I think that a comment describing
what the program does is more useful than a program
header in any case.
Pascal is completely case-insensitive. You can write
var j := 4; begin writeln(j + 1);
or
VAR J := 4; BEGIN WRITELN(J + 1);
or mix both styles within the same program.
I like writing keywords in lowercase and using function names that begin with a lowercase letter, so that's the style used in all examples in this course.
The Pascal Run-Time Library contains thousands of built-in functions that you can call. I've chosen several dozen of the most useful functions and listed them on a page called Run-Time Library Quick Reference. You will want to refer to this often when writing Pascal code for this class.
In Pascal, a function takes one or more arguments and returns a value. A procedure is like a function, but returns no value.
In the library quick reference, a function signature (i.e. the line of text indicating the function's name, parameter types and return type) looks like this:
function stringOfChar(c: char; n: integer) : string
This means that the function stringOfChar
takes two
parameters, a char
and an integer. It returns a string.
The names “c” and “n” appear in the function documentation
here, but you don't type them when calling the function. You can call
this function like this:
stringOfChar(4, 'm'); // returns 'mmmm'
Similarly, a procedure's signature looks like this:
procedure gotoXY(x: integer; y: integer)
Soon, we will learn to write our own functions and procedures in this course. When we do so, we will use the same syntax described here.
Free Pascal includes two statements break
and
continue
that can terminate the current iteration of a
loop. They were not in classic Pascal and are not covered in Pascal
Made Simple.
The break
statement breaks out of the nearest
enclosing for, while, or repeat loop.
Here is a program that looks for the letter 'x' in a string, and
terminates the search as soon as an 'x' is seen. It illustrates two
ways to accomplish this: one using break
and one
without.
// Search for the letter 'x' in a string. {$mode delphi} var s: string; i: integer; found: boolean; begin write('text: '); readln(s); // early exit without break i := 1; while (i <= length(s)) and (s[i] <> 'x') do i := i + 1; if i <= length(s) then found := true else found := false; // early exit with break found := false; for i := 1 to length(s) do if s[i] = 'x' then begin found := true; break; end; writeln(found); end.
The continue
statement continues with the next
iteration of the nearest enclosing for, while, or
repeat loop.
If continue
is executed during the last iteration of
a for
loop, the loop exits. When continue
is executed in a while
or repeat
loop, the
loop condition is tested before beginning a new iteration; if it is
false (for while
) or true (for repeat
) then
the loop exits.
The Pascal Made Simple book only discusses static arrays, which have a fixed size: they cannot grow or shrink as a program runs.
In this course we will also be using dynamic arrays. A dynamic array holds a variable number of elements and can grow or shrink as the program runs. You can declare a dynamic array like this:
var a: array of integer;
Before you can use a dynamic array, you must set its length by
calling setLength
:
setLength(a, 100);
Dynamic
arrays are always indexed from 0, so after the call above the array
will hold elements with indices from 0 to 99. When growing a dynamic
array, setLength
sets
any newly allocated elements to zero.
Like
static arrays, you can use the syntax a[i]
to
read from or write to a dynamic array:
a[44] := 33; a[44] := a[44] + 1;
Like static arrays, dynamic arrays can be multidimensional. Here's how to declare a multidimensional dynamic array:
var d: array of array of integer;
To set the dimensions of such an array, call setLength
and pass each dimension as a separate parameter:
setLength(d, 100, 20);
Like static arrays, you can access elements of a multidimensional
dynamic array using either of two syntaxes: a[i][j]
or
a[i, j]
.
Computers are incredibly fast. Below is a program that performs a billion integer additions and reports the time to perform one addition on average. By making small changes to this program, you can measure how long other operations take as well.
Recall that
1 ms = 1 millisecond = a thousandth of a second
1 μs = 1 microsecond = a millionth of a second
1 ns = 1 nanosecond = a billionth of a second
On my laptop, operations in Pascal take approximately this long in nanoseconds:
integer add |
0.3 |
integer multiply |
0.9 |
integer div |
11.5 |
integer mod |
11.3 |
floating-point add |
2.0 |
floating-point multiply |
2.0 |
floating-point division (/) |
3.5 |
{$mode delphi} uses dateutils, sysutils; const Iterations = 1000 * 1000 * 1000; var start, stop: TDateTime; x: integer; sum: integer; perIter: real; begin start := now(); sum := 0; for x := 1 to iterations do sum := sum + x; stop := now(); perIter := millisecondsBetween(start, stop) * 1000 * 1000 / Iterations; writeln(perIter:0:2, ' ns per iteration'); end.
Generally we don't have much use for goto, but it's interesting to
write a loop using it instead of for
or while
.
The Pascal compiler translates for
or while
loops into machine code that looks a lot like this.
label loop; var i: integer; begin i := 1; loop: writeln(i); i := i + 1; if i <= 10 then goto loop; end.
Here's a program that simulates throwing 2 6-sided dice a given number of times. It uses an array to keep track of the number of times that each outcome has been seen, and prints a histogram at the end.
var n: integer; roll, i: integer; count: array[2..12] of integer; begin randomize; write('how many throws? '); readln(n); for i := 2 to 12 do count[i] := 0; for i := 1 to n do begin roll := (random(6) + 1) + (random(6) + 1); count[roll] := count[roll] + 1; end; for i := 2 to 12 do writeln(i:2, ': ', stringOfChar('*', count[i])); end.
Here's a program
that tries to determine how much memory we can allocate using
setLength.
{$mode delphi} var a: array of integer; size: int64 = 1; begin while true do begin setLength(a, size); writeln('allocated ', size, ' elements'); size := size * 2; end; end.