High() and Low() Uh-Oh!

Started by
14 comments, last by Xorcist 22 years, 5 months ago
Exactly how would I go about determining the Upper and Lower Bounds of a two dimensional array''s second dimension? I know High and Low work with the first dimension, but that kinda leaves me hanging. If for instance I have a dynamic multi-dimensional array, thus not knowing the bounds, how could I go about initializing all the elements to a default value? I''m truely lost for an answer on this one... someone please help!
Advertisement
Is this what you mean? I think it might be, but I''m more than spectacular at misunderstanding the question.

  var   MyArray: array[0..6,3..7] of integer; // array with any bounds   AnyInt: integer;begin// Returns the high bounds of the first dimention, ie. 6     High(MyArray);         // Returns the high bounds of the second dimention, ie. 7     High(MyArray[AnyInt]); end;  


Just put that together quickly now and it works for me.

~ There''s no substitute for failure ~
works because
MyArray: array[0..6,3..7] of integer;equalsMyArray: array[0..6] of array[3..7] of integer;
Okay both of you guys really confused me but I think I found the answer. High and Low can be called with a specific dimension in mind, such as Low(MyArray[1]) for the first dimension or High(MyArray[10]) for the tenth dimension if there was one. So I can use the following code to clear/initialize a two dimensional array of integers without knowing the explicit bounds:

    Procedure Clear(var tmpArray: TArray);Var  X,Y: Integer;Begin  for X := Low(tmpArray[1]) to High(tmpArray[1]) do begin    for Y := Low(tmpArray[2]) to High(tmpArray[2]) do begin      tmpArray[X,Y] := 0;    end;  end;End;  



P.S. MarkyD, I'm not quite sure you got your code to work because in this line:

        // Returns the high bounds of the second dimention, ie. 7  High(MyArray[AnyInt]);   


AnyInt has yet to be assigned a value, which is what started my confusion, but I finally realized what you were trying to get across.

Edited by - Xorcist on November 8, 2001 5:47:45 PM
quote:Original post by Xorcist
MarkyD, I'm not quite sure you got your code to work


Neither am I.

quote:
AnyInt has yet to be assigned a value, which is what started my confusion.


I wasn't too sure about this either. But I just tried this now, and it worked perfectly...every time:

        procedure TForm1.FormActivate(Sender: TObject);var   High: array[1..5,4..57,-5..36,7..45] of integer;   AnyInt: integer;begin     randomize;     AnyInt:=Random(50000);     Label1.Caption:='High(BigArr): '+IntToStr(High(BigArr));     Label2.Caption:='High(BigArr[?]): '+IntToStr(High(BigArr[AnyInt]));     Label3.Caption:='High(BigArr[?][?]): '+IntToStr(High(BigArr[AnyInt][AnyInt]));     Label4.Caption:='High(BigArr[?][?][?]): '+IntToStr(High(BigArr[AnyInt][AnyInt][AnyInt]));end;    


I would have thought that AnyInt would have had to be within the bounds or the array, too. But after that threw out the same result every time, I guess that number doesn't actually have to be anything special. Strange.

~ There's no substitute for failure ~

Edited by - MarkyD on November 9, 2001 11:36:30 AM
I''ve just tried your code, and I got an Access Violation error. Here is some more code that you might be interested in...

  Procedure TForm1.FormActivate(Sender: TObject);var  BigArr: array[1..5,4..57] of integer;  L0,H0,L1,H1,L2,H2: integer;begin     L0:=Low(BigArr);     // Returns: 1     H0:=High(BigArr);    // Returns: 5     L1:=Low(BigArr[1]);  // Returns: 4     H1:=High(BigArr[1]); // Returns: 57     L2:=Low(BigArr[2]);  // Returns: 4     H2:=High(BigArr[2]); // Returns: 57end;  


That''s your answer. The number inside the brackets doesn''t affect anything - it''s the number of them. If you need to know how many dimensions there are in an array, I haven''t got a clue. I''ll have a look around and see.

~ There''s no substitute for failure ~
Actually that number in the brackets is important. I just ran a battery of tests and generated a quick console app and found the following:

          PROGRAM Check;TYPE  TArray = array[1..10, 2..20, 3..30] of char;VAR  MyArray: TArray;Procedure CheckDimensions(var tmpArray: TArray);Var  ResultH,ResultL: Integer;Begin{ Display First Dimensional Bounds }  ResultL := Low(tmpArray);  ResultH := High(tmpArray);  Writeln('Low:', ResultL, ' ', 'High:', ResultH);{ Display Second Dimensional Bounds }  ResultL := Low(tmpArray[10]);  ResultH := High(tmpArray[10]);  Writeln('Low:', ResultL, ' ', 'High:', ResultH);{ Display Third Dimensional Bounds }  ResultL := Low(tmpArray[1][2]);  ResultH := High(tmpArray[1][2]);  Writeln('Low:', ResultL, ' ', 'High:', ResultH);End;BEGIN { Main }{ Insert program code here }  CheckDimensions(MyArray);{ Remove the following two lines before production }  Writeln;  Write('Press any key to continue... ');  Readln;END. { Main }          


