Forum: PC-Programmierung doppelt Null terminierter String


von Christian (Gast)


Lesenswert?

Hallo.

Eine Windows-API Funktion verlangt als Argument ein LPCSTR.
Also ein Zeiger auf const char. Dieser String soll ein doppelt-Null
terminierter  String sein.

Intuitiv würde ich ja folgendes machen:
const char Buf[]={"test\0\0"};
LPCSTR pBuf = Buf;

//einsetzten in die WinAPI:
meineWinApi(pBuf);

//Prototype
void meineWinApi( LPCSTR );

Meiner Meinung nach würde das aber nicht einen doppelt-Null terminierten
String erzeugen, da die erste Null Sequenz "\0" den String terminiert 
und die zweite Null Sequenz ignoriert.
Im Speicher würde also [t| e |s| t| 0] stehen.
Falls meine Annahme richtig ist, wie kann man denn korrekt einen doppelt
Null terminierten String erzeugen, wie sie die WinApi ja erwartet.

Gruß
Christian

von 00 (Gast)


Lesenswert?

Hab von Doppel-Nullen (außer bei James Bond) ja noch nie etwas gehört 
... die Windows-Fuzzies machen immer komische Sachen.

Aber in C bleibt Deine Doppel-Null am Ende schon erhalten. Deine 
Variable Buf zeigt auf einen Speicherbereich, der 6 Zeichen lang ist und 
an dessen Ende 2 Null-Bytes stehen.

Die Variable pBuf zeigt dann auf denselben Speicherberich.

Ich denke also, daß Du schon ganz korrekt einen Doppel-Null-terminierten 
String erzeugt hast.

von Peter II (Gast)


Lesenswert?

Christian schrieb:
> Eine Windows-API Funktion verlangt als Argument ein LPCSTR.
> Also ein Zeiger auf const char. Dieser String soll ein doppelt-Null
> terminierter  String sein.

nenn doch mal bitte die API funktion. Ich kann es noch gar nicht so 
recht glauben.

von Vlad T. (vlad_tepesch)


Lesenswert?

was willst du? von welcher API-Routine redest du?
doppelt null-terminierte Strings werden meist da verlangt, wo man eine 
Liste von strings erwartet.

Christian schrieb:
> const char Buf[]={"test\0\0"};
> LPCSTR pBuf = Buf;

Christian schrieb:
> Meiner Meinung nach würde das aber nicht einen doppelt-Null terminierten
> String erzeugen,
komische Meinung

> da die erste Null Sequenz "\0" den String terminiert
> und die zweite Null Sequenz ignoriert.
warum sollte er das tun? der Compiler macht genau das, was du ihm sagst.
wenn du ihm ein Stringliteral gibst, erzeugt er genau so ein Array + ein 
zusätzliches '\0'. Dein Buff hat also sogar 3 '\0'en.

von 00 (Gast)


Lesenswert?

Wie kommst Du eigentlich auf Doppel-Null???

Da steht nur, daß es ein ganz stink normaler Null-terminierter const 
char * ist ...

http://msdn.microsoft.com/en-us/library/cc230350.aspx

von Christian (Gast)


Lesenswert?

>nenn doch mal bitte die API funktion.

Hier:

SC_HANDLE WINAPI CreateService(
  In       SC_HANDLE hSCManager,
  In       LPCTSTR lpServiceName,
  In_opt   LPCTSTR lpDisplayName,
  In       DWORD dwDesiredAccess,
  In       DWORD dwServiceType,
  In       DWORD dwStartType,
  In       DWORD dwErrorControl,
  In_opt   LPCTSTR lpBinaryPathName,
  In_opt   LPCTSTR lpLoadOrderGroup,
  Out_opt  LPDWORD lpdwTagId,
  In_opt   LPCTSTR lpDependencies,
  In_opt   LPCTSTR lpServiceStartName,
  In_opt   LPCTSTR lpPassword
);

Betrifft das 3.letzte Argument lpDependencies.

MSDN sagt folgendes:
A pointer to a double null-terminated array of null-separated names of 
services or load ordering groups that the system must start before this 
service.

Gruß
Christian

von Vlad T. (vlad_tepesch)


Lesenswert?

Peter II schrieb:
> nenn doch mal bitte die API funktion. Ich kann es noch gar nicht so
> recht glauben.

ich glaube zB bei den File-dialogen bei den Masken.
da gibt man die einzelnen Optionen durch \0 getrennt an und schließt das 
ganze durch einen leeren string, also zwei \0

von 00 (Gast)


Lesenswert?

Na also, da steht es doch: array ...

von Peter II (Gast)


Lesenswert?

Christian schrieb:
> A pointer to a double null-terminated array

genau das meine  Vlad Tepesch

hier geht es nicht im einen String sondern um eine StringListe.

von Vlad T. (vlad_tepesch)


Lesenswert?

