PDA

View Full Version : Are you delphi pointer pro?



siim
23-11-2003, 12:11 PM
It has been very quiet here lately, so I posted a little exercise for you.
Here is the question: What are those 6 ShowMessages displaying?
No testing with Delphi allowed.



function Get1(var X): Integer;
var
L: Integer absolute X;
begin
Result := PInteger(L-4)^;
end;

function Get2(var X): Integer;
asm
mov EAX, [EAX-4]
end;

procedure TForm1.Button4Click(Sender: TObject);
type
PIntArray = ^TIntArray;
TIntArray = array[0..MaxInt div SizeOf(Integer) - 1] of Integer;
var
pInt: ^Integer;
PTest: array of Integer;
begin
SetLength(PTest, 5);
PTest[0] := 57;PTest[1] := 1;PTest[2] := 2;PTest[3] := 3;PTest[4] := 4;
pInt := @PTest[0];
Inc(pInt, 3);
ShowMessage(IntToStr(pInt^)); // 1
Dec(pInt, 4);
ShowMessage(IntToStr(pInt^)); // 2
ShowMessage(IntToStr(Get2(PTest[0]))); // 3
ShowMessage(IntToStr(Get1((@PTest)^))); // 4
pInt := @PTest;
pInt := Pointer(pInt^);
ShowMessage(IntToStr(pInt^)); // 5
ShowMessage(IntToStr(PIntArray(pInt)[2])); // 6
end;

siim
23-11-2003, 02:51 PM
This is not about pointers, but ...
Exrecise no 2:



procedure TForm1.Button6Click(Sender: TObject);
var
a, b: Integer;
begin
a := 345;
b := 7690;
ShowMessage(IntToStr(a)+':'+IntToStr(b)); // 1
a := a xor b;
b := b xor a;
a := a xor b;
ShowMessage(IntToStr(a)+':'+IntToStr(b)); // 2
a := a + b;
b := a - b;
a := a - b;
ShowMessage(IntToStr(a)+':'+IntToStr(b)); // 3
end;



Siim

Paulius
23-11-2003, 06:42 PM
For the second one:
345:7690
7690:345
345:7690
Just looking at the first one makes my eyes hurt, so I?¢_Tll skip it for today :P

Useless Hacker
23-11-2003, 09:54 PM
Okay, for the first one I'm going to go with:

256
14592
-1
-1
1
2

Chances are most - if not all - of those are wrong, though... :scratch:

Personally, I think anyone writing code like that would get fired pretty soon!

Useless Hacker
25-11-2003, 12:43 PM
I pasted the code into Delphi... It seems the actual results are:

3
5
5
5
57
2

Well, at least I got one right! :oops:

Alimonster
25-11-2003, 02:50 PM
I pasted the code into Delphi... It seems the actual results are:

3
5
5
5
57
2

Well, at least I got one right! :oops:
Heh, at least you gave answers. ;) I got most of them but since I didn't post it then nobody would believe me!

Number 1: the pointer is pointed to the first element of the 5-element array. It's then inc'd on 3 places, meaning it goes to ptest[3] instead of ptest[0]. Ptest[3] = 3

Number 2: the pointer is dec'd four positions. This moves it before the first actual element, onto the internal array length int. This you might remember if you ever used Delphi 1 and its strings (my_string[0] there being the length of the array, later replaced with Length and SetLength, I believe, in Delphi 2).

Number 3: the parameter to the func will be passed in the accumulator (EAX). The value [EAX - 4] means "dereference the address 4 earlier (sizeof integer) than the given variable," which would be the value before the first array element. At least, if I remember my asm right. :) Again, the size of the array. From the help files: "The built-in assembler treats var parameters as a 32-bit pointers."

EDIT: It's also worth mentioning that the results of functions are put into the accumulator (al, ax or eax)...

Number 4: same deally here - the absolute directive (deprecated, IIRC) places the variable at the same spot in memory as the given var -- so it would be the same address as the untyped parameter. And I believe it works much the same as the previous asm routine.

Number 5: I admit that I was initially a little stumped by the fancy footwork here. Here's what I thought happens...

