Recent

Author Topic: Splitting an array in two using pointers  (Read 4085 times)

MortenB

  • Jr. Member
  • **
  • Posts: 59
Splitting an array in two using pointers
« on: January 17, 2017, 01:14:33 pm »
I have tried to find references to this kind of use, but to no avail.
Below is an easy example of what I would like to do.

Code: Pascal  [Select][+][-]
  1. SetLength(TheList,100);
  2. ptrPos1 := @TheList[0];
  3. ptrPos2 := @TheList[50];

My whole point is that I now want to use BOTH ptrPos1 and ptrPos2 as individual arrays from 0 to 49,
the first pointing to the first half of TheList, the second pointing to the last half of TheList.
I am aware that I can use INC and DEC on pointers, but this is of no use in this part of my project.
The variable type or array type can be anything from AnsiString to Int64. Not really important.

Maybe this is possible? I just have not found information about it.

Best regards,
Morten Brendefur.

balazsszekely

  • Guest
Re: Splitting an array in two using pointers
« Reply #1 on: January 17, 2017, 01:36:32 pm »
Hi MortenB,

Use the move command, something like this:
Code: Pascal  [Select][+][-]
  1. var
  2.   TheList, ptrPos1, ptrPos2: array of Integer;
  3.   I: Integer;
  4. begin
  5.   SetLength(TheList,100);
  6.   //populate the list
  7.   for I := Low(TheList) to High(TheList) do
  8.     TheList[I] := I;      
  9.  
  10.   //copy the values
  11.   SetLength(ptrPos1, 50);
  12.   Move(TheList[0], ptrPos1[0], 50*SizeOf(Integer));
  13.   SetLength(ptrPos2, 50);
  14.   Move(TheList[50], ptrPos2[0], 50*SizeOf(Integer));
  15.  
  16.   //print prtPos1, ptrPos2
  17.   for I := Low(ptrPos1) to High(ptrPos1) do
  18.     Writeln(ptrPos1[I]);
  19.   for I := Low(ptrPos2) to High(ptrPos2) do
  20.     Writeln(ptrPos2[I]);
  21. end;
« Last Edit: January 17, 2017, 01:46:21 pm by GetMem »

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Splitting an array in two using pointers
« Reply #2 on: January 17, 2017, 02:16:58 pm »
Problem with that would be that if you change the original TheList later, you would need to copy values again. Using pointers would be just referencing and therefore faster code
Code: Pascal  [Select][+][-]
  1. type
  2.   TheListType = integer;
  3.   TListArray = array[0..0] of TheListType;
  4.   PListArray = ^TListArray;
  5. ...
  6. procedure TForm1.FormCreate(Sender: TObject);
  7. var TheList: array of TheListType;
  8.     ptrPos1, ptrPos2: PListArray;
  9.     i: integer;
  10. begin
  11.   SetLength(TheList, 100);
  12.  
  13.   ptrPos1 := @TheList[0];
  14.   ptrPos2 := @TheList[50];
  15.  
  16.   //populate the list
  17.   for i := Low(TheList) to High(TheList) do TheList[i] := i;
  18.  
  19.   //print prtPos1, ptrPos2
  20.   for i := 0 to 49 do Memo1.Lines.Add(inttostr(ptrPos1^[i]));
  21.   for i := 0 to 49 do Memo1.Lines.Add(inttostr(ptrPos2^[i]));
  22. end;
One issue is you can't use low() and high(). But since you already know exactly the indexes when you're splitting it, you just need to manually deal with knowing how long the array is.

balazsszekely

  • Guest
Re: Splitting an array in two using pointers
« Reply #3 on: January 17, 2017, 02:28:34 pm »
Quote
@User137
Problem with that would be that if you change the original TheList later, you would need to copy values again. Using pointers would be just referencing and therefore faster code
That's true, but then why split the original array, I mean instead off:
Code: Pascal  [Select][+][-]
  1.  for i := 0 to 49 do Memo1.Lines.Add(inttostr(ptrPos1^[i]));
  2.  for i := 0 to 49 do Memo2.Lines.Add(inttostr(ptrPos2^[i]));
  3.  
You can do:
Code: Pascal  [Select][+][-]
  1.  for i := 0 to 49 do Memo1.Lines.Add(inttostr(TheList[i]));
  2.  for i := 50 to 99 do Memo2.Lines.Add(inttostr(TheList[i]));

PS: Of course it all depends on what the OP is after and how large/type the original array is.
« Last Edit: January 17, 2017, 02:30:37 pm by GetMem »

derek.john.evans

  • Guest
Re: Splitting an array in two using pointers
« Reply #4 on: January 17, 2017, 02:37:52 pm »
You could try a generic type which implements a sub array.
Code: Pascal  [Select][+][-]
  1. type
  2.   generic TSubArray<T> = object
  3.   public
  4.     type Instance = T;
  5.     type Pointer = ^Instance;
  6.     type DynArray = array of Instance;
  7.   public
  8.     Data: Pointer;
  9.     Low, High: integer;
  10.   private
  11.     function GetItem(AIndex: integer): Instance;
  12.     procedure SetItem(AIndex: integer; const A: Instance);
  13.   public
  14.     class function Create(var A: DynArray; ALow, AHigh: integer): TSubArray;
  15.   public
  16.     property Items[A: integer]: Instance read GetItem write SetItem; default;
  17.   end;
  18.  
  19. class function TSubArray.Create(var A: DynArray; ALow, AHigh: integer): TSubArray;
  20. begin
  21.   Result.Data := Pointer(A);
  22.   Result.Low := ALow;
  23.   Result.High := AHigh;
  24. end;
  25.  
  26. function TSubArray.GetItem(AIndex: integer): Instance;
  27. begin
  28.   Result := Data[AIndex];
  29. end;
  30.  
  31. procedure TSubArray.SetItem(AIndex: integer; const A: Instance);
  32. begin
  33.   Data[AIndex] := A;
  34. end;  
  35.  

