doppelt Null terminierter String

Gast #3208613
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
Gast #3208637
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.
#3208648
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.
Gast #3208654
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
Persönliche Seite #3208666
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 
...).
#3208667
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.
#3208687
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.
Gast #3208705
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
#3208716
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.
#3208717
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.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren