Pascal Programming/Arrays

An array is a structure concept for custom data types. It groups elements of the same data type. You will use arrays a lot if you are dealing with lots of data of the same data type.

Notion
In general, an array is a limited and arranged aggregation of objects, all of which having the same data type called base type or component type. An array has at least one discrete, bounded dimension, continuously enumerating all its objects. Each object can be uniquely identified by one or more scalar values, called indices, along those dimensions.

Declaration
In Pascal an array data type is declared using the reserved word  in combination with the auxiliary reserved word , followed by the array’s base type: Behind the word  follows a non-empty comma-separated list of dimensions surrounded by brackets. All array’s dimensions have to be ordinal data types, yet the base type type can be of any kind. If an array has just one dimension, like the one above, we may also call it a list.

Access
A variable of the data type  as declared above, holds five independent   values. Accessing them follows a specific scheme: This  will print , since it is the value of   that has the index value. Arrays are like a series of “buckets” each holding one of the base data type’s values. Every bucket can be identified by a value according to the dimension specifications. When referring to one of the buckets, we have to name the group, that is the variable name (in this case ), and a proper index surrounded by brackets.

Character array
Lists of characters frequently have and had special support with respect to I/O and manipulation. This section is primarily about understanding, as in the next chapter we will get to know a more sophisticated data type called.

Direct assignment
String literals can be assigned to variables using an assignment statement, thus instead of writing: You can simply write: Note, that you do not need to specify any index anymore. You are referring to the entire array variable on the LHS of the assignment symbol. This only works for overwriting the values of the whole array. There are extensions allowing you to overwrite merely parts of a  array, but more on that in the next chapter.

Most implementations of string literal to  array assignments will pad the given string literal with insignificant   values if it is shorter than the variable’s capacity. Padding a string means to fill the remaining positions with other characters in order meet a certain size. The GPC uses space characters, whereas the FPC uses  values whose  inal value is zero.

Reading and printing
Although not standardized, /  and  /  usually support writing to and reading from  variables.

Very early Pascal compilers supported only this kind of human-readable IO:

This works because  files, like the standard files   and , are understood to be infinite sequences of   values. Since our is also, although finite sequence of   values, individual values can be copied pretty much directly to and from   files, not requiring any kind of conversion.

Primitive comparison
Unlike other arrays, variables can be compared using   and. This kind of comparison only works as expected for identical data types. It is a primitive character-by-character comparison. If either array is longer or shorter, an  comparison will always fail, because not all characters can be compared to each other. Correspondingly, an  comparison will always succeed for  values that differ in length.

