I'm just curious, I was using setLength to increment my arrays all the while but i've been hoping..

is there any push and pop functions for delphi so that i can dynamically put values into my array without having to code anything myself to increase the array size?

Recommended Answers

All 10 Replies

I'm just curious, I was using setLength to increment my arrays all the while but i've been hoping..

is there any push and pop functions for delphi so that i can dynamically put values into my array without having to code anything myself to increase the array size?

ADrive, pushing and popping in that way goes entirely against the whole philosophy of Pascal. The raw code to do what you want goes something like this

1. type TADriveArr = array[MAXWORD] of Integer;
2.        PADriveArr = ^TADriveArr;

procedure UseADriveArr;
3. var P:PADriveArr;

   procedure ExpConArray(ACount);
   begin
4.       ReAllocMem(P,ACount*sizeof(Integer));
   end;
begin
5.   P:=AllocMem(sizeof(Integer)*32);
try
  //DoSomeStuff
6.  if TestCond then ExpConArra(96)y else ExpConArray(16);
  //DoMoreStuff  e.g. P^[1]:=255;
finally ReAllocMem(P,0) end;
end;

The key features you need to understand here are these

  1. The type declaration is just that - the declaration of an intent to use an array of the specified type having a maximum of MAXWORD elements. Naturally, you can use a different type and a different number of maximum elements. Remember that your first index will be zero!
  2. The pointer is required for us to handle dynamic memory allocation to manipulate an array of type TADriveArr
  3. We use a local variable of type PADriveArr
  4. The ExpConArray function is used to change the size of the array. This is the only way to do the equivalent Push and Pop in Delphi. Remember that if you attempt to dereference an array element you have not assigned memory for, Delphi will oblige! Write to that location and you are liable to have an almighty crash. Also, if you shrink the array the data beyond the preshrink location is not immediately lost. Nevertheless you should no longer access it.
  5. For starters we allocate enough memory for our array to accommodate 32 integers
  6. During code execution we dynamically expand(push) or shrink (pop) the array

Needless to say this is a great deal more complicted than Push and Pop. If you are not used to pointers it is also rather daunting. Besides, you don't get back the same feedback as you do with the Push and Pop functions. The solution to this is typical of Delphi - instead of using the messy code above just create an object which encapsulates the functionality that you require - including the Push and Pop functions. Then use that object.

I am afraid this is liable to come as something of a disappointment. However, it is the right way to do things and what makes Delphi such an efficient language. If you don't feel up to the task just yet take a look around Torry - you might find someone who has created an object wrapper which does everything you want.

Er, it doesn't go against Pascal's philosophy at all. The STL just does things from a different point of view.

If you want to push and pop, it should be easy enough to write your own procedures to do that. Keep in mind, however, that Pascal doesn't (yet) have a standardized template capability (some Pascals extend Schemata to do it --which I think is the Right Thing... but anyway):

Push/Pop an int array:

uses SysUtils;

procedure pushInt( var xs: array of integer; x: integer );
  begin
  setLength( xs, length( xs ) +1 );
  xs[ high( xs ) ] := x
  end;

function popInt( var xs: array of integer ): integer;
  begin
  if length( xs ) = 0
    then raise Exception.Create( 'popInt: nothing to pop' );
  result := high( xs );
  setLength( xs, high( xs ) )
  end;

