3

When I try to pass variable arrays from procedure to the main program, a[1] in the procedure was supposed to be equal to arr[1] in the main program, like this:

a[1] = arr[1]

a[2] = arr[2]

a[3] = arr[3]

a[4] = arr[4]

a[5] = arr[5]

But the program actually acta like this:

a[1] = ''

a[2] = arr[1]

a[3] = arr[2]

a[4] = arr[3]

a[5] = arr[4]

I don't know what's wrong to the code, can someone point out the mistake?

The simplied code, same problem:

var
  arr : array[1..5] of string;
  i : integer;

procedure test(var a : array of string);
var
  i : integer;
begin
  a[1] := 'one';
  a[2] := 'two';
  a[3] := 'three';
  a[4] := 'four';
  a[5] := 'five';
  for i := 1 to 5 do writeln(a[i]);
end;

begin
  test(arr);
  write('-----');
  for i := 1 to 5 do
  begin
    writeln(arr[i]);
    if arr[i] = '' then writeln('NOTHING');
  end;
  readln
end.
5
  • An "array of string" as in your Test" is zero-based, whereas your arr is 1-based - " array[1..5] of string;" Commented Jul 18, 2016 at 14:24
  • Can I declare the array in Test procedure as 1 based? Commented Jul 18, 2016 at 14:26
  • a : array[1..5] of string does not work Commented Jul 18, 2016 at 14:26
  • FWIW, please read this article of mine: "Open array parameters and array of const". It explains this and a little more about open array parameters, like you are using and are having problems with. Commented Jul 18, 2016 at 22:22
  • @cssjs50: as my article explains, a type declaration on the spot, inside a parameter declaration is not possible. You will have to declare a type in a type clause and use that. Example: type TArr = array[1..5] of string; ... procedure Test(var a: TArr);. Commented Jul 18, 2016 at 22:27

3 Answers 3

2

MartynA gave you the hint to look at "open array parameters" in the online help. But it is not necessary to do what he proposes, using ArrayLoBound etc. The declaration of the actual array can have any index range.

I would do this:

program OpenArrayTest;

{$APPTYPE CONSOLE}

var
  { Initialization like this only possible for global variables. }
  Arr: array[11..15] of string = ('once', 'doce', 'trece', 'catorce', 'quince');
  I: Integer;

procedure ModifyArray(var A: array of string);
var
  I: Integer;
begin
  for I := Low(A) to High(A) do
    A[I] := A[I] + ' <-- ' + IntToStr(I);
end;

procedure ShowArray(const A: array of string);
begin
  for I := Low(A) to High(A) do
    Writeln(A[I]);
end;

begin
  ModifyArray(Arr);
  ShowArray(Arr);
  Writeln('-----');
  ShowArray(['one', 'two', 'three', 'four', 'five', 'six', 'seven']);
  Readln;
end.

The output is:

once <-- 0
doce <-- 1
trece <-- 2
catorce <-- 3
quince <-- 4
-----
one
two
three
four
five
six
seven

In other words, use High() and Low() to access the items in the parameter. Do not use any fixed bounds, since the array can have any length. Also note that you can get the number of items in the array using Length(A) or Length(Arr). You can not only pass static arrays, like Arr, you can also pass dynamic arrays, or use an open array constructor (using [ and ]), like I did in the second call to ShowArray().

More about open arrays in my article "Open arrays and array of const".

Sign up to request clarification or add additional context in comments.

1 Comment

The point of my using constants was so that the OP could experiment with changing them, that was all. Not matter ...
1

Judging by your comment, you are in a bit of a muddle.

In short, if you declare a parameter to a procedure to be an "array of", the array is always zero-based, regardless of the structure of the array you pass to it as an argument, as in

  test(arr);

Try the code below. You'll find that when it runs, you get a Range-Check error on the line

  a[5] := 'five';

That's because although arr has five elements, they are numbered 0..4, so there is no element of arr with index 5.

Although there are other was to declare procedure parameters, if you want to pass arrays to it as arguments, you have to make sure that either you mentally translate the array indexes as you write the code or (better) you declare the arrays you pass to it as zero-based, as I've done.

And, try and make a habit of turning range-checking on. It will catch error you yourself may overlook.

I'm going to leave you to rewrite your test procedure so that it works correctly as an exercise, because I'm "guessing" that what you've posted is some kind of school- or course-work and you should really put some effort into finding out how to correct your error yourself. If you're still stuck after reading this and trying the obvious solution, ask.

Btw, if you are using Delphi, look up "Open array parameters" in the Online Help. That explains the restrictions on using "array of ..." procedure-parameters.

Also btw, Rudy Velthuis says in his answer "But it is not necessary to do what {MartynA] proposes, using ArrayLoBound etc." That is true, it is not necessary but he has missed my point. If you hard-code array bounds, with values like 1 and 5, and then change them later, it is easy to overlook other values that need updating too, like in your for loop. Defining these values as consts is a good habit to get into because it avoids introducing inconsistencies, but more importantly makes sure you think about what you are doing. IME ...

program arrayparam;

const
  ArrayLoBound = 0;
  ArrayHiBound = 4;

var
  arr : array[ArrayLoBound..ArrayHiBound] of string;
  i : integer;

{$R+}  // Turn range-checking on

procedure test(var a : array of string);
var
  i : integer;
begin
  a[1] := 'one';
  a[2] := 'two';
  a[3] := 'three';
  a[4] := 'four';
  a[5] := 'five';
  for i := 1 to 5 do
    writeln(a[i]);
end;

begin
  test(arr);
  writeln('-----');

  for  i := ArrayLoBound to ArrayHiBound do
  begin
    writeln(arr[i]);
    if arr[i] = '' then
      writeln('NOTHING');
  end;
  readln
end.

2 Comments

Actually, the array passed in doesn't have to be zero-based. It is just indexed on a zero base inside the routine that has the open array parameter. To put it differently: the formal open array parameter is zero-based. The actual array passed in doesn't have to be.
In other words, you can pass an array[11..16] to an open array parameter. But inside it will be accessed as 0..5. So there is no need for your ArrayLoBound etc. Rather teach them to use Low() and High(). That is much safer.
0

All good answers but just to be complete: the asker can get exactly the result asked for.

It could be that accessing them using 1 to 5 is important for the asker's purposes.

Make the changes below and it will print out as originally expected.

type

TArr = array[ 1..5 ] of string;

var

arr : TArr;

procedure test( var a : TArr );

I agree that defaulting to 0 based arrays is simply easier and using the functions low / hi make it bulletproof.

But I can also see that sometimes indexing in your own way could be of use / important.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.