Delphi-PRAXiS

Delphi-PRAXiS (https://www.delphipraxis.net/forum.php)
-   Object-Pascal / Delphi-Language (https://www.delphipraxis.net/32-object-pascal-delphi-language/)
-   -   Zugriff auf String^ (String pointer) (https://www.delphipraxis.net/191756-zugriff-auf-string%5E-string-pointer.html)

Pixel 16. Feb 2017 12:20

Delphi-Version: 5

Zugriff auf String^ (String pointer)
 
Hallo,

nehmen wir folgenden Code an:

Delphi-Quellcode:
var
  NormalerString : String;
  PointerString : ^String;
.
.
NormalerString := 'Hallo Welt!';
PointerString := Pointer(Integer(@NormalerString) + 5);
ShowMessage(String(PointerString^));
Da gibt's eine Fehlermeldung, ich schätze das mit den Pointern habe ich nicht so ganz verstanden in FP.
Kann mir das bitte einer erklären? Danke!

Neutral General 16. Feb 2017 12:25

AW: Zugriff auf String^ (String pointer)
 
Delphi-Quellcode:
NormalerString := 'Hallo Welt!';
PointerString := @NormalerString;
ShowMessage(PointerString^);
Einfach so.

mkinzler 16. Feb 2017 12:26

AW: Zugriff auf String^ (String pointer)
 
Was hast Du vor?

Pixel 16. Feb 2017 12:32

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von Neutral General (Beitrag 1361812)
Delphi-Quellcode:
NormalerString := 'Hallo Welt!';
PointerString := @NormalerString;
ShowMessage(PointerString^);
Einfach so.

Ich möchte aber nicht den gesamten String in PointerString,

Zitat:

Zitat von mkinzler (Beitrag 1361814)
Was hast Du vor?

sondern eben ab NormalerString + 5! Ich möchte dass PointerString auf den NormalerString zeigt, und zwar auf die Stelle 5 (das klappt ja auch soweit, hab die Adressen geprüft). Nur der Zugriff, der klappt nicht.

Neutral General 16. Feb 2017 12:37

AW: Zugriff auf String^ (String pointer)
 
Delphi-Quellcode:
var
  NormalerString : String;
  PointerString : PChar;
.
.
NormalerString := 'Hallo Welt!';
PointerString := @NormalerString[5];
ShowMessage(PointerString);
Sollte so gehen.

Pixel 16. Feb 2017 12:39

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von Neutral General (Beitrag 1361819)
Delphi-Quellcode:
var
  NormalerString : String;
  PointerString : PChar;
.
.
NormalerString := 'Hallo Welt!';
PointerString := @NormalerString[5];
ShowMessage(PointerString);
Sollte so gehen.

Ja geht, danke.

Warum geht mein code nicht?

Ich caste die Adresse von NormalerString doch als Integer, addiere 5 drauf, Caste das wieder als Pointer und weise es einem Pointe rzu, warum ist das falsch?

Neutral General 16. Feb 2017 12:41

AW: Zugriff auf String^ (String pointer)
 
Weil ein String an Stelle [0] die Länge gespeichert hat und ich glaube davor sogar noch ein paar Informationen.
Wenn du einen String-Pointer einfach um 5 nach hinten verschiebst gibt es diese Informationen davor nicht, weil davor ja die anderen Buchstaben stehen.
Außerdem ist ein String schon ein Pointer. Wenn du @StringVariable schreibst ist das ein Pointer auf den String-Pointer. Und wenn du den verschiebst landest du irgendwo im Nirvana.

Pixel 16. Feb 2017 12:42

AW: Zugriff auf String^ (String pointer)
 
// EDit: nvm

Neutral General 16. Feb 2017 12:43

AW: Zugriff auf String^ (String pointer)
 
Lies den 2. Teil meiner Antwort.
=>
Delphi-Quellcode:
var
  NormalerString : String;
  PointerString : PChar;
begin
  NormalerString := 'Hallo Welt!';
  PointerString := PChar(Integer(NormalerString) + 5);
  ShowMessage(PointerString);
Das ist aber deutlich gefährlicher in Hinblick auf Unicode strings ab Delphi 2009.

p80286 16. Feb 2017 12:59

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von Neutral General (Beitrag 1361822)
Außerdem ist ein String schon ein Pointer.

Nicht notwendiger Weise, aber mit
Delphi-Quellcode:
pteilstr:=@Mystring[5];
sollte man immer auf der sicheren Seite sein.

Bei Arrays ist's übrigens genauso.

Gruß
K-H

Pixel 16. Feb 2017 13:01

AW: Zugriff auf String^ (String pointer)
 
Ja ich denke ich hab es jetzt verstanden.

Delphi-Quellcode:
@String = Adresse die Auf String zeigt
String[0] = Länge
String[1] = Erster Char
@String[1] = Adresse von erstem Char

=>

Entweder PChar(@NormalerString[1] + 4); (gefährlich)

oder (einfacher, besser)

@NormalerString[5];

Neutral General 16. Feb 2017 13:20

AW: Zugriff auf String^ (String pointer)
 
Zitat:

@String = Adresse die Auf String zeigt
Ja, wenn dus richtig meinst :mrgreen:

String (ohne @) ist schon die Adresse auf den Zeichenkette des Strings.
@String ist die Adresse auf die Adresse auf die Zeichenkette des Strings

Oder anders gesagt: @String (ohne Index auf ein bestimmtes Zeichen) ist zu 99% falsch oder unnötig.
Delphi-Quellcode:
var str: String;
    pstr: PChar;
begin
  // Beides das gleiche
  // Die erste Zeile zeigt aber was intern bei @str[5] quasi passiert.
  // ==> str[5] = PChar(Integer(str) + 4)^ intern
  // ==> str ist schon ein Pointer
  pstr := @(PChar(Integer(str) + 4)^);
  pstr := @str[5];

himitsu 16. Feb 2017 18:08

AW: Zugriff auf String^ (String pointer)
 
Ein String ist mehr als nur Text, gefolgt von einer #0.
Wobei Delphi-Strings die #0 eigentlich nicht brauchen, denn "vor" dem Text (also vor der Stelle des ersten Zeichens, auf die der interne String-Pointer zeigt) liegt noch eine Längenangabe, der Referenzzähler und die CodePage-Informationen.
Und hinter dem letzten Zeichen liegen noch zwei #0-en, als Kompatibilität und um "schnell" in einen PChar casten zu können.

Fazit: Als "String" kann man den Zeiger nicht einfach so verschieben.
Ein Cast von String zu PChar geht immer,
aber andersrum geht's nimmer (hier muß man eine neue String-Variable erzeugen und da rein den PChar-Inhalt kopieren).

Mit einem PChar kann man das problemlos machen (also von einem PChar aus oder Anfangs auch von einem String/AnsiString/UnicodeString oder WideString),
denn dort zeigt der Zeiger wirklich "nur" auf ein Zeichen und dann so lange, bis eine #0 gefunden wird.

p80286 16. Feb 2017 21:51

AW: Zugriff auf String^ (String pointer)
 
Delphi-Quellcode:
mystring[0]
ist nur bei Shortstrings die Länge des Strings. Benutze bitte immer
Delphi-Quellcode:
length(mystring)
falls Du die Länge benötigst.

Gruß
K-H

Neutral General 17. Feb 2017 08:20

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von p80286 (Beitrag 1361891)
Delphi-Quellcode:
mystring[0]
ist nur bei Shortstrings die Länge des Strings. Benutze bitte immer
Delphi-Quellcode:
length(mystring)
falls Du die Länge benötigst.

Stimmt nicht:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var str: String;
begin
  str := 'Hallo Welt!';
  Caption := IntToStr(PInteger(Integer(@str[1])-SizeOf(Integer))^);
end;
Length(mystring) ist natürlich trotzdem zu bevorzugen.

Sherlock 17. Feb 2017 08:28

AW: Zugriff auf String^ (String pointer)
 
Ohne konkreten Anwendungsfall und Not, würde ich mir heutzutage keine Gedanken mehr um Zeiger machen...speziell bei Strings. Moderne Strings sind mehr als nur simple Bytefolgen, da steckt zu viel dahinter, um es von Hand durchzuhecheln.

O'Neill

p80286 17. Feb 2017 10:50

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von Neutral General (Beitrag 1361909)
Zitat:

Zitat von p80286 (Beitrag 1361891)
Delphi-Quellcode:
mystring[0]
ist nur bei Shortstrings die Länge des Strings. Benutze bitte immer
Delphi-Quellcode:
length(mystring)
falls Du die Länge benötigst.

Stimmt nicht:
Delphi-Quellcode:
procedure TForm1.Button1Click(Sender: TObject);
var str: String;
begin
  str := 'Hallo Welt!';
  Caption := IntToStr(PInteger(Integer(@str[1])-SizeOf(Integer))^);
end;
Length(mystring) ist natürlich trotzdem zu bevorzugen.

Delphi-Quellcode:
const
  bstb='aaaaaaaaaa';
var
  i: integer;
  mystring: ansistring;

begin
  mystring:='';
  for i:=1 to 30 do
    mystring:=mystring+bstb;
  self.Button1.Caption:=format('%d -- %d',[length(mystring),mystring[0]]);
end;
ergibt:

[Fehler] Unit1.pas(38): Auf Element 0 kann nicht zugegriffen werden - 'Length' oder 'SetLength' verwenden
es ging ja explizit um MyString[0] mit irgendwelcher Pointerartistik kann man ja beinahe alles erreichen:)

Gruß
K-H

himitsu 17. Feb 2017 15:18

AW: Zugriff auf String^ (String pointer)
 
Zitat:

Zitat von Sherlock (Beitrag 1361910)
Ohne konkreten Anwendungsfall und Not, würde ich mir heutzutage keine Gedanken mehr um Zeiger machen...speziell bei Strings. Moderne Strings sind mehr als nur simple Bytefolgen, da steckt zu viel dahinter, um es von Hand durchzuhecheln.

Die interne Definition versteckt sich als Record in der System.pas.
Im Grunde genommen ist String recht einfach, wenn man sich einen Hauch auskennt.
* der Zeiger bei Strings zeigt auf das erste Zeichen und und nicht auf den Recordanfang.
* leere Strings sind NIL (theoretisch könnte man auch den Record mit der Daten-Länge 0 verwenden, aber eigentlich kommt das nie vor)
** drum kann man Strings/dynamische Arrays auch oft "schnell" mit Assigned oder =nil bzw. ='' prüfen, anstatt ein Length(x)=0 nehmen zu müssen
* Die beiden #0#0 am Ende werden da nicht erwähnt, aber sind immer da (wenn niemand einen Buffer-Overflow verbrockt hat)
** #0 für PChar-Ende und #0#0 für C-StringListen (#0 für WertEnde und #0#0 für ListenEnde, also ein '' als letzter Wert)
* Die Referenzzählung hat einen Wert für String-Konstanten (-1), welcher bei Speicheroperationen beachtet werden sollte.


Alle Zeitangaben in WEZ +1. Es ist jetzt 11:09 Uhr.

Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz