String Token speichern

Guten Tag,

ich möchte gern in einem ANSI-C Programm Token aus einem String einzeln in einer Variable speichern um diese später im Programm wieder verwenden zu können.

Ich treffe dabei scheinbar auf ein grundsätzliches Verständnis-Problem.

Ich habe aus meinem Programm mal ein Beispiel extrahiert einfach klar zu machen worum es mir geht.

Hier der Code:

#include 
#include 
#include 

int main(void) {

 char string[] = "Garage1 Auto1 Auto3";

 char savetoken[10];
 char \*ptr;

 ptr= strtok(string,"\n ");

 while(ptr != NULL) {
 printf("%s\n",ptr);

 savetoken=\*ptr;
 printf("%s\n",savetoken);
 ptr = strtok(NULL, "\n\t ");

 }

 return EXIT\_SUCCESS;

}

Wenn ich diesen Code compilieren möchte bekomme ich folgende Meldung:

Tech$ gcc -o example example.c 
example.c: In function ‘main’:
example.c:17: error: incompatible types in assignment

Das Problem ist ganz klar die Zeile:
savetoken=*ptr;

Aber wie kann ich denn den Inhalt des Zeigers ptr in einen „String“ (Char-Array) schreiben?
Ist das nur ein Syntax-Problem? Ist mein Ansatz falsch?

Vielen Dank im voraus…

Tobias

_[MOD]: code in

-tags gesetzt_ 

Hallo Tobias,

ich möchte gern in einem ANSI-C Programm Token aus einem
String einzeln in einer Variable speichern um diese später im
Programm wieder verwenden zu können.
Ich treffe dabei scheinbar auf ein grundsätzliches
Verständnis-Problem.

char savetoken[10];
char *ptr;

ptr= strtok(string,"\n ");