Note, the EP standard also defines the undefined and undefined functions, beside many more. The difference to  and   is that blank padding (i.&#8239;e.   in FPC or  in GPC) has no significance in   and. In consequence, that means using these functions you can compare strings and  arrays regardless of their respective maximum capacity and still get the naturally expected result. The  and   comparisons on the other hand look at the memory’s internal representation.

Matrices
An array’s base type can be any data type, even another array. If we want to declare an “array of arrays” there is a short syntax for that: This has already been described above. The last line is identical to: It can be expanded to two separate declarations allowing us to “re-use” the “inner” array data type: Note that in the latter case  uses   as the base type which is an array by itself. Yet in the short notation we specify  as the base type, not a   but its base type.

When an array was declared to contain another array, there is a short notation for accessing individual array items, too: This corresponds to the array’s declaration. It is vital to ensure the indices you are specifying are indeed valid. In the latter loop the  branch checks for that. Attempting to access non-existent array values, i.&#8239;e. by supplying illegal indices, may crash the program, or worse remain undetected thus causing difficult to find mistakes.

Note, the “unusual” order of  and   has been chosen to facilitate drawing an upright graph: That means, it is still possible to refer to entire “sub”-arrays as a whole. You are not forced to write all dimension an array value has, given it makes sense.

Array data types that have exactly two dimensions are also called matrices, singular matrix.

Real values
As introduced in one of the first chapters the data type  is part of the Pascal programming language. It is used to store integer values in combination with an optional fractional part.

Real literals
In order to distinguish  literals from   literals, specifying   values in your source code (and also for  / ) differs slightly. The following source code excerpt shows some  literals: To summarize the rules:
 * A  value literal always contains either a   as a radix mark, or an  /  to separate an exponent (the $$x$$ in $$\text{…} \times 10^{x}$$), or both.
 * There is at least one Western-Arabic decimal digit before and one after the  (if there is any).
 * The entire number and exponent are preceded by signs, yet a positive sign is optional.

As it has always been, all number values cannot contain spaces.

Limitations
The  data type has many limitations you have to be aware of in order to effectively use it. First of all, we want to re-emphasize an issue that was mentioned when data types were introduced: In computing  variables can only store a subset of rational numbers (ℚ). That means, for example, you cannot store the (mathematically speaking) real number (ℝ) $$\sqrt{2}$$. This number is an irrational number (i.&#8239;e. not a rational number). If you cannot write a number as a finite  literal, it is impossible to store it in a system using a finite amount of memory, such as computer systems do.

Fortunately, in EP three constants aide your usage of  values. is the smallest positive  value. It conjunction with the constant, it is guaranteed that all arithmetic operations in $$\left[-\texttt{maxReal}, \texttt{maxReal}\right] \setminus \left(-\texttt{minReal}, \texttt{minReal}\right) \cup \left\{0\right\}$$ produce, quote, reasonable approximations. It is not specified what exactly constitutes a “reasonable” approximation, thus it can, for example, mean that yields as “an approximation”. Also, it is quite possible that  variables can store larger values than.

is short for “epsilon ”. The small Greek letter ε (epsilon) frequently denotes in mathematics an infinitely small (positive) value, yet not zero. According to the ISO standard 10206 (“Extended Pascal”),  is the result of subtracting   from the smallest value that is greater than. No other value can be represented between this value and, thus   represents the highest precision available, but just at that point. Most implementations of the  data type will show a significantly varying degree of precision. Most notable, the precision of  data type implementations complying with the IEEE standard 754 format, decays toward the extremes, when approaching (and going beyond)   and. Therefore you usually use, if at all, a reasonable multiple of  that fits the given situation.

Transfer functions
Pascal’s strong typing system prevents you from assigning  values to   variables. The  value may contain a fractional part that an   variable cannot store.

Pascal defines, as part of the language, two standard functions addressing this issue in a well-defined manner. Both functions will fail if there is no such  value fulfilling the function’s respective definition.
 * The function, short for “truncation”, simply discards any fractional part and returns, as an  , the integer part. As a consequence this is effectively rounding a number toward zero.   will return the value.
 * If this feels “unnatural”, the  function rounds a   number to its closest   value.   is (regarding the resulting value) equivalent to  for non-negative values, and equivalent to  for negative   values. In other words, this is what you were probably taught in grade school, or the first rounding method you learned in homeschooling. It is commonly referred to as “commercial rounding”.

There is no function if you want to (explicitly) “transfer” an  value to a   value. Instead, one uses arithmetically neutral operations: These expressions make use of the fact, as it was mentioned earlier as a passing remark in the chapter on expressions, that the expression’s overall data type will become  as soon as one   value is involved.
 * (using multiplicative neutral element), or
 * (using summing neutral element)

Printing values
By default /  print   values using “scientific notation”. Borland Pascal defines a value constant. It was adopted by many compilers.

While this style is very universal, it may also be unusual for some readers. Particularly the  notation is something now rather archaic, usually only seen on pocket calculators, i.&#8239;e. devices lacking of enough display space.

Luckily, /  allow us to customize the displayed style. For starters, specifying a minimum total width is legal for parameters, too, but this also shows more digits:

The procedures /  accept for   type values (and only for   values) another colon-separated format specifier. This second number determines the (exact) number of post-decimal digits, the “fraction part”. Supplying two format specifiers also disables scientific notation. All  values are printed using regular positional notation. That may mean for “large” numbers such as  printing a one followed by a hundred zeros (just for the integer part).

Let’s look at an example: In some regions and languages it is customary to use a  (comma) or other character instead of a dot as a radix mark. Pascal’s on-board /  procedures will, on the other hand, always print a dot, and for that matter –  /  will always accept dots as radix marks only. Nevertheless, all current Pascal programming suites, Delphi, FPC and GPC provide appropriate utilities to overcome this restriction. For further details we refer to their manuals. This issue should not keep us from continuing learning Pascal.

The output / (and in EP also  ) generate will be rounded with respect to the last printed digit.

Comparisons
First of all, all (arithmetic) comparison operators do work with  values. The operators  and , though, are particularly tricky to handle.

In most applications you do not compare  values to each other when checking for equality or inequality. The problem is that numbers such as ⅓ cannot be stored exactly with a finite series of binary digits, only approximated, yet there is not one valid approximation for ⅓ but many legit ones. The  and   operators, however, compare – so to speak — for specific bit patterns. This is usually not desired (for values that cannot be represented exactly). Instead, you want to ensure the values you are comparing are within a certain range, like: Delphi and the FPC’s standard RTS provide the function  as part of the   unit. You do not want to program something other people already have programmed for you, i.&#8239;e. use the resources.

Division
Now that we know the data type used for storing (a subset of) rational numbers, in Pascal known as, we can perform and use the result of another arithmetic operation: The division.

Flavors
Pascal defines two different division operators:
 * The  operator performs an integer division and discards, if applicable, any remainder. The expression’s resulting data type is always  . The   operator only works if both operands are   expressions.
 * The, probably more familiar, operator  (a forward slash), divides the LHS number (the dividend) by the RHS number (the divisor), too, but a  -division always yields a   type value. This is also the case if the fractional part is zero. A “remainder” does not exist for the   operation.

The  operation can be put in terms of  : However, this is only a semantic equivalent, it is not how it is actually calculated. The reason is, the  operator would first convert both operands to   values and since, as explained above, not all   values can necessarily be represented exactly as   values, this would produce results potentially suffering from rounding imprecisions. The  operator on the other hand is a pure   operator and works with “integer precision”, that means no rounding is involved in actually calculating the   result.

Off limits divisor
Note, since there is no generally accepted definition for division by zero, a zero divisor is illegal and will result in your program to abort. If your divisor is not a constant and depends on run-time data (such as a variable read from user input), you should check that it is non-zero before doing a division: Alternatively, you can declare data types excluding zero, so any assignment of a zero value will be detected: Some Pascal dialects introduce the concept of “exceptions” that can be used to identify such problems. Exceptions may be mentioned again in the “Extensions” part of this Wikibook.

Arrays as parameters
Arrays can be copied with one simple assignment. This requires, however, as it is customary with Pascal’s strong type safety, that both arrays are assignment-compatible: That means their base type and dimension specifications are the same.

Because calling a routine involves invisible assignments, writing general-purpose code dealing with lots of different situations would be virtually impossible if the entire program had to use one array type only. In order to mitigate this situation, conformant array type parameters allow writing routines accepting differing array dimension lengths. Array dimension data types still have to match.

Let’s look at an example program using this feature:

A conformant-array parameter looks pretty similar to a regular array variable declaration, but the dimensions are specified differently. Usually, when declaring new arrays you provide constant values as dimension limits. Since we do not want constants, though, we name placeholder identifiers for the actual dimension limits of any array  will receive. In this case they are named  and , joined by   inbetween indicating a range.

and  become variables inside the definition of , but you are not allowed to assign any values to them. You are not allowed to declare new identifiers bearing the same name as the array boundary variables.

In Pascal all constants implicitly have an unambiguously determinable data type. Since our array limit identifiers are in fact variables they require a data type. The indicates both   and   have the data type.

Once we have declared and defined  we can use it with lots of differently sized arrays:

Delphi and the FPC (as of version 3.2.0 released in 2020) do not support conformant-array parameters, but the GPC does.

Special support
Prior the 21st century logarithm tables and slide rules were heavily utilized tools in manual calculations, so much so it led to the inclusion of two basic functions in Pascal. Both functions always return  values.
 * The function  exponentiates a number to the base $$e$$, Euler’s constant. The value of   is equivalent to the mathematical term $$e^{\texttt{x}}$$.
 * The function, short for Latin “logaritmus naturalis”, takes the natural logarithm of a positive number. “Natural” refers to $$e$$ again.

Introduction
Since the use of logarithms is not necessarily taught in all curricula, or you might just need a refresher, here is a short primer: The basic idea of logarithms is that all operations are lifted one level. On the lifted level many operations become simpler, especially if the numbers are large. For instance, you can perform a rather easy addition if you actually mean to take the product of two numbers. For this you have to “lift” all operands one level up: This is done by taking the logarithm. Pay particular attention to $$x^y$$: On the logarithm level $$y$$ is a non-“logarithmized” factor, you only take the logarithm of $$x$$

Once you are done, you have descend one level again to get the actual “real” result of the intended operation (on the underlying level). The reverse operation of  is. To put this principle in Pascal terms: Remember,  and   have to be positive in order to be valid parameters to.

Application
Taking the logarithm and then exponentiating values again are considered “slow” operations and introduce a certain overhead. In programming, overhead means taking steps that are not directly related to the actual underlying problem, but only facilitate solving it. In general, overhead is avoided, since (at first) it takes us even farther away from the solution. Nevertheless, logarithms can be used to overcome range limitations of the data type if intermediate results are out of its range, but it is known that the final result will definitely be within the range of   again. As you can see, this goes to the detriment of precision. It is a compromise between fast operations, and “accurate enough” results.

The best solution is, of course, finding a better algorithm. The above demonstration $$\sqrt{x^2}$$ is effectively $$\left|x\right|$$, that is  (remember, squaring a number always yields a non-negative number). This operation’s result will stay in the range of.

Tasks
All tasks, including those in the following chapters, can be solved without conformant-array parameters. This takes account of the fact that not all major compilers support them. Nonetheless, using routines with conformant-array parameters are often the most elegant solution.

More tasks you can solve can be found on the following Wikibook pages:
 * A-level Computing 2009/AQA/Problem Solving, Programming, Data Representation and Practical Exercise/Fundamentals of Programming/One-Dimensional Arrays
 * A-level Computing 2009/AQA/Problem Solving, Programming, Data Representation and Practical Exercise/Fundamentals of Programming/Two-Dimensional Arrays

Sources: (the other possibly being of type ) the following operators yield a real value: }} Notes: