Avatar billede rrm Nybegynder
26. marts 2004 - 18:15 Der er 9 kommentarer og
2 løsninger

Pointer problem

Davs...

Jeg har et lille problem med pointers i delphi.
Jeg forsøger med nedstående kode at overfører et dynamsik array fra LoadConfig til FormCreate via Pointers, men kan ikke få det til at virke. Hvad skal jeg gøre for at få indeholdet af heads overført til headGroups???

På forhånd tak
  rrm


Kode:

headGroup er en record og headsGroups er et array af headGroup.

function LoadConfig(errHandle: hWnd): Pointer;
var
  heads: array of headGroup;
  ...
begin
...
  Result := @heads;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
var
  tmp: Pointer;
begin
...
  tmp := LoadConfig(frmMain.Handle);
  if(tmp <> nil) then
      headGroups := tmp
  else
  begin
      MessageBox(frmMain.Handle, 'Opstarts fejl', 'Fejl',MB_OKERROR);
      halt;
  end;
...
end;
Avatar billede doc404 Novice
26. marts 2004 - 20:03 #1
Dit (et af dem) problem ligger i at din variable heads bliver deallokeret når du forlader din LoadConfig function - dvs. at din pointer peger på noget garbage..

Delphi holder ellers styr på en reference count på dynamic arrays - men det GÆLDER IKKE når du f.eks. sætter en pointer til at pege på et sådant.

Hvis du skal gøre det på denne måde kan du gøre følgende:

type
  THeadGroupArray = array of HeadGroup;

function LoadConfig(bla bla) : THreadGroupArray;
var
  heads : THeadGroupArray;
begin
  ..
  Result := heads;
end;

procedure TfrmMain....
var
  tmp : THeadGroupArray;
begin
  tmp := LoadConfig(...);
  ...
  ...
end;
Avatar billede doc404 Novice
26. marts 2004 - 20:06 #2
I øvrigt er det en meget dårlig ide at benytte untyped pointers fordi compileren ikke har en negermands chance for at vide hvad du peger på - og derfor ikke kan hjælpe dig særlig meget at fange fejl..

pointer typen skal kun benyttes, hvis du virkelig ikke har andre muligheder - og jeg vil næsten sig, at det så skyldes dårligt design.
Avatar billede zerohero Nybegynder
26. marts 2004 - 20:31 #3
Jeg vil bare lige nævne at jeg oftere og oftere benytter untyped pointers... det er måske lidt af dovenskab, da jeg ikke gider at lade mit kode være fyldt med en mase "ligegylige" defineringer! Men du har RET vær varsomt, og undgå at bruge untyped pointers, hvis du ikke rigtigt er vant til dem!!!!! :))
Avatar billede rrm Nybegynder
26. marts 2004 - 22:53 #4
Ok - det skal jeg huske, lige et lille spørgsmål mere: Ved en pointer kan man checke om den er sat ved at se om den er nil, er der også en måde at teste om en bruger definere variable (dette tilfælde en record) er sat???
Avatar billede doc404 Novice
26. marts 2004 - 22:58 #5
En bruger definieret variabel er altid "sat" med mindre det er pointere, objecter eller dynamiske arrays
Avatar billede rrm Nybegynder
26. marts 2004 - 23:02 #6
Grunden til jeg spørger om det, er at jeg sætter resultatet lig nil, hvis der opstår en fejl..
Avatar billede doc404 Novice
26. marts 2004 - 23:49 #7
du kan ikke sætte en record til nil. Kun pointere og objecter (hvilket i bund og grund bare er en pointer) og dynamiske arrays.

kan du give et eksempel?
Avatar billede hrc Mester
27. marts 2004 - 09:10 #8
Med fremkomsten af objekter svandt behovet for at bruge records, til et absolut minimum. Også her ville jeg lave den sædvanlige konstallation af en TheadGroup klasse og en TObjectList som jeg har nedarvet til at indeholde THeadGroups - det er bare een unit og du kan fylde al mulig intelligens ind i objektet, såsom streaming funktionalitet.

Desuden er det dynamisk og frigiver du en TObjectList så sørger den selv for at frigive sine "Items" (i øvrigt uanset hvad du skriver i listens Create). Det er så' nemt og det virker altid.

Du vil i øvrigt finde, at specielt untyped pointers får Delphi 8 spytte warnings ud som var det en C++ compiler! Det er ikke god skik.

Din kode har jeg modificeret til nedenstående hvis jeg ikke kan overtale dig til at køre med lister og klasser i stedet:


type
  TGroup = packed record
    id : integer;
    valid : boolean;
  end;

  THeadGroups = array of TGroup;

procedure CreateGroup(var aHeads : THeadGroups; aItemCount : integer);
begin
  SetLength(aHeads,aItemCount);
end;

procedure TfrmMain.Button1Click(Sender: TObject);
var
  Heads : THeadGroups;
begin
  CreateGroup(Heads,10); // og det er jo analogt til SetLength
  ...
end;

Alternativt kan du vist også gøre det således:

type
  HeaderGroup = packed record
    ...
  end;

  THeads = array of headGroup;
  TPHeads = ^THeads;

function LoadConfig(errHandle: hWnd): TPHeads;
begin
  GetMem(result); // Allokér pointer
  SetLength(result^,10); // Allokér 10 felter
  // fyld i'
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  // pHeadGroups = nil fra starten

  pHeadGroups := LoadConfig(frmMain.Handle);
  if not assigned(pHeads) then begin
    MessageBox(Handle,'Opstartsfejl','Fejl',MB_OKERROR); // 'Opstartsfejl' er eet ord.
    PostQuitMessage(1); // Er bedre at bruge end Halt!
  end;
end;

procedure TfrmMain.FormDestroy(Sender: TObject)
begin
  if assigned(pHeadGroups) then begin
    // måske nødvendig med SetLength(pHeadGroups^,0); ???
    FreeMem(pHeadGroups);
  end;
end;

Bemærk endelig, at jeg ikke har testet det ret meget af det (en rigtig Microsoft disclamer, hva?).
Avatar billede doc404 Novice
27. marts 2004 - 11:16 #9
hrc> endnu en gang er vi enige.. Objecter er vejen frem. De koster forsvindende lidt i forhold til records.

zerohere>for gudsskyld... Se at komme din dovenskab til livs eller skift til C ;-)
Avatar billede zerohero Nybegynder
27. marts 2004 - 16:34 #10
He he... ;))
Avatar billede rrm Nybegynder
01. april 2004 - 20:50 #11
Tak for svarene, mht. objecter vs record, så tror jeg ikke det kan betale sig at skifte, idet hver enkelt record kun skal indeholde ganske få data.
Så derfor vil jeg benytte doc404 "metode".
Avatar billede Ny bruger Nybegynder

Din løsning...

Tilladte BB-code-tags: [b]fed[/b] [i]kursiv[/i] [u]understreget[/u] Web- og emailadresser omdannes automatisk til links. Der sættes "nofollow" på alle links.

Loading billede Opret Preview
Kategori
Kurser inden for grundlæggende programmering

Log ind eller opret profil

Hov!

For at kunne deltage på Computerworld Eksperten skal du være logget ind.

Det er heldigvis nemt at oprette en bruger: Det tager to minutter og du kan vælge at bruge enten e-mail, Facebook eller Google som login.

Du kan også logge ind via nedenstående tjenester