Chapter 6: Arrays and Strings


This chapter shows how to efficiently work with large numbers of variables, how to manipulate strings using standard Delphi procedures and functions, and how to create your own procedures and functions that work with strings.

Arrays

Arrays are very useful for working with a large number of variables of the same type that are logically related. For instance, imagine that you have to create an application for your local cinema that shows which seats are occupied and which are vacant. Let's say that the entire cinema has 350 seats. To remember the state of every seat in the cinema, you would need 350 uniquely named Boolean variables:

var   seat1: Boolean;   seat2: Boolean;   seat3: Boolean;   seat350: Boolean;

Not only is this large number of declarations unacceptable, it leads to even more problems. What if you wanted to update the state of a seat based on what the user enters? There is no way other than to write a huge if-then or case statement that would check the value the user entered and change the corresponding variable. This means that you would have at least 350 lines of code to simply change the state of one seat:

var   seat1: Boolean;   seat2: Boolean;   seat3: Boolean;   seat350: Boolean;   userSeat: Integer; begin   ReadLn(userSeat);   case userSeat of     1: seat1 := True;     2: seat2 := True;     350: seat350 := True;   end; end. 

Obviously, there has to be a better way of dealing with large collections of variables. The best way of doing so is to use an array.

An array is simply a collection of variables. All variables in the array share the same name and have the same data type. But unlike individual variables, all variables in an array have an additional property that differentiates them from one another — the index.

The syntax for array declaration is:

ArrayName: array[Range] of DataType;  Cinema: array[1..350] of Boolean;

To access a variable in the array, you have to specify the name of the array followed by the variable's index. The variable's index must be enclosed in brackets. The syntax for accessing a single element of the array is:

ArrayName[Index]

If you are using the Cinema array and you need to change the state of seat 265 to vacant, you can write this:

Cinema[265] := False;

The index of an element doesn't need to be a constant value. It can be a variable or a function result. The important thing is that the index value has to be inside the declared range.

Listing 6-1: Array element access

image from book
const   MAX_SEATS = 350; var   Cinema: array[1..MAX_SEATS] of Boolean;   userSeat: Integer; begin   ReadLn(userSeat);   if (userSeat >= 1) and (userSeat <= MAX_SEATS) then     Cinema[userSeat] := True; end.
image from book

The best thing about arrays is that you can access array elements in a loop, which can easily solve a lot of problems. In this case, you can easily set all seats to vacant if the cinema is empty or calculate the percentage of seats occupied. If you take a closer look at the GetPercent function, you will notice that arrays support the new for-in loop.

Listing 6-2: Accessing array elements in a loop

image from book
program Project1; {$APPTYPE CONSOLE} uses   SysUtils; const   MAX_SEATS = 350; var   Cinema: array[1..MAX_SEATS] of Boolean;   i: Integer; procedure ClearCinema; var   i: Integer; begin   for i := 1 to MAX_SEATS do     Cinema[i] := False; end; function GetPercent: Double; var   seat: Boolean;   occupiedCnt: Integer; begin   occupiedCnt := 0;   for seat in Cinema do     if seat then Inc(occupiedCnt);   Result := occupiedCnt * 100 / MAX_SEATS; end; begin   { 67 seats occupied }   for i := 1 to 67 do     Cinema[i] := True;   WriteLn(GetPercent:0:2, '% seats occupied.');   ReadLn; end.
image from book

Arrays in Delphi are much more flexible than arrays in other programming languages. For instance, array indexes in C++, C#, and VB.NET are always zero based. In Delphi, you can use index values that best suit your needs:

negativeArray: array[-100..100] of Integer; bigIndex:      array[1000..1020] of Integer; alphabet:      array[Ord('a')..Ord('z')] of Char

Since arrays in Delphi can have different indexes, it can be difficult to remember the starting and ending indexes of every array you use in an application. Delphi has two functions that get the first and last index of an array: Low and High. If you're not using the for-in loop, the best way to read index values is by using the High and Low functions.

Listing 6-3: Low and High functions