while(ptr != NULL) {
printf("%s\n",ptr);

savetoken=*ptr;

Dein Ansatz ist fast richtig. Ein char[10] ist
in C/C++ eine Sequenz von 10 Zeichen und nicht
eine Sequenz von 10 Strings.

Dein Beispiel würde funktionieren, wenn man eine
eigene kleine „Speicherverwaltung“ einbaut. Leider
ist C nicht gerade gut dazu geeignet, mit Strings
zu Arbeiten. In C++ sähe das ganz anders aus.

==>

#include 
#include 
#include 
 
 void addtoken\_to(char \*savetoken[], int\* savetoken\_n, char \*ptr) 
{
 char \*q = malloc(strlen(ptr)\*sizeof(char)+1);
 savetoken[\*savetoken\_n] = strcpy(q, ptr);;
 ++(\*savetoken\_n);
}

 int main(void) 
{
 #define MAXTOKENS 24
 int i, savetoken\_n = 0;
 char \*savetoken[MAXTOKENS]; 

 char string[] = "Garage1 Auto1 Auto3";
 char \*ptr = strtok(string, "\n\t ");

 while(ptr != NULL) {
 addtoken\_to(savetoken, &savetoken\_n, ptr);
 ptr = strtok(NULL, "\n\t ");
 }
 
 for(i=0; i


Grüße

CMБ

Hallo Semjon,

vielen Dank für deine Hilfe.

Ich bin aber noch nicht ganz im Klaren bei deinem Programm.

Es gibt 2 Stellen die mich etwas verunsichern.

  1. Laut Dokumentation übergibt strcpy eine Zeichenkette von string1 nach string2. Diese beiden werden als Variablen der Funktion mitgegeben.

Du nutzt aber den Rückgabewert der Funktion. Wie kommt das?
Verstehe ich das richtig? Erkennt die Funktion selbständig wie sie angewendet wird und arbeitet dann anders?

char *q = malloc(strlen(ptr)*sizeof(char)+1);
savetoken[*savetoken_n] = strcpy(q, ptr);;

  1. Bei der folgenden Zeile übergibst du &savetoken_n und nicht einfach savetoken_n. Da arbeitest du mit der Adresse der Variable, oder? Da fehlts bei mir noch. Ich hätte einfach savetoken_n geschrieben. Es soll ja nur der integer-Wert übergeben werden.

addtoken_to(savetoken, &savetoken_n, ptr);

Gruß Tobias

Hallo Tobias,

Ich bin aber noch nicht ganz im Klaren bei deinem Programm.
Es gibt 2 Stellen die mich etwas verunsichern.

  1. Laut Dokumentation übergibt strcpy eine Zeichenkette von
    string1 nach string2. Diese beiden werden als Variablen der
    Funktion mitgegeben.

Umgekehrt:

 Zeiger\_Auf\_Ziel = strcpy(ziel, quelle)

Du nutzt aber den Rückgabewert der Funktion. Wie kommt das?
Verstehe ich das richtig? Erkennt die Funktion selbständig wie
sie angewendet wird und arbeitet dann anders?

Nein, sie liefert „ziel“ auch noch als Rückgabewert,
dies kann, muß man aber nicht nutzen.
http://www.cplusplus.com/reference/clibrary/cstring/…

char *q = malloc(strlen(ptr)*sizeof(char)+1);
savetoken[*savetoken_n] = strcpy(q, ptr);;

  1. Bei der folgenden Zeile übergibst du &savetoken_n und nicht
    einfach savetoken_n. Da arbeitest du mit der Adresse der
    Variable, oder? Da fehlts bei mir noch. Ich hätte einfach
    savetoken_n geschrieben. Es soll ja nur der integer-Wert
    übergeben werden.

Wir wollen ja, daß an der Stelle, an der wir einen
neuen String hinzufügen – auch die „Anzahl“ ent-
sprechend hochgezählt wird. Daher interessiert
uns nicht (nur) der „Wert“ der Variablen, sondern
(auch und vor allem) die Variable selbst. Würden
wir diese nicht als „Adresse“ übergeben, hätten
wir keine Chance, diese Variable *in der Funktion*
zu ändern.

Grüße

CMБ

Hallo Semjon,

Danke für die Hilfe.
Funzt alles wie es soll und gelernt hab ich auch was bei. :smile:

Gruß

Tobias

hallo tobex

Du kannst auch ein Array mit char-Zeigern machen, das hätte den Vorteil, dass die einfache Zuweisung eines Zeigers (also der Speicheradresse) wohl möglich ist, und das Kopieren mit strcpy() entfällt (Kurzfassung):

char \*liste[10];
int i=0;
while(ptr != NULL) {
 liste[i++] = ptr;
}

Das Array hat nun aber eine feste Größe, da bist du mit einer verketteten Liste noch besser dran, da speicherst Du dann char-Zeiger, so viele du nur willst.
Das geht schon auch mit C.

lG
Martin B

Hallo Martin

Du kannst auch ein Array mit char-Zeigern machen, das hätte
den Vorteil, dass die einfache Zuweisung eines Zeigers (also
der Speicheradresse) wohl möglich ist, und das Kopieren mit
strcpy() entfällt (Kurzfassung):

char *liste[10];
int i=0;
while(ptr != NULL) {
liste[i++] = ptr;
}

Die Idee ist erstmal nicht schlecht, hat aber
einen Haken. Die Zeiger, die strtok zurück-
liefert, sind Positionen *in* dem String, den
strtok() verändert hat (strtok schreibt ja Nullen
in den übergebenen String rein!).

Im praktischen Falle würde man daher an strtok eine
String-Kopie übergeben, in die die Funktion auch
schreiben darf (statische Strings sind ggf. Readonly!).

Nun muß man aufpassen, daß man den temporären String
überall dorthin mitnimmt, wo man sich die Zeiger nach
obiger Weise abgespeichert hat. Tut man das nicht
(z.b. Liste der Zeiger wird in einer Funktion
gebaut, in der auch der temporäre String erzeugt
wurde), hängen die Zeiger in der Luft, was man
u.U. nicht mal gleich mitbekommt.

Desaster waiting to happen“.

Das Array hat nun aber eine feste Größe, da bist du mit einer
verketteten Liste noch besser dran, da speicherst Du dann
char-Zeiger, so viele du nur willst.
Das geht schon auch mit C.

Man könnte auch mit strtok einen „Leerlauf“ machen,
dann den Speicher allozieren und dann nochmal mit
strtok() die Elemente herausholen:

 ...
 char \*ptr, \*\*liste;
 int cnt=0, len=strlen(string);

 if(ptr=strtok(string, "\n\t ")) // Token zaehlen (String veraendern)
 while(++cnt && (ptr=strtok(NULL, "\n\t ")));
 for(i=0; i

Wie gesagt, die Zeiger zeigen jetzt auf den String,
der von strtok verändert wurde.

Grüße

CMБ

Hallo Semjon

Die Idee ist erstmal nicht schlecht, hat aber
einen Haken. Die Zeiger, die strtok zurück-
liefert, sind Positionen *in* dem String, den
strtok() verändert hat (strtok schreibt ja Nullen
in den übergebenen String rein!).

Ja, schon gehört davon. Obwohl dazu keinerlei Notwendigkeit besteht (s.u.).

Im praktischen Falle würde man daher an strtok eine
String-Kopie übergeben, in die die Funktion auch
schreiben darf (statische Strings sind ggf. Readonly!).

Ja genau, meine Rede.

…, hängen die Zeiger in der Luft, was man
u.U. nicht mal gleich mitbekommt.
Desaster waiting to happen“.

Natürlich, da kann viel sein. Aber solange die Zeiger „read only“ behandelt werden, sollte das kein Problem sein - auch wenn die strtok() ihre Nullen reingeschrieben hat - ?
Ich meine, können wir doch ohnehin brauchen - ? Bloss löschen darf man die dann nicht.

Man könnte auch mit strtok einen „Leerlauf“ machen,
dann den Speicher allozieren und dann nochmal mit
strtok() die Elemente herausholen:

Bevor ich mir Mühe mache, um die Besonderheiten von diversen C-Funktionen auszubügeln, schreibe ich mir gleich eine eigene, und die kriegt einen const-String:

#include 
#include 
#include 
#include 
typedef const char \* CC;

// pass the same char\* several times (first time reset), 
// and get the next word each time, fit for cpp "\_a123456\_\_":

char\* strTok(CC str, CC delims=" \r\n\t,;.:=")
 {
 static CC current = 0;
 static int offset = 0;

 // a new char\* ? then reset:
 if (current != str) {current = str; offset = 0;}

 // advance to the first char of the following word:
 while ( !isalpha(current[offset]) &&
 current[offset] != '\_' &&
 current[offset]
 )
 {offset++;}
 if (! \*current[offset]) {return 0;}
 // "offset" points to begin of word now

 int stop = offset;
 bool done=false;

 // drag "stop", will be the terminator:
 for (; !done; stop++)
 {
 for (int j=0; j

lG
Martin B