Recent

Author Topic: Problem with the pointer that points to the first element of a dynamic array  (Read 5701 times)

carlejt

  • New Member
  • *
  • Posts: 39
Hello

I use Lazarus 1.6 - Free Pascal 3.0 - Win7-32

I do not know if this is a bug, when I have a dynamic array empty and increase its length in one, and then get the address of the first element, this direction stops point where should I just after increase for the second time the length of the array in one.

A simple program that shows the effect:

Code: Pascal  [Select][+][-]
  1. program Project1;
  2. var
  3. a: array of integer;
  4. p: ^integer;
  5.  
  6. begin
  7.   setlength(a, 0);
  8.   setlength(a, length(a)+1);
  9.   a[0] := 66;
  10.   p := @a[0];
  11.   setlength(a, length(a) + 1);
  12.   a[0] := 77;
  13.  
  14.   writeln(a[0], ',', p^, ',', p=@a[0]); // write 77, 66, False
  15.  
  16.   readln;
  17. end.
  18.  

In response to this problem, my doubts are:

1) The change of address of the first element should occur or is bug?

2) If it is a bug as solve the problem?, because it is very uncomfortable having to change the value of a pointer to the first element when the array increases in length.

Thank you for your attention.

julgus

  • New Member
  • *
  • Posts: 29
Seems not to be a bug:
http://wiki.freepascal.org/Dynamic_array

"Although writing to elements of dynamic arrays does not create a new instance of the array (no copy-on-write as it exists for Ansistrings) using SetLength on such arrays does create a copy! So if 2 dynamic array variables point to the same array (one has been assigned to the other) they do not do so after using SetLength on one (or both) of them. After the SetLength() call the two variables are distinct arrays whose elements are independent from each other."

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
The change is allowed, so no bug.

The change does not happen always, but it does happen often, and it can happen at any time (any setLength). It can happen at different times, if you run the same code twice

setLength allocates memory for either exact, or sometimes a few extra elements. (depends on various factors, and may change with fpc versions).

If there had been extra mem, then no change of address occurs (but there is no way to know when this is. So you can not use this)

Otherwise the entire array is moved to a new location. This is because the array must always be one continuous block of mem.

-----------
The question is, why you need the pointer, why not use a[0] ?
« Last Edit: October 28, 2016, 06:00:05 am by Martin_fr »

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
Seems not to be a bug:
http://wiki.freepascal.org/Dynamic_array

"so if 2 dynamic array variables point to the same array (one has been assigned to the other) they do not do so after using SetLength on one (or both) of them. After the SetLength() call the two variables are distinct arrays whose elements are independent from each other."
That quote does not apply here.

only "a" holds the array.

The pointer p points to it, but does not count for copies.

Code: Pascal  [Select][+][-]
  1. var a, b: array of integer;
  2.  a := b // @a[n] = @b[n]
  3.  
then both var have the same array (same memory, no copy)

But the array knows it is hold twice, and then SetLenght(b, xxx) changes b only (and therefore at that point b becomes a copy (b gets its own memory @a[n] <> @b[n]).

In either case, a pointer to the array, can become invalid with any SetLenght.

julgus

  • New Member
  • *
  • Posts: 29
No, not exactly but it illustrates the problem I think.

Thaddy

  • Hero Member
  • *****
  • Posts: 14210
  • Probably until I exterminate Putin.
Code: Pascal  [Select][+][-]
  1. var a, b: array of integer;
  2.  a := b // @a[n] = @b[n]
  3.  

If you want the expected behavior that is indeed wrong, but this code simply does it:
Code: Pascal  [Select][+][-]
  1. program untitled;
  2. {$ifdef fpc}{$mode delphi}{$endif}
  3.  
  4. var
  5.  a: array of integer;
  6.  b: array of integer absolute a;
  7.  
  8. begin
  9.   setlength(a,100);
  10.   writeln(length(b));  // 100
  11.   setlength(a,300);
  12.   writeln(length(b)); // 300
  13. end.

It is about choosing the right syntax for the type of job on hand.
Specialize a type, not a var.

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Class comes to rescue in some cases
Code: Pascal  [Select][+][-]
  1. program Project1;
  2.  
  3. type
  4.   TMyClass = class
  5.     a: integer;
  6.   end;
  7.  
  8. var
  9.   a: array of TMyClass;
  10.   p: TMyClass;
  11.  
  12. begin
  13.   setlength(a, 0);
  14.   setlength(a, length(a)+1);
  15.   a[0] := TMyClass.Create;
  16.   a[0].a := 66;
  17.   p := a[0];
  18.   setlength(a, length(a) + 1);
  19.   a[0].a := 77;
  20.  
  21.   writeln(a[0].a, ',', p.a, ',', @p = @a[0], ',', p = a[0]); // write 77,77,False,True
  22.  
  23.   readln;
  24. end.

Same wouldn't work with records.

totya

  • Hero Member
  • *****
  • Posts: 720
...Otherwise the entire array is moved to a new location. This is because the array must always be one continuous block of mem.

Thanks for this information :)

"a" array memory address changed under win32, so the p^ value will not change. Under win64 the result is is okay if array size changed +1, but from +2 the result too "bad". I think you are right, so this isn't bug.

Quote
a[0] address: 023718B0
p address: 023718B0
After array length changed (win32): (+1)
a[0] address: 023400F0
p address: 023718B0
77,66,0

Quote
a[0] address: 0000000001134E40
p address: 0000000001134E40
After array length changed: (win64) (+1)
a[0] address: 0000000001134E40
p address: 0000000001134E40
77,77,-1

Quote
a[0] address: 00000000011D4E40
p address: 00000000011D4E40
After array length changed: (win64) (+2)
a[0] address: 00000000011B3200
p address: 00000000011D4E40
77,66,0

carlejt

  • New Member
  • *
  • Posts: 39
Many thanks to all of you for responding. Martin_fr if the arrangement has length 2, it seems that the addresses do not change, should trust it?. User137, it is interesting to the properties of the Class (pity that not work with objects or records).

Now I can continue with my project. (Maybe use array of class or an array of length 2)

Many thanks for all the attention, guidance and suggestions.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 9794
  • Debugger - SynEdit - and more
    • wiki
Quote
f the arrangement has length 2, it seems that the addresses do not change

No, do not trust it.

This behaviour can change: new fpc version, other OS, other cpu, .....

The simple truth is: any pointer to an array element, will be invalid after a SetLength.

If it sometimes is not, that is pure random luck. Even if this "luck" happens on all your PC, it might still break on someone elses, or in future.

carlejt

  • New Member
  • *
  • Posts: 39
Thank you very much Martin_fr

 

TinyPortal © 2005-2018