image from book
program Project1; {$APPTYPE CONSOLE} uses   SysUtils; var   alphabet: array[Ord('a')..Ord('z')] of Char;   i: Integer; begin   for i := Low(alphabet) to High(alphabet) do   begin     alphabet[i] := Chr(i);     WriteLn(alphabet[i]);   end;   ReadLn; end.
image from book

The Low and High functions remove the burden of remembering the exact indexes of an array, are easy to read, and don't slow down the application because the functions aren't called at run time. The compiler replaces the calls to both functions with appropriate values from the array declaration at compile time.

Array Constants

The syntax for array constant declaration is:

const   ArrayName: array[Range] of DataType = (value_1, value_2, value_n);

There are times when array constants can drastically reduce the amount of code. One such situation is when using a function that returns the name of the month. The function for returning the month name is pretty long when implemented without an array constant.

function GetMonthName(AMonth: Integer): string; begin   case AMonth of     1: Result := 'January';     2: Result := 'February';     3: Result := 'March';     4: Result := 'April';     5: Result := 'May';     6: Result := 'June';     7: Result := 'July';     8: Result := 'August';     9: Result := 'September';     10: Result := 'October';     11: Result := 'November';     12: Result := 'December';     else Result := '';   end; end;

A much better solution to this problem is to declare a local array constant. The function that uses the array constant is much smaller and looks more professional.

Listing 6-4: Using array constants

image from book
function GetMonthNameEx(AMonthName: Integer): string; const   MONTH: array[1..12] of string = ('January', 'February',     'March', 'April', 'May', 'June', 'July', 'August',     'September', 'October', 'November', 'December'); begin   if (AMonthName < Low(MONTH)) or (AMonthName > High(MONTH)) then     Result := ''   else     Result := MONTH[AMonthName]; end;
image from book

The GetMonthNameEx function returns an empty string if the AMonth parameter is out of valid range. You should always check user values to make sure they are valid. If you blindly accept user values, even simple functions like this one can cause an error and produce invalid results. In this case, if the user passes the number 13 as the AMonth parameter, the function returns an empty string.

WriteLn(GetMonthNameEx(13));

If you remove the range check, the application will try to read a value that is located outside of the array. If that memory location is empty, the call will probably execute without problems, but if the memory location isn't empty, the call will cause an error.

Array constants also give us the ability to use the case statement with string values. Although we can't use string values directly in the case statement, we can get the index of the value in the array and use that index in the case statement.

Listing 6-5: Using strings with the case statement

image from book
program Project1; {$APPTYPE CONSOLE} uses   SysUtils; function MonthIndex(const AMonthName: string): Integer; const   MONTH: array[1..12] of string = ('January', 'February',     'March', 'April', 'May', 'June', 'July', 'August',     'September', 'October', 'November', 'December'); var   i: Integer; begin   Result := -1;   for i := Low(MONTH) to High(MONTH) do   begin     if AMonthName = MONTH[i] then     begin       Result := i;       Exit;     end;      // if AMonthName   end;       // for i end; var   userEntry: string; begin   Write('Enter a month: ');   ReadLn(userEntry);   if MonthIndex(userEntry) = -1 then     WriteLn('Invalid month name')   else begin     case MonthIndex(userEntry) of       4: WriteLn('Easter');       12: WriteLn('Christmas');     end;      // case MonthIndex   end;   ReadLn; end.
image from book

The MonthIndex function returns –1 if the AMonthName parameter isn't a valid month name and the proper index if AMonthName is a valid month name. You should remember this value because a large majority of functions (not only in Delphi) return –1 if something is wrong.

Another thing to note in the MonthIndex function is the use of the Exit procedure. The Exit procedure is used when you want to terminate the procedure or function and immediately return control to the caller. In this case, the use of the Exit procedure ensures optimal execution. If the user passes "January" as the AMonthName parameter, the Exit procedure terminates the loop after the single iteration. You can omit the call to the Exit procedure, but the function will be slower because it will needlessly iterate 11 more times and give the same result.



Inside Delphi 2006
Inside Delphi 2006 (Wordware Delphi Developers Library)
ISBN: 1598220039
EAN: 2147483647
Year: 2004
Pages: 212
Authors: Ivan Hladni

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net