Finally, ExplainThat, you need to stop pushing bare pointer usage on everyone. It is good to know how they work and how to use them, but they are not the answer to all questions. Their usage is deprecated in Pascal just as in every other language because:
- they are not type safe (even in Pascal, where they are more carefully typed than anywhere else!)
- they reduce the compiler's ability to use meta information that structured data contains
- they introduce programmer errors
- (there's more, but I have to go right now...)

Er, it doesn't go against Pascal's philosophy at all. The STL just does things from a different point of view.

If you want to push and pop, it should be easy enough to write your own procedures to do that. Keep in mind, however, that Pascal doesn't (yet) have a standardized template capability (some Pascals extend Schemata to do it --which I think is the Right Thing... but anyway):

Push/Pop an int array:

uses SysUtils;

procedure pushInt( var xs: array of integer; x: integer );
  begin
  setLength( xs, length( xs ) +1 );
  xs[ high( xs ) ] := x
  end;

function popInt( var xs: array of integer ): integer;
  begin
  if length( xs ) = 0
    then raise Exception.Create( 'popInt: nothing to pop' );
  result := high( xs );
  setLength( xs, high( xs ) )
  end;

Finally, ExplainThat, you need to stop pushing bare pointer usage on everyone. It is good to know how they work and how to use them, but they are not the answer to all questions. Their usage is deprecated in Pascal just as in every other language because:
- they are not type safe (even in Pascal, where they are more carefully typed than anywhere else!)
- they reduce the compiler's ability to use meta information that structured data contains
- they introduce programmer errors
- (there's more, but I have to go right now...)

I know I'm just a novice, but perhaps you could use a TStack to have your pushes and pops. But it would imply in pointer manipulation, so you have to weight if it is worth the trouble and remember to free all the structures you created. In this particular case, where you want to save integers, you can just use a cast, as pointers and integers, if I'm not mistaken, have the same size or integers are smaller than pointers

There is nothing wrong in using pointers when you need to. Since a TStack doesn't have any idea what kind of thing you intend to store (push and pop), it must recur to the most generalized thing: a pointer. You'll just have to cast it to the proper thing when you pop or peek it.

It might be worth it to spend the twenty lines of code or so to derive from TStack something that works specifically with your data type. Thus all casting and pointer errors are confined to one spot and not spread out over your code.

For example, if you wish to handle a record:

type
  PEmployee = ^TEmployee;
  TEmployee = record
    name: string[ 128 ];
    payrate: currency
    end;

  TEmployeeStack = class( TStack )
    public
      function peek: TEmployee;
      function pop: TEmployee;
      procedure push( employee: TEmployee );
    end;

implementation

  function TEmployeeStack.peek: TEmployee;
    begin
    result := PEmployee( inherited peek )^
    end;

  function TEmployeeStack.pop: TEmployee;
    var pe: PEmployee;
    begin
    pe := PEmployee( inherited pop );
    result := pe^;
    dispose( pe )
    end;

  procedure TEmployeeStack.push( employee: TEmployee );
    var pe: PEmployee;
    begin
    new( pe );
    pe^ := employee;
    inherited push( pe )
    end;

Now when you use a stack of employees you don't need to worry about the pointers being used behind the scenes, and you can deal directly with the employee records.

This version of peek prevents you from directly modifying the last item on the stack. You must pop, modify, then push to change it. If you really, really want to do it directly you can of course:

function peek: PEmployee;
  begin
  result := PEmployee( inherited peek )
  end;

but you must remember to dereference it properly when using peek. writeln( 'The current employee's pay rate is ', myEmployees.peek^.payrate ); You can do the same sort of thing for any type of thing you wish to keep in a stack.

The problem, of course, with a stack is that it forbids random access. Unlike an array, you can only access the last item pushed (the whole point of a stack).


I think that either GNU Pascal or Free Pascal extend schemata to define templated procedures and functions, but I can't remember for sure.

Hi, Duoas. I agree entirely with you and I used exactly that when I was teaching data structures and in systems programming in general. In this very specific case, I considered (my fault?) that he wanted to use the array as a stack and he would deal with integers only. So I presented a "quick and (very) dirty" solution to have a stack of integers where one would not need to create or dispose of records.

Probably I should have kept it to myself instead of confusing someone (adrive). My apologies.

I've done my fair share of confusing people. :$

It has always been dangerous to assume that pointers and integers are compatible, but programming practice on a PC encouraged it for so many years...

Alas.

Member Avatar for Micheus

Push/Pop an int array:

uses SysUtils;

procedure pushInt( var xs: array of integer; x: integer );
  begin
  setLength( xs, length( xs ) +1 );
  xs[ high( xs ) ] := x
  end;

function popInt( var xs: array of integer ): integer;
  begin
  if length( xs ) = 0
    then raise Exception.Create( 'popInt: nothing to pop' );
  result := high( xs );
  setLength( xs, high( xs ) )
  end;

Good Duos, right to the point!
But (every time has a but... :icon_smile:) at line 13 I think that something is wrong. I think It must be:
result := xs[[/B]high( xs )[B]];

Finally, ExplainThat, you need to stop pushing bare pointer usage on everyone. It is good to know how they work and how to use them, but they are not the answer to all questions.

At this point, I have to agree.
But (again...) I think that must has an others ways to say this without come it to personal side (It's came frequent between You).
Everyone has your view point about a subject in agreement your know how and experience. ;-)

Bye

at line 13 I think that something is wrong. I think It must be: result := xs[high( xs )];

Nice catch! (That's what I get whenever I just type something in...)

I think that must has an others ways to say this without come it to personal side (It's came frequent between You).
Everyone has your view point about a subject in agreement your know how and experience. ;-)

I didn't mean to come across as caustic.

thanks guys for the confirmation, I actually thought there was some system functions to do this.

You don't need to write it yourself!
If you're looking for fast and easy List handling, you need the TList class, not an array. Or TStack if you only need push and pop, but again, that's not for objects or pointers like this. And there is a separated class for storing intefaces too!
It's just because Delphi prefer composing things, not expanding like C does. In Delphi you only have to use arrays, if you're looking for a fast way for example to process images.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.