Frage zu strtok()
-
Hallo zusammen,
ich bräuchte einen Rat von euch. Die folgende Funktion und deren Anwendung ist mir nicht ganz klar.
Hier das ganze Programm:/* strtok.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> int main(void) { char string[] = "Ein Teststring mit mehreren Worten\n" "und mehreren Zeilen.\t Ende\n"; int i=1; char *ptr; ptr = strtok(string, "\n\t "); while(ptr != NULL) { printf("% d. Wort: %s\n",i++,ptr); ptr = strtok(NULL, "\n\t "); } return EXIT_SUCCESS; }
Folgende Fragen habe ich:
1. Was hat es mit "NULL" auf sich?
Ich habe ein ähnliches Programm schon einmal irgendwo anders gesehen und da wurde auch "NULL" verwendet. Muss man genau dieses Wort verwenden? Mir ist die Schleife dabei nicht ganz klar.
Denn es steht ja in den Klammern ptr != NULL. In den geschweiften Klammern wird der Funktion jedoch NULL zugewiesen. Müsste die Schleife dann nicht abgebrochen werden?
Denn zu diesem Zeitpunkt ist ja ptr nicht != sondern == NULL.2. Wie kann ich nach dem Durchlauf der Funktion mit dem Zeiger geziehlt auf die einzelnen tokens zugreifen?
3. in der printf Funktion steht am Schluss ptr ohne das Sternchen. Wie ich gelernt habe muss der Zeiger, wenn man das anzeigen möchte worauf er zeigt, jedoch mit einem Sternchen stehen.
Ich würde mich über eure Hilfe sehr freuen.
Viele Grüße
-
BIOSzillator schrieb:
Ich habe ein ähnliches Programm schon einmal irgendwo anders gesehen und da wurde auch "NULL" verwendet. Muss man genau dieses Wort verwenden?
Das ist kein Wort, das ist ein NULL-Zeiger.
BIOSzillator schrieb:
1. Was hat es mit "NULL" auf sich?
On a first call, the function expects a C string as argument for str, whose first character is used as the starting location to scan for tokens. In subsequent calls, the function expects a null pointer and uses the position right after the end of last token as the new starting location for scanning.
BIOSzillator schrieb:
2. Wie kann ich nach dem Durchlauf der Funktion mit dem Zeiger geziehlt auf die einzelnen tokens zugreifen?
Das kann man vorteilhafterweise innerhalb der Schleife nach jedem Strtok-Aufruf machen, dessen Rückgabewert ungleich NULL ist.
BIOSzillator schrieb:
3. in der printf Funktion steht am Schluss ptr ohne das Sternchen. Wie ich gelernt habe muss der Zeiger, wenn man das anzeigen möchte worauf er zeigt, jedoch mit einem Sternchen stehen.
Dem Zeiger wird ein Zeiger auf ein Token oder NULL zugewiesen.
Das Sternchen benutzt man bei der Deklaration oder bei einer Dereferenzierung.
Hier findet aber eine Zuweisung einer Startadresse eines Tokens statt oder es wird NULL zugewiesen, wenn kein Token existiert, das ist korrekte C-Syntax.
-
BIOSzillator schrieb:
Folgende Fragen habe ich:
1. Was hat es mit "NULL" auf sich?
Ich habe ein ähnliches Programm schon einmal irgendwo anders gesehen und da wurde auch "NULL" verwendet. Muss man genau dieses Wort verwenden?Ja. Dieses NULL Ist per Vereinbarung die Kennzeichnung für einen ungültigen Zeiger.
Er hat auch den Wert 0. Durch das Wort ist aber klar, das es um Zeiger geht.BIOSzillator schrieb:
Mir ist die Schleife dabei nicht ganz klar.
Denn es steht ja in den Klammern ptr != NULL. In den geschweiften Klammern wird der Funktion jedoch NULL zugewiesen. Müsste die Schleife dann nicht abgebrochen werden?
Denn zu diesem Zeitpunkt ist ja ptr nicht != sondern == NULL.Der Funktion wird NULL übergeben. strtok kann aber auch andere Werte zurückgeben, die dann ptr zugewiesen werden.
BIOSzillator schrieb:
2. Wie kann ich nach dem Durchlauf der Funktion mit dem Zeiger geziehlt auf die einzelnen tokens zugreifen?
Über den Rückgabewert.
Wenn du die Wörter noch am Ende der Schleife haben willst, musst du die Zeiger zwischenspeichern.BIOSzillator schrieb:
3. in der printf Funktion steht am Schluss ptr ohne das Sternchen. Wie ich gelernt habe muss der Zeiger, wenn man das anzeigen möchte worauf er zeigt, jedoch mit einem Sternchen stehen.
Dann bekommst du aber nur den Inhalt der Stelle, auf die der Zeiger verweist. Bei char wäre das ein Zeichen. Du willst aber ganze Wörter ausgeben.
Darum übergibst du an printf mit dem Zeiger den Anfang deines Wortes und printf macht die Dereferenzierung.strtok ist ein etwas schwieriger Kandidat für Einsteiger.
1. Hat es eine lokalen static Pointer, in dem die aktuelle Position von dem String abgelegt wird. Übergibst du einen Wert != NULL, wird dieser interne Wert überschrieben.Das bedeutet aber auch, das du zu einer Zeit nur einmal strtok verwenden kannst.
Rufst du in deiner Schleife eine andere (eigene) Funktion auf, die auch strtok verwendet, hast du Chaos.2. Verändert strok den übergebenen String. Es schreibt an die Stellen von den Trennzeichen die '\0'.
-
BIOSzillator schrieb:
1. Was hat es mit "NULL" auf sich?
NULL ist ein Makro für die Zahl 0. NULL wird gerne für Zeiger eingesetzt, die die Adresse 0 angeben und somit als ungültig angesehen werden.
Der Rest erklärt sich aus dem Lesen der strtok Referenz.BIOSzillator schrieb:
2. Wie kann ich nach dem Durchlauf der Funktion mit dem Zeiger geziehlt auf die einzelnen tokens zugreifen?
Nach dem Durchlauf gar nicht, sondern während. In jedem Durchgang der Schleife ist ptr ein Token, also zwischen Zeile 13 & 15.
BIOSzillator schrieb:
3. in der printf Funktion steht am Schluss ptr ohne das Sternchen.
Laut der Format-Angabe wird erst eine Zahl und dann ein String zum Einfügen erwartet. Ein String ist eine Adresse auf ein char Array, welches mit dem Element '\0' sein Ende angibt. Somit ist die Angabe ptr richtig, denn die Deferenzierung mit ***** würde nur dazu führen, dass der erste char an der Adresse ausgegeben wird.
-
Das ging ja schnell!
Vielen Dank euch drei für die Hilfe. Das würde auch erklären, warum NULL in Großbuchstaben geschrieben ist.
Ist ja bei "#define" auch so, richtig?Also char arrays sind echt eine nummer für sich. Alles andere, wie int arrays, ging ja noch recht einfach.
@Dirk,
Wie würdest du einen zeiger zwischenspeichern?
Man könnte natürlich einen zweiten Zeiger deklarieren, in dem man dann die Adresse zwischenspeichert. Doch bei einer Schleife würde dieser eine Zeiger ja ständig überschrieben.
-
BIOSzillator schrieb:
Wie würdest du einen zeiger zwischenspeichern?
Man könnte natürlich einen zweiten Zeiger deklarieren, in dem man dann die Adresse zwischenspeichert. Doch bei einer Schleife würde dieser eine Zeiger ja ständig überschrieben.Dann brauchst du halt mehrere Zeiger. Und da man viele Variablen des gleichen Typs in einem Array zusammenfassen kann, macht man z.B. ein
char *woerter[100];
Da kannst du dann 100 Zeiger ablegen.Allerdings verweisen diese Zeiger immer noch auf Positionen innerhalb von
string
. Wenn sich der Inhalt vonstring
ändert (einlesen aus Datei), sind die Wörter dahin.Also neuen Speicher mit malloc besorgen, diesen Zeiger im Array ablegen und das Wort dahin kopieren.
BIOSzillator schrieb:
Also char arrays sind echt eine nummer für sich. Alles andere, wie int arrays, ging ja noch recht einfach.
Da ist doch gar kein Unterschied. Ein char ist auch nur eine Ganzzahltyp mit kleinem Wertebereich.
In C hat man nur das char-Array noch für die Strings verwendet. Und da gibt es die Vereinbarung, dass diese Strings als Endekennung das '\0'-Zeichen haben.
Und der Compiler unterstützt das, indem er Stringliterale (Text zwischen ") entsprechend anlegt.
Und der Standard unterstützt dies, durch die Funktionen aus string.h (auch stdio.h und ...)Du kannst dir auch ein inttok schreiben, das ein int-Array so aufteilt.
-
Hallo Dirk,
danke für die Info.
Das man sowas wie ein Zeiger Array machen kann, wusste ich noch gar nicht.
Aber eigentlich auch logisch, wenn man mal drüber nachdenkt.Jetzt nach ein paar Versuchen, klappt es aber schon ganz gut.
So einfache Sachen, wie z.B. eine Aussage in eine Frage umzuformen klappt schon.
Diese ganze Zeigergeschichte ist manchmal noch etwas Komplex. Aber so nach und nach steige ich immer etwas mehr dahinter.