| 
| Autor | Beitrag |  
| Knulli 
          Beiträge: 116
 Erhaltene Danke: 2
 
 Win2k, Win7, Win10
 D5, D2005, D2006, D2007, D10.4.2
 
 | 
Verfasst: Mi 20.03.19 17:30 
 
Hi Leute,
 ich möchte gerne die Format-Funktion mit einem dynamischen Array als Argumentenliste aufrufen.
 	--> Format(stFmt, Args)
 Den FormatString und das Array für die Argumente möchte ich mir in Abhängigkeit diverser Bedingungen selber zusammenbasteln.
 Leider zeschießt sich das Array beim dynamischen längermachen von selbst.
 Ab dem vierten Eintrag wird der LastIDX-2 mit überschrieben.
 Was mache ich falsch?
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 
 | procedure TForm1.Button1Click(Sender: TObject);
 type
 TMyVarRecArray = Array of TVarRec;
 var
 stFMT: String;
 stResult: String;
 Args: TMyVarRecArray;
 Loop: Integer;
 procedure AddToVarRecArray(var aVarRecArray: TMyVarRecArray; aValues: Array of const);
 var
 VarRec: TVarRec;
 begin
 for VarRec in aValues do
 begin
 SetLength(aVarRecArray, Length(aVarRecArray) + 1);
 Args[High(aVarRecArray)] := VarRec;
 end;
 end;
 begin
 
 stFmt := 'Das wird eine Zeile: '; SetLength(Args, 0);
 for Loop := 1 to 5 do
 begin
 stFmt := stFmt + ' %s ';
 AddToVarRecArray(Args, ['Wert ' + IntToStr(Loop)]);
 end;
 stResult := Format(stFmt, Args);
 MessageBox(0, PChar(stResult), 'NaNu', MB_OK);
 end;
 
 |  Knulli_________________ Echte Männer schreiben Windows-Programme in Assembler unter edlin.
 |  |  |  
| GuaAck 
          Beiträge: 378
 Erhaltene Danke: 32
 
 Windows 8.1
 Delphi 10.4 Comm. Edition
 
 | 
Verfasst: Mi 20.03.19 18:18 
 
Hallo, 
 diese Zeile verstehe ich nicht und mein Compiler will si auch nicht übersetzen:
 		                       Delphi-Quelltext 
 									| 1:
 |    for VarRec in aValues do					 |  Gruß
 GuaAck |  |  |  
| jasocul 
          Beiträge: 6395
 Erhaltene Danke: 149
 
 Windows 7 + Windows 10
 Sydney Prof + CE
 
 | 
Verfasst: Do 21.03.19 07:25 
 
In Delphi 7 gibt es diese Möglichkeit noch nicht.
Daher meckert dein Compiler
 
 Zum eigentlichen Problem:
 VarRec ist ein Zeiger auf einen temporären Speicher, der in der Schleife immer wieder genutzt wird.
 Durch die Vergrößerung deines Records reservierst du zwar neuen Speicher, aber weist dann doch einen anderen (den oben genannten temporären) Speicherbereich zu.
 Dadurch, dass dieser Speicher immer wieder benutzt wird, bekommst du deine falschen Werte.
 
 Das kann soweit führen, dass du im späteren Programmverlauf immer wieder andere Informationen in deinem Array stehen hast, weil der Speicher durch andere Daten überschrieben werden kann. Abgesehen davon dürftest du dadurch auch ein Memoryleak bekommen.
 
 Du musst also bei den Zuweisung in dein Array die Inhalte und nicht die Zeiger zuweisen.
 In TVarRec stehen unter VType auch Typ-Informationen. Bei AnsiStrings (und nicht nur da) gibt es noch das zusätzliche Problem, dass die auch nur als Zeiger im Record stehen. Auch dieser Speicherbereich ist nur temporär und wird innerhalb von Delphi sicher wieder mit anderen Informationen während des Programm gefüllt werden können.
 Für diesen Beitrag haben gedankt: Knulli
 |  |  |  
| Knulli  
          Beiträge: 116
 Erhaltene Danke: 2
 
 Win2k, Win7, Win10
 D5, D2005, D2006, D2007, D10.4.2
 
 | 
Verfasst: Do 21.03.19 14:12 
 