Calling Low or High with just the array name is the same as checking the lower and upper bounds of the first dimension of an array. Calling Low or High with the array name and a single bracketed number will return the second dimension, however that bracketed number must be within the range of the first dimension. Try putting 0 or 11 into the second dimensional check of the console app above and you'll get a comipler error. Every other bracketed number you append will move the dimensional check up one rung, but the number within must be within the range of the previous dimension (otherwise the compiler will complain with "Constant expression violates subranges bounds"). So indeed it is not the number that matters but rather the number of subscripts appended, however the subscripts can not be any number, they must be within the range for the given dimension. (Did that make sense?)


Example:

Low(MyArray) checks the lower bound on MyArray[]
Low(MyArray[#1]) checks the lower bound on MyArray[][]
Low(MyArray[#2][#3]) checks the lower bound on MyArray[][][]

#1 must be within the bounds of the array's first dimension
#2 must be within the bounds of the array's first dimension
#3 must be within the bounds of the array's second dimension

it kinda makes sense when you consider exactly what Low and High do, which is nothing more than return a limit on a range.

Edited by - Xorcist on November 9, 2001 2:15:30 PM
Comma delimited notation seems to work as well:

  { Display Third Dimensional Bounds }  ResultL := Low(tmpArray[10,20]);  ResultH := High(tmpArray[10,20]);  Writeln(''Low:'', ResultL, '' '', ''High:'', ResultH);  
Of course now we get back to the problem were, since multi-dimensional arrays need to be declared and passed as user defined types, will retain their actual ranges. Unlike using array of type , to pass single dimensional arrays. Which changes the range of the array inside of the procedure it was passed to, to 0 though elements - 1 (reguardless of what the original range was). Thus we must know exactly how the array was dimensioned in order to get the proper return from High and Low , which would force us to do something along the lines of this to generalize it:

    { Display Third Dimensional Bounds }  ResultL := Low(tmpArray[Low(tmpArray),Low(tmpArray[Low(tmpArray)])]);  ResultH := High(tmpArray[High(tmpArray),High(tmpArray[High(tmpArray)])]);  Writeln('Low:', ResultL, ' ', 'High:', ResultH);    



Which I'm sure we'll all agree is pretty messy... so, back to my original question. Without knowing the explicit bounds, how would I go about writing a generalized unit procedure that takes in a two dimensional array of integers and clears it. That is without knowing how the "user" declared his array. I'm having a lot of trouble figuring this out, because it always seems I need some sort of pre-defined array type. Which is not what I want because I want the user to be able to define and declare a two dimensional array however he/she likes and my functions should be able to work on it reguardlessly. I've tried messing around with passing arrays as pointers but come up short handed each time. Anyone?

{Why is this so difficult, you'd think such as task would be trivial... at least in any language other than Delphi }

Edited by - Xorcist on November 9, 2001 3:03:30 PM
I had this post ready yesterday, but after my browser started to slow down, I cut, pasted and saved it just before the thing crashed. Ah well, got there in the end.

[oldpost]

quote:Original post by Xorcist
Actually that number in the brackets is important.


Actually it isn''t. Kind of.
If the number in the brackets is a constant, then indeed it must be inside that dimension''s bounds. However, if it is a variable, then it doesn''t have to be. Well...not with me anyway.
Anyway, here is some more code:

  procedure Cleararraysorsomething;const  NUM_OVER_10 = 11;var  MyArray: array[1..10,2..20,3..30] of integer;  TempInt,  Result: integer;begin{Here, 11 is exceeding the dimension''s bounds, so the compiler will generate an error}     Result:=High(MyArray[11]);{Here, since NUM_OVER_10 equals 11, the compiler will again generate an error}     Result:=High(MyArray[NUM_OVER_10]);{Here, TempInt is assigned the value of 11. But since the compiler doesn''t know that TempInt is out of bounds, the code will still run}     TempInt:=11;     Result:=High(MyArray[TempInt]);end;  


I still don''t believe that the number passed in the brackets is important - even though the compiler seems to think so. High and Low , I think, return the range of the dimension above the number of brackets, like you pointed out. But I don''t think that those procedures actually use the numbers in the brackets - it''s just that the compiler doesn''t realise it.

I''ve rambled enough here. Time to do some more testing...

[/oldpost]

There. Posted it in the end. I''ve got an idea around this, though. This is only a recent thought that I have not put in practise, but if you call a procedure with an out word before the array, it would be cleared before the procedure is ran through. Like so...

  procedure ClearArray(out SomeArray: array of integer);beginend;  


If you call that procedure, shouldn''t the array get cleared before the procedure''s lines - even though it has none? Just an idea...

~ There''s no substitute for failure ~

This topic is closed to new replies.

Advertisement