pInt := @PTest;
pInt := Pointer(pInt^);

Dynamic arrays are dynamically allocated, hence they're pointers with fancy compiler support. pInt is pointed to a pointer's (the array's) address-of, then dereferenced (the original array address again) and cast as a pointer. So, it's still pointing to the first element of the array, I believe, when next dereferenced (ptest[0] = 57). ;)

Number 6: not exactly a difficult one here. :) Just treat the pint pointer as a pointer to an array of integers starting at the same pos as the first element of the dynamic array. So return the value of ptest[2], in other words, which is 2.

Loved these puzzles. If I got any of the above wrong then please let me know! Got any more of these puzzles for us (or maybe I'll try to think up one...)?

Useless Hacker
25-11-2003, 05:42 PM
Number 1: the pointer is pointed to the first element of the 5-element array. It's then inc'd on 3 places, meaning it goes to ptest[3] instead of ptest[0]. Ptest[3] = 3

Number 2: the pointer is dec'd four positions. This moves it before the first actual element, onto the internal array length int. This you might remember if you ever used Delphi 1 and its strings (my_string[0] there being the length of the array, later replaced with Length and SetLength, I believe, in Delphi 2).
I had thought that Inc(pInt, 3) would increase the pointer by 3 bytes, and that Dec(pInt, 4) would decrease it by 4 bytes...

I'm not quite sure how I got those minuses for 3 and 4 :?

Useless Hacker
25-11-2003, 05:46 PM
I had thought that Inc(pInt, 3) would increase the pointer by 3 bytes, and that Dec(pInt, 4) would decrease it by 4 bytes...
but then again...

procedure Inc(var X [ ; N: Longint ] );

Description

In Delphi code, Inc adds one or N to the variable X.

X is a variable of an ordinal type (including Int64), or a pointer type if the extended syntax is enabled.

N is an integer-type expression.

X increments by 1, or by N if N is specified; that is, Inc(X) corresponds to the statement X := X + 1, and Inc(X, N) corresponds to the statement X := X + N. However, Inc generates optimized code and is especially useful in tight loops.

Note: If X is a pointer type, it increments X by N times the size of the type pointed to.

siim
26-11-2003, 09:39 PM
Very well explained Alimonster.
Okay another puzzle...
Exercise no 3:
There may be more than one solution for this problem. And for some people the problem might be very easy to solve.
A crazy programmer (me?!?) has design a component with eventhandler like this:


TOnChange = procedure(var I: Integer);
TMyObject = class
private
FOnChange: TOnChange;
public
property OnChange: TOnChange read FOnChange write FOnChange;
end;

You want to keep your code object-oriented at all costs and you want to attach a method DoIt with this event so you do something like this:


TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
private
{ Private declarations }
Obj: TMyObject;
procedure DoIt(var I: Integer);
public
{ Public declarations }
end;

var
Form1: TForm1;

implementation

{$R *.DFM}

{ TForm1 }
procedure TForm1.DoIt(var I: Integer);
begin
ShowMessage(IntToStr(I));
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
Obj := TMyObject.Create;
Obj.FOnChange := DoIt;
end;

Remember that you can't change anything that crazy programmer has already done (TOnChange is done by a crazy programmer) and you have to keep things object-oriented.
The code above doesn't even compile. Your job is to fix it.

Siim

Canderel
22-04-2004, 08:10 AM
I am not quite sure what you want to happen, (and where we may change etc.) But if we may add, I'd just write an overload precedure for doit without parameters, and then it should compile.

Ie.

procedure TForm1.DoIt;
begin
ShowMessage('Nike!');
end;


But if I am not allowed to add even 'overload to his' DoIt(I:Integer) procedure... I dunno.

Canderel
22-04-2004, 08:19 AM
Ok, wait, it is not at ALL that simple... :)

Canderel
22-04-2004, 09:03 AM
This make it compile. Dunno if it is what you wanted.


TOnChange = procedure(var I:integer) of object;

But I have no idea if this is what you meant and if it is what you want. (this is getting a little too complex for me :scratch: )