PChar unverändert

Für Fragen zur Programmiersprache auf welcher Lazarus aufbaut
Antworten
Mathias
Beiträge: 6207
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

PChar unverändert

Beitrag von Mathias »

Code: Alles auswählen

program Project1;

const
  max = 10;
var
  i: integer;
  s: string;

  widget: array[0..max] of record
    pc: PChar;
  end;

begin
  for i := 0 to max do begin
    str(i, s);
    widget[i].pc := PChar('Button' + s);
    WriteLn(widget[i].pc);
    s[4] := 'x';
  end;
  WriteLn();

  for i := 0 to max do begin
    WriteLn(widget[i].pc);
    WriteLn(PtrUInt(widget[i].pc));
  end;

end.
Ausgabe:

Code: Alles auswählen

Button0
Button1
Button2
Button3
Button4
Button5
Button6
Button7
Button8
Button9
Button10

Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Button10
140710960345240
Wieso hat jeder PChar im Array den gleichen Inhalt ?
Und jeder PChar im Array zeigt auf die gleiche Adresse.
Was ich noch dachte, das der PChar auf auf den String zeigt, aber dies kann ich auch nicht nachweisen, das ich ein Zeichen folgendermassen im String verändert habe:

Code: Alles auswählen

s[4] := 'x';    
Ich habe noch versucht die Unit "heaptrc" einzubinden. Und siehe da, ich habe ein Speicherleak

Code: Alles auswählen

11 memory blocks allocated : 346/352
9 memory blocks freed     : 314/320
2 unfreed memory blocks : 32
True heap size : 32768
True free heap : 32256
Should be : 32352
Call trace for block $00007FD2D8EEF200 size 32
Marked memory at $00007FD2D8EEF100 invalid
Wrong signature $A8523398 instead of 079F9929
Muss ich da etwa bei jedem PChar im Array den Speicher selbst mit GetMem reservieren ?
Oder gibt es dafür etwas fertiges ?
Ich vermute der C-Programmierer löst dies mit "strdub".
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
theo
Beiträge: 10498
Registriert: Mo 11. Sep 2006, 19:01

Re: PChar unverändert

Beitrag von theo »

Code: Alles auswählen

    widget[i].pc := StrNew(PChar('Button' + s));
.....
    StrDispose(widget[i].pc);    

wp_xyz
Beiträge: 4892
Registriert: Fr 8. Apr 2011, 09:01

Re: PChar unverändert

Beitrag von wp_xyz »

@KodeZwerg: Was ist denn mit deinem Datum los?
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

Benutzeravatar
KodeZwerg
Beiträge: 96
Registriert: Mo 6. Feb 2023, 11:04

Re: PChar unverändert

Beitrag von KodeZwerg »

wp_xyz hat geschrieben:
Fr 17. Feb 2023, 23:10
@KodeZwerg: Was ist denn mit deinem Datum los?
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.
Das ist meine Signatur :mrgreen:
(Sorry für meine vorige Post, ich fand keinen "Löschen" Knopf)
Zuletzt geändert von KodeZwerg am Sa 39. Okt 6043, 29:87, insgesamt 43-mal geändert.

Benutzeravatar
Jorg3000
Lazarusforum e. V.
Beiträge: 170
Registriert: So 10. Okt 2021, 10:24
OS, Lazarus, FPC: Win64
Wohnort: NRW

Re: PChar unverändert

Beitrag von Jorg3000 »

Moin!
Wenn jedes Widget einen Namen kriegt, ist das doch genau das, wofür der Typ String gut ist.
Das Tolle an einem String ist ja, das der Speicher automatisch reserviert und automatisch wieder freigegeben wird, ohne dass man sich selbst darum kümmern muss.
Wenn man im Programmablauf wirklich einen Pointer benötigt, kann man einfach mittels PChar(widget[x].Str) den Pointer bekommen.
Der Pointer ist solange gültig, wie der zugehörige String unverändert ist.
Grüße, Jörg

Mathias
Beiträge: 6207
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: PChar unverändert

Beitrag von Mathias »

theo hat geschrieben:
Fr 17. Feb 2023, 17:46

Code: Alles auswählen

    widget[i].pc := StrNew(PChar('Button' + s));
.....
    StrDispose(widget[i].pc);    
