Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations SkipVought on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Trunc of multidimensional dynamic arrays 1

Status
Not open for further replies.

ElenaKB

Programmer
Jun 24, 2008
6
0
0
GB
I have a large 2 dimensional dynamic array of doubles.

I want to "crop" it in an elegant way, e.g. use a function SetDimensions(xstart, ystart, xend, yend) on it. Now the "high" end is no problem, I can just call SetLength(myDynArray, xend, yend) and it will either enlarge or reduce the size of the array to what I want. But how do I do it at the "low" end? i.e. how do I release the memory for the first 10 rows and columns of my array?

I could iterate through all the elements and copy them into a new array, and then trash the original, but that is not so elegant.

Any suggestions appreciated.
 
i.e. how do I release the memory for the first 10 rows and columns of my array?

You don't. Not in the way you want.

I could iterate through all the elements and copy them into a new array, and then trash the original, but that is not so elegant.

But that's the only way.

It seems like the array isn't the right tool for what you are wanting to do. You might consider telling us what you are trying to do with this array and why and we might be able to come up with a better idea for the task at hand.

----------
Measurement is not management.
 
Wow, what a quick reply - thanks very much!

My program manipulates measured data values, at the moment about 200 x 200 doubles, but I want it to be able to do 1000x1000 or more. The user can then view this data as a 3D surface chart. He may want to edit certain points, apply verious filters etc and crop edges. I have created a DataHolder object, which containes the dynamic array and verious methods for creating, deleting and accessing the array, this is where the above ChangeDimensions(xStart, yStart, xEnd, yEnd) comes in. I mistakenly called it SetDimensions earlier, I have that routine as well, but it is used to initialise the dynamic array, i.e. allocate memory for it the very first time.

I used static arrays originally, which was fine when the measurement program which produces the data had a fixed size for the number of points it measures. Now the program allows scans of any size, so I must be able to cope with that too.
 
A thought here: The array isn't such a bad tool if your data are structured in a table format - which it seems to be. Maybe the way to access it might need to change though.

Instead of working from table element [1,1] all the time, you might define a pointer and set it to be whatever your base position is at the time.

You won't be able to free up the memory (that would take making a new array, copying, etc) on the low side of the resize, but you'll be able to work from that pointer position into the rest of the table.

Then for whatever that works on the table, I would have it pass the pointer as a parm and then typecast it to your table within the function to work on it (or do pointer math, or whatever works best).

Keep track of the borders of your actual memory allocation (I would consider starting out by defining a "base size" of the table, consisting of what would work for most cases and leave it at that), and then expand/contract the right boundaries as needed.

Hope that gives you a starting idea anyway.

----------
Measurement is not management.
 
Nice to get confirmation for what I had thought myself, that what I wanted to do wasn't possible. My mistake was thinking of my dynamic array as a continuous block of memory with a pointer to it's start, so what I wanted to do was make that pointer point to a new start further into the array and release the parts not needed. Which is a bit like you are suggesting, without releasing the memory.

I am a C++ programmer just starting with Delphi so am finding it a bit tedious at times with its tight typechecking when I am just wanting to use simple pointers.
 
For a more "elegant" approach, have a look at:

procedure Move(const Source; var Dest; Count: integer);


Roo
Delphi Rules!
 
Do or not do, there is no "impossible" unless you make it so...

Case in point:
I am a C++ programmer just starting with Delphi so am finding it a bit tedious at times with its tight typechecking when I am just wanting to use simple pointers.

Remember that word "typecast" in my last post? That's the key word. You don't find out if you do not try...I wouldn't do this unless I had fully dynamic data (i.e. can be double, integer, string, etc), but it's an illustration that would be fitting now. Works as indicated except for the memory freeing stuff, which I presume was hobbled (probably with good reason) - again as was pointed out, nothing wrong with leaving the front side there.

But remember though, 99.99% of the time, strict type-checking is your friend.

Code:
{$APPTYPE CONSOLE}
program dynmem; uses sysutils;
  var
    allocptr, newalloc: pointer;
    workptr: pointer;
    elements, arraycut: integer;
    i: integer;

  procedure writedata(workptr: pointer);
    var
      i: integer;
    begin
      for i := 1 to elements do
        begin
          writeln(Double(workptr^):0:5);
          inc(Integer(workptr), sizeof(Double));
        end;
    end;

  begin
    write('Number of double elements: ');
    readln(elements);
    GetMem(allocptr, elements * Sizeof(Double));
    { puts data 1..20 into double array }
    workptr := allocptr;
    for i := 1 to elements do
      begin
        Double(workptr^) := i;
        inc(Integer(workptr), sizeof(Double));
      end;
    { write the array }
    workptr := allocptr;
    writedata(workptr);

    write('Cut the array off after what position?');
    readln(arraycut);
    dec(elements, arraycut); // adjust array size
    { now attempt to cut the array at the element specified }
    Integer(workptr) := Integer(workptr) + (arraycut * sizeof(Double));
    newalloc := workptr;
    FreeMem(allocptr, (arraycut * sizeof(Double))); // this passes muster
    allocptr := newalloc;

    { start work ptr at the end of element given and write data }
    workptr := allocptr;
    writedata(workptr);
    try
      FreeMem(allocptr, elements * sizeof(Double)); // this line produces EInvalidPointer
    except
      On EInvalidPointer do writeln('Invalid pointer op.');
    end;
    writeln;
    write('Press a key.');
    readln;
  end.