OK, habs (hoffentlich) begiffen:
 In TVarRec werden nur Referenzen gespeichert. Und weil bei meinem Aufruf von AddToVarRecArray das Argument nur auf dem Stack existiert (also innerhalb von AddToVarRecArray), gabs Datensalat bei den nachfolgenden Aufrufen.
 Ich muss also bis zum Ende der "Nutzzeit" von Args ( also bis nach nach Format(...) ) den Speicherplatz für die Argumente vorhalten. Richtig verstanden?
 												| 1:2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
 10:
 11:
 12:
 13:
 14:
 15:
 16:
 17:
 18:
 19:
 20:
 21:
 22:
 23:
 24:
 25:
 26:
 27:
 28:
 29:
 30:
 31:
 32:
 33:
 34:
 35:
 36:
 37:
 
 | procedure TForm1.Button1Click(Sender: TObject);
 type
 TMyVarRecArray = Array of TVarRec;
 var
 stFMT: String;
 stResult: String;
 Args: TMyVarRecArray;
 Strings: Array of String;                               Loop: Integer;
 procedure AddToVarRecArray(var aVarRecArray: TMyVarRecArray; aValues: Array of const);
 var
 VarRec: TVarRec;
 begin
 for VarRec in aValues do
 begin
 SetLength(aVarRecArray, Length(aVarRecArray) + 1);
 Args[High(aVarRecArray)] := VarRec;
 end;
 end;
 begin
 
 stFmt := 'Das wird eine Zeile: '; SetLength(Args, 0);
 for Loop := 1 to 5 do
 begin
 stFmt := stFmt + ' %s ';
 SetLength(Strings, Length(Strings) + 1);                Strings[High(Strings)] := 'Wert ' + IntToStr(Loop);     AddToVarRecArray(Args, [Strings[High(Strings)]]);     end;
 stResult := Format(stFmt, Args);
 SetLength(Strings, 0);                                  MessageBox(0, PChar(stResult), 'Hubba Hubba!!', MB_OK);
 end;
 
 |  Also kann ich das TVarRecArray nicht WIRKLICH effektiv nutzen.    Frisst Format noch andere Arrays / Listen, die sich auch die WERTE statt nur Referenzen merken können?
 Knulli_________________ Echte Männer schreiben Windows-Programme in Assembler unter edlin.
 |  |  |  
| jasocul 
          Beiträge: 6395
 Erhaltene Danke: 149
 
 Windows 7 + Windows 10
 Sydney Prof + CE
 
 | 
Verfasst: Fr 22.03.19 07:57 
 
	  |  Knulli hat folgendes geschrieben  : |  	  | Also kann ich das TVarRecArray nicht WIRKLICH effektiv nutzen.
   
 | 
 Es ist zumindest nicht trivial.
 Ich habe nochmal etwas recherchiert, weil ich zu wenig Zeit habe, eine Lösung für dich zu erarbeiten, die brauchbar ist. Dabei habe ich folgendes gefunden:
https://stackoverflow.com/questions/6058697/how-to-set-string-or-ansistring-constant-in-the-tvarrec Insbesondere die letzte Antwort beschreibt einen Lösungsansatz, der dein Problem lösen kann. Ist aber dennoch etwas Aufwand.
 	  |  Knulli hat folgendes geschrieben  : |  	  | Frisst Format noch andere Arrays / Listen, die sich auch die WERTE statt nur Referenzen merken können?
 | 
 Format habe ich bisher noch nie genutzt. Da muss vielleicht mal ein anderer User was zu sagen. |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Fr 22.03.19 09:04 
 
In dem vorliegenden Fall ist es relativ simpel, da du ja das Array nur innerhalb deiner Methode benötigst. Es genügt daher, wenn du deine Strings in einer lokalen Variable hast (was ja schon der Fall ist) und du nicht versuchst den String in den Record zu bekommen, sondern (wie in den Links gezeigt) nur die Pointer auf diese vorhandenen Strings.
 So habe ich das auch schon für die Verwendung mit Format gemacht.
 	  |  jasocul hat folgendes geschrieben  : |  	  | Format habe ich bisher noch nie genutzt. | 
 Wir benutzen das um Ausgabestrings nicht per Hand zusammenzuklöppeln, was einfach die Übersichtlichkeit verringern würde und die Übersetzung in andere Sprachen deutlich erschweren oder unmöglich machen würde. |  |  |  
| jasocul 
          Beiträge: 6395
 Erhaltene Danke: 149
 
 Windows 7 + Windows 10
 Sydney Prof + CE
 
 | 
Verfasst: Fr 22.03.19 10:03 
 
Off-Topic:
 	  |  jaenicke hat folgendes geschrieben  : |  	  | Wir benutzen das um Ausgabestrings nicht per Hand zusammenzuklöppeln, was einfach die Übersichtlichkeit verringern würde und die Übersetzung in andere Sprachen deutlich erschweren oder unmöglich machen würde.	  |  jasocul hat folgendes geschrieben  : |  	  | Format habe ich bisher noch nie genutzt. | 
 | 
 Genau dieser Bedarf existiert bei uns nicht/kaum, da wir nur Inhouse-Entwicklung machen. Es gibt zwar Anwendungen, die Protokolle erzeugen, aber die werden nur von der IT genutzt. Großartige Formatierungen sind daher nicht erforderlich.
 On-Topic:
 Die Strings sind eben nicht in einer lokalen Variablen. Es wird als Konstante (in einem Array of const) an die Verarbeitungsroutine übergeben. Somit wird der reservierte Speicher wieder frei gegeben und im späteren Schleifendurchlauf wieder genutzt. Das führt ja genau zu dem beschriebenen Problem. |  |  |  
| jaenicke 
          Beiträge: 19326
 Erhaltene Danke: 1749
 
 W11 x64 (Chrome, Edge)
 Delphi 12 Pro, C# (VS 2022), JS/HTML, Java (NB), PHP, Lazarus
 
 | 
Verfasst: Fr 22.03.19 10:42 
 |  |  |  
| jasocul 
          Beiträge: 6395
 Erhaltene Danke: 149
 
 Windows 7 + Windows 10
 Sydney Prof + CE
 
 | 
Verfasst: Fr 22.03.19 11:38 
 
Ah, ok.
Das hatte ich bei der neuen Source-Variante übersehen.
 |  |  |  |