Danke, dies habe ich gesucht. Was noch wichtig ist, "sysutils" einbinden.
In der "syspchh.inc" hat es sonst noch Befehle, wen man etwas C-mässiges braucht.
Wenn jedes Widget einen Namen kriegt, ist das doch genau das, wofür der Typ String gut ist.
Stimmt, man könnte auch einen Zeiger auf einen String übergeben.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Mathias
Beiträge: 6207
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: PChar unverändert

Beitrag von Mathias »

Mit dem "String" ist es echt übersichtlich, ich habe es jetzt auf GTK2 übertragen.

Code: Alles auswählen

  procedure press(widget: PGtkWidget; Caption: PString); cdecl;
  begin
    WriteLn('Cklicked: ', Caption^);
  end; 
  ...
    var
    widget: array[0..max] of record
      allign, button: PGtkWidget;
      pc: String;
    end;
...
g_signal_connect(G_OBJECT(widget[i].button), 'clicked', G_CALLBACK(@press), @widget[i].pc);    
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Benutzeravatar
af0815
Lazarusforum e. V.
Beiträge: 6214
Registriert: So 7. Jan 2007, 10:20
OS, Lazarus, FPC: FPC fixes Lazarus fixes per fpcupdeluxe (win,linux,raspi)
CPU-Target: 32Bit (64Bit)
Wohnort: Burgenland
Kontaktdaten:

Re: PChar unverändert

Beitrag von af0815 »

Geht das auf GTK3 auch so ?
Blöd kann man ruhig sein, nur zu Helfen muss man sich wissen (oder nachsehen in LazInfos/LazSnippets).

Mathias
Beiträge: 6207
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: PChar unverändert

Beitrag von Mathias »

Geht das auf GTK3 auch so ?
Ich denke Pointer ist Pointer.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Warf
Beiträge: 1912
Registriert: Di 23. Sep 2014, 17:46
OS, Lazarus, FPC: Win10 | Linux
CPU-Target: x86_64

Re: PChar unverändert

Beitrag von Warf »

Mathias hat geschrieben:
Fr 17. Feb 2023, 17:27
Wieso hat jeder PChar im Array den gleichen Inhalt ?
Und jeder PChar im Array zeigt auf die gleiche Adresse.
Was ich noch dachte, das der PChar auf auf den String zeigt, aber dies kann ich auch nicht nachweisen, das ich ein Zeichen folgendermassen im String verändert habe:

Code: Alles auswählen

s[4] := 'x';    
Ganz einfach, Strings haben automatischens Memory Management durch Referenzzählung, PChar als simpler pointer nicht.
Was also passiert mit "PChar('Button' + s)" ist du erzeugst einen neuen Temporären String 'Button' + s, nimmst von dessen ersten char dann einen Pointer, danach wird der String aber nicht mehr (als string) verwendet (PChar ist ein nicht gemanageter typ, daher kann die Referenzzählung hier nicht angewendet werden), Referenzcounting fällt auf 0 und der Pointer ist damit invalid.

Jetzt ist der Memory Manager aber by default so "effizient" das er Speicher der Freigegeben wurde wieder belegen kann. Wenn also der Nächste Temporäre String im loop erzeugt wird liegt der "zufällig" auf der Selben addresse wie der alte, denn die ist ja grade frei geworden.
Als ergebnis hast du jedes mal einen Pointer auf die selbe region bekommst, die zwar ganz kurz tatsächlich den echten string enthält, aber direkt wieder gefreed wird.

Wie du selbst schon festgestellt hast, ist hier die Lösung der Speicher selbst zu verwenden, via GetMem. Alternativ kannst du natürlich auch einfach einen Array an Strings erzeugen und dann auf den Referenzieren

Mathias
Beiträge: 6207
Registriert: Do 2. Jan 2014, 17:21
OS, Lazarus, FPC: Linux (die neusten Trunk)
CPU-Target: 64Bit
Wohnort: Schweiz

Re: PChar unverändert

Beitrag von Mathias »

Alternativ kannst du natürlich auch einfach einen Array an Strings erzeugen und dann auf den Referenzieren
Ja, das ist das beste. PChar möglichst vermeiden, ausser es geht nicht anders.
Mit Lazarus sehe ich grün
Mit Java und C/C++ sehe ich rot

Antworten