Usage:

Code: Pascal  [Select][+][-]
  1. type
  2.   TIntegerSubArray = specialize TSubArray<integer>;
  3. var
  4.   LIndex: integer;
  5.   LArray: array of integer;
  6. begin
  7.   SetLength(LArray, 100);
  8.   for LIndex := Low(LArray) to High(LArray) do begin
  9.     LArray[LIndex] := LIndex;
  10.   end;
  11.   with TIntegerSubArray.Create(LArray, 0, 5) do begin
  12.     for LIndex := Low to High do begin
  13.       ShowMessage(IntToStr(Items[LIndex]));
  14.     end;
  15.   end;
  16.   with TIntegerSubArray.Create(LArray, 20, 30) do begin
  17.     for LIndex := Low to High do begin
  18.       ShowMessage(IntToStr(Items[LIndex]));
  19.     end;
  20.   end;
  21. end;  
  22.  

But, I'd look into other options first.

glorfin

  • Full Member
  • ***
  • Posts: 148
  • LMath supporter
Re: Splitting an array in two using pointers
« Reply #5 on: January 17, 2017, 04:13:36 pm »
Why not to use simply typed pointers?
Code: Pascal  [Select][+][-]
  1. type
  2.   TMyArr = array[0..1000] of Float; // or of whatever
  3.   TArrPtr = ^MyArr;
  4. var
  5.   ActualArr : TMyArr;
  6.   PtrPos1, PtrPos2 : TArrPtr;
  7.  begin
  8.   SetLength(ActualArr, 100);
  9.   PtrPos1 := @ActualArr[0];
  10.   PtrPos2 := @ActualArr[50];
  11.   PtrPos1^[25] := 7.0;
  12. ........
  13.  
Of course, it is then your responsibility not to go beyond actual range.

Hope, this helps.

Thaddy

  • Hero Member
  • *****
  • Posts: 14210
  • Probably until I exterminate Putin.
Re: Splitting an array in two using pointers
« Reply #6 on: January 17, 2017, 04:52:16 pm »
Well, that looks like a fixed array?
Why a dynamic array?
You can use ranges to do what you want.
Here's an example (with an intentional error):
Code: Pascal  [Select][+][-]
  1. {$ifdef fpc}{$mode delphi}{$H+}{$endif}
  2. {$rangechecks on}
  3. type
  4.   TPtrPos1 = 0..49;
  5.   TPtrPos2 = 50 ..99;
  6.   TFullRange = Low(TPtrPos1)..High(TPtrPos2);
  7. var
  8.   TheList: array[TFullrange] of integer;
  9.   ptrPos1:TPtrPos1 = Low(TPtrPos1);
  10.   ptrPos2:TPtrPos2 = Low(TPtrPos2);
  11.   i:integer;
  12. begin
  13.   writeln(PtrPos1 :4,PtrPos2 :4);
  14.   Inc(PtrPos1);
  15.   writeln(PtrPos1 :4,PtrPos2 :4);  
  16.   //Dec(PtrPos2); // rangecheck error! ;)
  17.   for i := Low(PtrPos1) to High(PtrPos1) do
  18.     TheList[i] := 0; // do something
  19.   for i := Low(PtrPos2) to High(PtrPos2) do
  20.     TheList[i] := 10; // do something
  21.   writeln(TheList[High(PtrPos1)]:4,TheList[High(PtrPos2)]:4);
  22. end.
« Last Edit: January 17, 2017, 05:05:19 pm by Thaddy »
Specialize a type, not a var.

MortenB

  • Jr. Member
  • **
  • Posts: 59
Re: Splitting an array in two using pointers
« Reply #7 on: January 17, 2017, 06:43:49 pm »
Problem with that would be that if you change the original TheList later, you would need to copy values again. Using pointers would be just referencing and therefore faster code
Code: Pascal  [Select][+][-]
  1. type
  2.   TListArray = array[0..0] of TheListType;
  3. var
  4.   TheList: array of TheListType;
  5.     ptrPos1, ptrPos2: ^TListArray;
  6.  
  7. begin
  8.   SetLength(TheList, 100);
  9.   ptrPos1 := @TheList[0];
  10.   ptrPos2 := @TheList[50];
  11.   ... ... ...
  12. end;

One issue is you can't use low() and high(). But since you already know exactly the indexes when you're splitting it, you just need to manually deal with knowing how long the array is.

Yesss.
Thank you so much for this information. I simply hadn't tried the ARRAY[0..0] type declaration, but that worked wonders!
And. You are Most correct. Using only pointers mean faster code.
And yes. I would know the size of the array and where to split it, and I would never actually need the HIGH()-function on these pointers. Everything is precalculated.

Thank you again.
Morten.

MortenB

  • Jr. Member
  • **
  • Posts: 59
Re: Splitting an array in two using pointers
« Reply #8 on: January 17, 2017, 07:00:30 pm »
My problem has been solved, and the solution was of course easier than I thought. Isn't it always like that  >:D

Where several users had something that may work, my main aim was to find something I could use in a fully dynamic way. Dynamically setting the array size, and dynamically dividing it in two, using no fixed definition or sizes in any types. The solution given was doing just that!

I am still thankful for all other suggestions and answers. They all give me ideas.

Most appreciated. :)

Morten.

 

TinyPortal © 2005-2018