----------
Measurement is not management.
 
Thanks for the ideas. I'll play with them and I know the right solution will present itself.
Cheers!
 
FWIW, here's the proper working program for Delphi. The previous program didn't work because the memory manager ties specific memory allocations to the specific pointer. Specifying the size in FreeMem isn't relevant.

Notice that allocptr is not touched after the allocation. Newalloc is used to reference the start of the work area.

Code:
{$APPTYPE CONSOLE}
program dynmem; uses sysutils;
  var
    allocptr, newalloc: pointer;
    workptr: pointer;
    elements, arraycut: integer;
    i: integer;

  procedure writedata(workptr: pointer; elements: integer);
    var
      i: integer;
    begin
      for i := 1 to elements do
        begin
          writeln(Double(workptr^):0:5);
          inc(Integer(workptr), sizeof(Double));
        end;
    end;

  begin
    write('Number of double elements: ');
    readln(elements);
    GetMem(allocptr, elements * Sizeof(Double));
    newalloc := allocptr;
    { puts data 1..20 into double array }
    workptr := newalloc;
    for i := 1 to elements do
      begin
        Double(workptr^) := i;
        inc(Integer(workptr), sizeof(Double));
      end;
    { write the array }
    writedata(newalloc, elements);

    write('Cut the array off after what position?');
    readln(arraycut);
    dec(elements, arraycut); // adjust array size

   { now attempt to cut the array at the element specified }
    Integer(newalloc) := Integer(allocptr) + (arraycut * sizeof(Double));

    writedata(newalloc, elements);
    FreeMem(allocptr);
    writeln;
    write('Press a key.');
    readln;
  end.

----------
Measurement is not management.
 
Glenn - This info, combined with that in thread102-1484875 would make my suggestion of using the Move() command a bad idea for dynamic arrays, although it does work well for truncating static arrays. (Just for the record and the sake of future archive searches for "array".)
And since the OP did not give you one for all your hard work, another *4u.

Roo
Delphi Rules!
 
Yes - if memory was such a concern in the other post, one could apply a method like in the program and then calculate addresses, either directly or with a typecast. Probably much more efficient than the 2-dim dynamic array the other poster proposed. Even better for clarity would be to create a 1-dim array typecast of absurd size (which would fit for this OP too) and typecast the GetMem pointer to that.

The major benefits would be much less processing in terms of following pointers out (only one of them to deal with), and the ability to handle the entire array as one unit (like with blockread/blockwrite, and the pointer math I did in this program). The major deficiency compared to the dynamic array would be the calculations for the addressing, but that's a small hurdle to overcome to do yourself (the array addressing is always one of those "behind the scenes" things if you define one).

Even better, though, would be to simply use the static array with a high but reasonable boundary and process against it using the capacities that were given in the file. But all is relative depending on requirements.

(and I apologize for the word "table" slipping in there - that's common terminology for another language I have proficiency in)

----------
Measurement is not management.
 
Here is *** for Glenn! And some for roo too!

After trying out various things with copying and moving etc and each time running into unexpected problems, I've implemented Glenn's suggestion of having a base value from which I calculate the indexes. So the array does not actually get cropped, no memory is freed at the lower end, but at least I get no out of bounds errors!

I read the other thread too. Dynamic arrays are obviously much more complicated than I thought. This array is such an essential part of my program, that I have to be sure myself that what I am doing is completely safe.
 
Dynamic arrays are obviously much more complicated than I thought.

Yes they looks like a good idea in the manual? But not generally encouraged I would say, as you have seen.

Delphi comes with powerful Database components (a whole other ball game) that might be the way to go if your data sets are large, variable and at all complex.

I write embedded 'C' and don't really understand your comment about types.
Glenn is quite right when he says Delphi's type checking is good.
But looser checking in 'C' is not a good thing you forget data types at your peril!


Steve: N.M.N.F.
If something is popular, it must be wrong: Mark Twain
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top