String Token speichern

Von: , Frage gestellt am Mo, 30. Mär 2009

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 <stdio.h>
#include <stdlib.h>
#include <string.h>
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 <pre>-tags gesetzt

7 Antworten zu dieser Frage

  1. Antwort von nach 2 Stunden 0 hilfreich
    Re: String Token speichern

    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 <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    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<savetoken_n; i++) {
    printf("%d\t%s\n", i+1, savetoken[i]);
    }
    return EXIT_SUCCESS;
    }
    



    Grüße

    CMБ

    • Antwort von nach 3 Stunden 0 hilfreich
      Re^2: String Token speichern

      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);;
      2. 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

      • Antwort von nach 3 Stunden 0 hilfreich
        Re^3: String Token speichern

        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);;
        2. 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Б

        • Antwort von nach einem Tag 0 hilfreich
          Re^4: String Token speichern

          Hallo Semjon,

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


          Gruß

          Tobias

  2. Antwort von nach 2 Tagen 0 hilfreich
    Re: Zeiger-Array oder Liste

    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

    • Antwort von nach 3 Tagen 0 hilfreich
      Re^2: Zeiger-Array oder Liste

      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<len-1; i++)          // Nullzeichen wieder entfernen
      if(string[i] == '\0')string[i] = ' ';
      printf("\"%s\" has %d tokens\n", string, cnt);
      liste = calloc(cnt, sizeof(*liste)); // Speicher fuer Zeiger bereitstellen
      cnt = 0;
      if(ptr = strtok(string, "\n\t ")) // Token uebernehmen (String veraendern)
      while(liste[cnt++]=ptr, ptr=strtok(NULL, "\n\t "));
      for(i=0; i<cnt; i++)              // Ausgeben
      printf("%d\t%s\n", i+1, liste[i]);
      ...
      


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

      Grüße

      CMБ

      • Antwort von nach 4 Tagen 0 hilfreich
        Re^3: Zeiger-Array oder Liste

        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 <stdio.h>
        #include <ctype.h>
        #include <string.h>
        #include <conio.h>
        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<strlen(delims); j++)
        {
        if (current[stop] == delims[j]) {done=true; break;}
        }
        }
        stop--; // has dragged one too much before, :-)
        // copy word and drag "offset" for next call:
        char *te = new char[stop - offset + 2];
        int i;
        for (i=0; offset < stop; i++, offset++)
        {te[i] = current[offset];}
        te[i] = 0;
        return te;
        }
        int main()
        {
        CC text = "Ich kann schon ein bisschen das C "
        "und moechte gern Spiele machen.";
        char* wort = 0;
        while (wort = strTok(text, " \r\n\t,;.:="))
        {
        printf("%s\n", wort);
        delete[] wort; wort = 0;
        getch();
        } 
        return 0;
        }
        


        lG
        Martin B

Keine passende Antwort gefunden? Jetzt eigene Frage stellen!