Christian schrieb:
> MSDN sagt folgendes:
> A pointer to a double null-terminated array of null-separated names of
> services or load ordering groups that the system must start before this
> service.
Ich nehme an du meinst Parameter pDependencies

genau das ganze muss dann so aussehen:

"Abhängigkeit1\0Abhängigkeit2\0Abhängigkeit3\0\0"

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Christian schrieb:
> A pointer to a double null-terminated array of null-separated names of
> services or load ordering groups that the system must start before this
> service.

Das sind mehrere im Speicher direkt hintereinanderliegende 
nullterminierte Strings, das Ende wird durch zwei aufeinanderfolgende 
Nullen gekennzeichnet.

Also:

Hallo\0Egon\0Berta\0foobar\0\0

Es ist also kein Array von Pointern auf Strings!

So etwas kann man durch Kopieren der Teilstrings in ein ausreichend 
großes, vorher Nullinitialisiertes Array erreichen (denn auf die 
terminierende Doppel-Null dürfen beliebig viele weitere Nullen folgen 
...).

von Vlad T. (vlad_tepesch)


Lesenswert?

ich finde das ganze übrigends recht clever.
anstatt ein array aus char* und länge zu übergeben.
Itererieren ist auch einfach
1
const char* d0ta;
2
3
for(; d0ta[0]; d0ta+=strlen(d0ta)+1 )
4
{
5
  printf ("%s \n",d0ta);
6
}

Edit:
hab das auch schon benutzt. besonders für Stringlisten als Rückgabewerte 
bietet sich das an. Die Funktion bekommt Speicher und eine max Länge und 
kann dann so viele strings zurückgeben wie platz ist.

von Peter II (Gast)


Lesenswert?

Vlad Tepesch schrieb:
> ich finde das ganze übrigends recht clever.
> anstatt ein array aus char* und länge zu übergeben.

geht auch ohne länge, wenn man festlegt das der letze Zeiger NULL sein 
muss. Dann kann man auch eine Liste von Zeigern übergeben.

von Vlad T. (vlad_tepesch)


Lesenswert?

Peter II schrieb:
> geht auch ohne länge, wenn man festlegt das der letze Zeiger NULL sein
> muss. Dann kann man auch eine Liste von Zeigern übergeben.

stimmt natürlich, dennoch muss man auf der anderen Seite die Daten dann 
erst irgendwie zusammen kopieren. So bestimmt man die gesamt Länge und 
kopiert einen Block. Die Parameter bei denen ich dieses Format bisher 
gesehen habe, sind eher statisch und zur Kompilezeit bekannt (wie ebend 
jene Lsite mit Abhängigkeiten oder eben der Filterparameter der 
OPENFILENAME Struktur). Durch dieses Format entfällt das zusätzliche 
Array mit Pointern.

von Christian (Gast)


Lesenswert?

Also ist der Zweck, das man aus einen einzigen Array eine Liste aus 
Strings
ereugt, anstand z.b. sowas:

struct ArrayList
{
 char arr1[];
 char arr2[];
 char arr3[];
}

Man könnte doch aber dann auch die Adresse der struct übergeben, was 
genauso
einfach ist. Oder?

Gruß
Christian

von MaWin (Gast)


Lesenswert?

Am Ende muss nicht \0\0 stehen weil das " auch eine \0 anfügt.

"a\0b\0c\0"

reicht also.

von Vlad T. (vlad_tepesch)


Lesenswert?

Christian schrieb:
> Also ist der Zweck, das man aus einen einzigen Array eine Liste aus
> Strings
> ereugt, anstand z.b. sowas:
>
> struct ArrayList
> {
>  char arr1[];
>  char arr2[];
>  char arr3[];
> }

das geht nicht und ist auch nicht sinnvoll, da die aufgerufene Funktion 
ja nicht weiß, wieviel strings du ihr geben willst.

Alternative wäre ein Array, aus char*, also:
1
const char* strList[4] = {//ein eintrag mehr, wegen null-pointer als Endemarke
2
  "string 1", "string2", "string3"
3
};
wäre genauso einfach, aber bräuchte Speicher für 4 char* mehr und 
erfordert eine zusätzliche Dereferenzierung.

Beide Varianten haben Vorteile und Nachteile.

von Udo S. (urschmitt)


Lesenswert?

Peter II schrieb:
> geht auch ohne länge, wenn man festlegt das der letze Zeiger NULL sein
> muss. Dann kann man auch eine Liste von Zeigern übergeben.

Trotz allem hast du dann noch mindestens 2 Speicherbereiche, das Array 
und der Speicher in dem sie Strings selbst liegen.

So kommt man mit einem Block aus.

Man könnte natürlich erst das Array und dann die Werte hintereinander in 
einen Block schreiben, dann wäre der wahlfreie Zugriff über das Array 
einfacher, das Erzeugen aber komplexer.
Immer die Frage was man will.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.