Declaring Arrays of Variable Length in Delphi [duplicate] - arrays

This question already has answers here:
How do I declare an array when I don't know the length until run time?
(2 answers)
Closed 9 years ago.
This post was edited and submitted for review 4 months ago and failed to reopen the post:
Original close reason(s) were not resolved
I have a procedure in Delphi which currently looks like this:
Procedure Time.TimeDB(algorithm: string; Encode, Decode: InputFunction; N, R: Int);
VAR
i : LongInt;
Errors : Array[N] of LongInt;
BEGIN
for i := 0 to N-1 do
Errors[i] := 0;
END;
I'm given the error that N, as passed to the definition of Errors, is an undeclared identifier, despite declaring it in the procedure definition. N is recognized in the BEGIN-END section, though. Any ideas what's causing this and how I can otherwise declare a variable-length array in the VAR section?

You write array of Int to declare a dynamic array of Ints:
procedure Time.TimeDB(algorithm: string; Encode, Decode: InputFunction; N, R: Int);
var
i: int;
errors: array of Int;
begin
SetLength(errors, N);
for i := 0 to N - 1 do
Errors[i] := 0;
end;
Also notice that if an array has N elements, then they are indexed 0, 1, ..., N - 1. There is no element indexed N.
(Also, are you sure you don't mean integer when you write Int?)
The construct array[M..N] of Int is called a static array. In this case, M and N must be constants, like array[0..15] of TColor. You also got the static array declaration array[TMyType] of TMySecondType where the index will be of type TMyType, as in array[byte] of TColor or array[TFontStyle] of cardinal.

In your code your initializing your Errors Array to zero...Note with SetLength you don't need to do this...just set the Array to 0 and then set it to the length you want, and then just assign the values you need.
procedure WorkArrays(var aWorking: array of integer);
begin
if High(aWorking) >= 0 then
aWorking[0] := 1;
if High(aWorking) >= 3 then
aWorking[3] := 5;
end;
procedure WorkArrays2(var aWorking: array of integer);
begin
if High(aWorking) >= 1 then
aWorking[1] := 4;
if High(aWorking) >= 9 then
aWorking[9] := 7;
end;
procedure WorkArrays3(var aWorking: TIntArray);
begin
SetLength(aWorking, 4);
aWorking[0] := 1;
aWorking[3] := 5;
end;
procedure WorkArrays4(var aWorking: TIntArray);
begin
SetLength(aWorking, 10);
aWorking[1] := 4;
aWorking[9] := 7;
end;
procedure TForm58.ShowArrays(aWorking: array of integer);
var
a_Index: integer;
begin
for a_Index := Low(aWorking) to High(aWorking) do
Memo1.Lines.Add(IntToStr(aWorking[a_Index]));
end;
procedure TForm58.ShowArrays2(aWorking: TIntArray);
var
a_Index: integer;
begin
for a_Index := Low(aWorking) to High(aWorking) do
Memo1.Lines.Add(IntToStr(aWorking[a_Index]));
end;
procedure TForm58.Button1Click(Sender: TObject);
var
a_MyArray: array of integer;
a_MyArray1: TIntArray;
begin
SetLength(a_MyArray, 3);//note this is a Zero based Array...0 to 2
WorkArrays(a_MyArray);//note aWorking[3] will not show...because High is 2...
ShowArrays(a_MyArray);
SetLength(a_MyArray, 0);
SetLength(a_MyArray, 10);//note this is a Zero based Array...0 to 9
WorkArrays2(a_MyArray);
ShowArrays(a_MyArray);
WorkArrays3(a_MyArray1);
ShowArrays2(a_MyArray1);
WorkArrays4(a_MyArray1);
ShowArrays2(a_MyArray1);
end;
end.

Related

Pascal Latest N Prime Number in Array

I want to print array of n prime number, like if the input is 5 so it'll print [2,3,5,7,11].
This is my code
program prime;
type
prime_number = array [1..10] of Integer;
var
dataset:prime_number;
n,i,j,count,angka:Integer;
function isPrime(a:Integer): Boolean;
var
i: Integer;
begin
for i := 2 to round(sqrt(a)) do
begin
if(a mod i = 0) then isPrime:=false
else isPrime:=true;
end;
end;
procedure printPrime(a:Integer;var df:prime_number);
var
number,primeCount,i: Integer;
begin
number:=2;
primeCount:=0;
while (primeCount < a) do
begin
if(isPrime(number)) then
begin
for i := 1 to a do
begin
df[i]:=number;
primeCount:=primeCount+1;
end;
end;
number:=number+1;
end;
end;
begin
write('Enter n: ');read(n);
printPrime(n,dataset);
end.
When I run the program it's totally fine, but it prints nothing instead of the array :( What's wrong with my code, anyone?
I see at least a couple of issues.
First, isPrime: You'll want to break out of the loop as soon as you see something that divides the test value, a, so it should be more like
function isPrime(a:Integer): Boolean;
var
i: Integer;
begin
for i := 2 to round(sqrt(a)) do
begin
if(a mod i = 0) then begin
isPrime:=false;
exit;
end;
end;
isPrime:=true;
end;
Then, in printPrime you have some, frankly, odd logic.
First of all, you're not printing anything anywhere within that procedure.
Then, when you do find a prime, you initialize all values in df up to the size with that value, why not just set the value at primeCount? You know, as in
procedure printPrime(a:Integer;var df:prime_number);
var
number,primeCount,i: Integer;
begin
number:=2;
primeCount:=0;
while (primeCount < a) do
begin
if(isPrime(number)) then
begin
primeCount:=primeCount+1;
df[primeCount]:=number;
end;
number:=number+1;
end;
end;

Printing an array as an ArrayType in Pascal

This program is supposed to sort an array and fill it with random integers from 1 to 1000. It needs to find the maximum value and print the array. It should print the array in two ways: ARRAY OF INTEGER and ArrayType. I need help to print this array in ArrayType. I am not super familiar with Pascal and my assignment is to print this array with ArrayType as a parameter. This is my code I have so far:
PROGRAM SortingAlgorithm;
Var intArray : array[1..20] OF INTEGER;
Var i, j, index : INTEGER;
PROCEDURE Sort(intArray : ARRAY OF INTEGER; size : INTEGER);
BEGIN
FOR i := 2 to 20 do
BEGIN
index := intArray[i];
j := i;
WHILE ((j > 1) AND (intArray[j-1] > index)) do
BEGIN
intArray[j] :=intArray[j-1];
j := j - 1;
END;
intArray[j] := index;
END;
END;
PROCEDURE fillArray(var a,b : integer);
VAR temp : INTEGER;
BEGIN
temp := a;
a := b;
b := temp;
END;
BEGIN
FOR i := 1 to 20 do
intArray[i] := i;
FOR i := 1 to 20 do
fillArray(intArray[i],intArray[random(20)+1]);
END.
PROCEDURE findMax(intArray : ARRAY OF INTEGER; size : INTEGER);
VAR max : INTEGER;
begin
max := 1;
FOR i := 2 to size do
BEGIN
IF intArray[i] > intArray[max] THEN
max:=i;
END;
END;
PROCEDURE printArray(intArray : ARRAY OF INTEGER; size : INTEGER);
BEGIN
FOR i := 1 to 20 do
Writeln(intArray[i]);
END;
PROCEDURE printArray2();
BEGIN
END;
BEGIN
fillArray (intArray);
printArray (intArray);
printArray2 (intArray);
largestValue := findMax (intArray);
WriteLn (‘The largest value is ‘, largestValue);
sort (intArray);
printArray (intArray);
END.
printArray2 is for the ArrayType parameter. This is all the information I was given for this program, I'm not sure what printing with a parameter of ArrayType means. Any help is appreciated. Thanks.

Pascal/Delphi dynamic array as argument

I'd like to do something like this:
procedure show(a : Array of Integer);
var
i : integer;
begin
for i in a do
writeln(i);
end;
begin
show((1, 2));
show((3, 2, 5));
end.
but this is the closest I got
Program arrayParameter(output);
type
TMyArray = Array[0..2] of Integer;
var
arr : TMyArray = (1, 2, 3);
procedure show(a : TMyArray);
var
i : integer;
begin
for i in a do
writeln(i);
end;
begin
show(arr);
end.
So do I have to declare a different array for each time I want to call the function? Please provide a working example.
If you do
procedure show(a: array of Integer);
var
i: Integer;
begin
for i in a do
Writeln(i);
end;
then you may write
show([1, 2, 3, 4]);
This kind of array parameter is called an open array parameter. If a function has an open array parameter, you can give it both dynamic and static arrays, in addition to these "literal arrays". So, given our show procedure, we may also do
var
DynArr: TArray<Integer>; // = array of Integer
StaticArr: array[0..2] of Integer;
begin
show(DynArr);
show(StaticArr);
end;
Just for comparison: If you instead do
procedure show(a: TArray<Integer>);
or has a
type
TDynIntArray = array of Integer;
and do
procedure show(a: TDynIntArray);
then show will only accept such dynamic arrays.

How to change the values of a boolean array in delphi

I'm making a small Delphi program using Delphi XE5. In my code there is a dynamic boolean array and I'm no able to change the value of some of the arrays elements. I tried to initialize the array after setting it's length but it didn't help. Here is part of the code:
procedure DoSomething(names: array of string);
var startWithA: array of Boolean;
i: integer;
begin
SetLength(startWithA, Length(names)); // each element is false by default
for i := 0 to Length(names) - 1 do begin
if (names[i].indexOf('A') = 0) then begin
startWithA[i] := true; // the value is not changed after executing this line
end;
end;
end;
Your code works absolutely fine. Here is the proof:
{$APPTYPE CONSOLE}
uses
System.SysUtils;
function StartsWithAIndices(const Names: array of string): TArray<Boolean>;
var
i: Integer;
begin
SetLength(Result, Length(Names));
for i := 0 to high(Result) do begin
if (Names[i].IndexOf('A') = 0) then begin
Result[i] := true;
end;
end;
end;
var
Indices: TArray<Boolean>;
b: Boolean;
begin
Indices := StartsWithAIndices(['Bob', 'Aaron', 'Aardvark', 'Jim']);
for b in Indices do begin
Writeln(BoolToStr(b, True));
end;
Readln;
end.
Output
False
True
True
False
Perhaps your confusion stems from the fact that you assign to an array that is a local variable and whose values are never read. How can you say that the array values are not modified if you never read from them? Or perhaps you have optimizations enabled and the compiler decided to optimize away the local variable whose values are written to but never read.
As an aside, your function could be written more simply like this:
function StartsWithAIndices(const Names: array of string): TArray<Boolean>;
var
i: Integer;
begin
SetLength(Result, Length(Names));
for i := 0 to high(Result) do begin
Result[i] := Names[i].StartsWith('A');
end;
end;

How to swap two rows of a two-dimensional array, and why would it work?

Summarization:
Please check the comments below from David, Uwe, and other experts.
================================================================================
The following code swaps two rows in a two-dimensional, dynamic array of double values. I am wondering: (1) whether the following code is a best practice of swapping two rows of a two-dimensional array? If not, then what is the best practice to do this kind of job? (2) why would the following code work? I mean, isn't two-dimensional array a continuous contiguous section of memory? Does the following code work only by luck? Any suggestion is appreciated!
unit Unit5;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs;
type
TAADouble = array of array of Double;
TForm5 = class(TForm)
procedure FormShow(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form5: TForm5;
procedure SwapRows(arr: TAADouble; row0, row1: Integer);
implementation
{$R *.dfm}
procedure SwapRows(arr: TAADouble; row0, row1: Integer);
var
Tmp: Integer;
begin
{$IFDEF FPC}
Tmp := PtrUInt(arr[row0]);
PtrUInt(arr[row0]) := PtrUInt(arr[row1]);
PtrUInt(arr[row1]) := Tmp;
{$ELSE}
Tmp := Integer(arr[row0]);
Integer(arr[row0]) := Integer(arr[row1]);
Integer(arr[row1]) := Tmp;
{$ENDIF}
end;
procedure TForm5.FormShow(Sender: TObject);
var
tmpArray: TAADouble;
I, J: Integer;
rowStr: string;
begin
SetLength(tmpArray, 10, 10);
rowStr := '';
for I := 0 to 9 do
for J := 0 to 9 do
tmpArray[I][J] := I * J;
for I := 0 to 9 do
begin
rowStr := '';
for J := 0 to 9 do
rowStr := rowStr + FloatToStr(tmpArray[I][J]) + ' ';
OutputDebugString(PWideChar(rowStr));
end;
SwapRows(tmpArray, 3, 4);
for I := 0 to 9 do
begin
rowStr := '';
for J := 0 to 9 do
rowStr := rowStr + FloatToStr(tmpArray[I][J]) + ' ';
OutputDebugString(PWideChar(rowStr));
end;
end;
end.
You ask:
Does the following code work only by
luck?
Well, yes, you are relying on implementation specific details.
In fact the correct way to write it is perfectly natural and simple:
type
TDoubleArray = array of Double;
TDoubleMatrix = array of TDoubleArray;
procedure SwapRows(M: TDoubleMatrix; Row1, Row2: Integer);
var
Temp: TDoubleArray;
begin
Temp := M[Row1];
M[Row1] := M[Row2];
M[Row2] := Temp;
end;
You need to declare an intermediate type for the row, TDoubleArray, so that you can perform the assignment to Temp in the swap routine.
A 2D constant size array
array [1..M] of array [1..N] of TMyType
is a contiguous block of memory.
A 2D dynamically size array as you have is not. Indeed it can even be ragged in the sense that the rows have different numbers of columns. So you can have, say, a triangular matrix.
A dynamic array is implemented as a pointer to a memory block representing that array. So a two-dimensional dynamic array is actually a pointer to an array of pointers. Thats why swapping the row(-pointer)s actually works.
See David's answer for a cleaner approach.
Update:
If you are allowed to use generics you might as well do this:
procedure <SomeClassOrRecord>.SwapRows<T>(var arr: TArray<T>; row0, row1: Integer);
var
Tmp: T;
begin
Tmp := arr[row0];
arr[row0] := arr[row1];
arr[row1] := Tmp;
end;

Resources