Steffanie: C-String teilen

Hallo,

eigentlich sollte ich ja bei solch einem schönen Wetter nicht vor dem PC rumsitzen, aber ich muss das noch hinbekommen.
Ich habe einen String (also char-Array), den ich erstmal teilen muss, da dort einiger Schrott drin ist. Danach will ich den String mittels eines Trennzeichen in mehrer Strings (char-Arrays) teilen. Leider klappt das mit den mehrdimensionalen arrays einfach nicht. Hoffentlich kann mir jemand helfen...

Tausend Dank!
Gruß Steffi

hier mein Ansatz:

#include <stdio.h>
  #include <string.h>

int main(void)
  {
     char empfangspuffer[] = "aklsdfjlkasdjflkasjdflkasdj#<start>#6#920FC1CD#Herr#Mustermann";
     char trennzeichen[] = "#";
 char startflag[] = "<start>";
 char empfangsdaten[40];
 char *strpointer;
 char *wort_aktuell;
 char empfangsdaten_einzeln[5][10];
 int i = 0;

strpointer = strstr(empfangspuffer, startflag);
 strcpy(empfangsdaten,strpointer);

wort_aktuell = strtok(empfangsdaten, trennzeichen);
 strcpy(empfangsdaten_einzeln[i],wort_aktuell);
 while( wort_aktuell != NULL )
 {
  wort_aktuell = strtok(NULL, trennzeichen);
  i++;
  strcpy(empfangsdaten_einzeln[i],wort_aktuell);
 }

return 0;
  }

  1. hi!

    Da hast du wohl die Reihenfolge etwas durcheinandergebracht in deiner while-
    Schleife:

    while( wort_aktuell != NULL ) {
      wort_aktuell = strtok(NULL, trennzeichen);
      i++;
      strcpy(empfangsdaten_einzeln[i],wort_aktuell);
    }

    Hier musst du zwischen strtok und strcpy ueberpruefen, ob es ein Ergebnis gab.
    Aber du hast nur eine Ueberpruefung am Anfang der Schleife eingebaut. Richtig
    waere zum Beispiel:

    while( wort_aktuell != NULL ) {
        strcpy(empfangsdaten_einzeln[i],wort_aktuell);
        wort_aktuell = strtok(NULL, trennzeichen);
        i++;
    }

    bye, Frank!

    --
    Never argue with an idiot. He will lower you to his level and then
    beat you with experience.
    1. Hi!

      Da hast du wohl die Reihenfolge etwas durcheinandergebracht in deiner while-
      Schleife:

      OHHHHH MAAAAANNN! Ich sollte echt raus an die Sonne!

      Vielen Dank!
      Gruß Steffi!

      1. Hallo Steffi,

        Da hast du wohl die Reihenfolge etwas durcheinandergebracht in deiner while-Schleife:
        OHHHHH MAAAAANNN! Ich sollte echt raus an die Sonne!

        oder vielleicht besser raus aus der Sonne? ;-)
        Sorry, ich bin normalerweise nicht fies, aber bei der Steilvorlage ...

        *scnr*
         Martin

        --
        Einer aktuellen Erhebung zufolge sind zehn von neun Ehefrauen eifersüchtig auf ihren Mann.
        1. oder vielleicht besser raus aus der Sonne? ;-)
          Sorry, ich bin normalerweise nicht fies, aber bei der Steilvorlage ...

          :-) Könnte man auch meinen. Aber jetzt kann ich wirklich ohne schlechtes Gewissen raus... nen Sonnenstich kann ich mir jetzt auch nicht mehr holen...

          Danke nochmal!
          Gruß Steffi

    2. bye, Frank!

      Hey, dich gibt's ja auch noch ;)

      Viele Grüße!
      _Dirk

      --
      »[..] ich finde, man muss heutzutage rebellisch sein und sich von den Kids abheben. Unsere Generation soll schließlich mal besser werden als die.«
      - kommirnichmitkation
  2. Moin.

    Ich hoffe mal, du kannst garantieren, dass die Länge deiner Daten die hardcodierten Feldbreiten nie überschreiten...

    Verwende besser eine Funktion, die Strings beliebiger Länge 'splitten' kann. Ich habe sowas tatsächlich bei mir rumfliegen, für Bug-Freiheit übernehme ich allerdings keine Garantie ;)

      
    #include <stdlib.h>  
    #include <string.h>  
      
    char ** strsplit(const char * input, char sep, size_t max_tokens)  
    {  
     char ** tokens = NULL;  
     char * str = NULL;  
      
     tokens = malloc(sizeof(char *) * (max_tokens + 1));  
     if(!tokens) goto failed;  
      
     size_t size = strlen(input) + 1;  
      
     str = malloc(size);  
     if(!str) goto failed;  
      
     memcpy(str, input, size);  
     tokens[0] = str;  
     char ** current = &tokens[1];  
      
     for(; *str; ++str)  
     {  
      if(*str != sep) continue;  
      if(!--max_tokens) break;  
      *str = '\0';  
      *current++ = str + 1;  
     }  
     *current++ = NULL;  
      
     tokens = realloc(tokens, (char *)current - (char *)tokens);  
     if(!tokens) goto failed;  
      
     return tokens;  
      
     failed:  
     if(tokens) free(tokens);  
     if(str) free(str);  
     return NULL;  
    }  
    
    

    Die Funktion gibt ein Array von char* auf die einzelnen Teilstrings zurück, im Fehlerfall NULL. Der letzte Array-Eintrag ist stets NULL.

    Christoph

    1. PS: Nach Verwendung Speicher freigeben nicht vergessen...

        
      char ** tokens = strsplit(input, sep, 32);  
      free(*tokens); // erster Array-Eintrag zeigt auf allozierten String  
      free(tokens); // Speicher des Arrays freigeben  
      
      

      CHristoph

  3. Hallo,

    eigentlich sollte ich ja bei solch einem schönen Wetter nicht vor dem PC rumsitzen, aber ich muss das noch hinbekommen.
    Ich habe einen String (also char-Array), den ich erstmal teilen muss, da dort einiger Schrott drin ist. Danach will ich den String mittels eines Trennzeichen in mehrer Strings (char-Arrays) teilen. Leider klappt das mit den mehrdimensionalen arrays einfach nicht. Hoffentlich kann mir jemand helfen...

    Falls es wirklich nur ein einzelnes Trennzeichen ist,
    kannst Du es Dir und der CPU auch leicht machen:

    1. Den gesamten String kopieren (nur, falls Du den
         Empfangspuffer noch anderweitig brauchst, ansonsten
         kann die Manipulation direkt im Empfangspuffer geschehen...)
    2. Alle '#' in der Kopie durch (char)0 ersetzen.
    3. Ein Pointer-Array vom typ char** anlegen, welches
         auf die jeweiligen Teilstring-Fragmente zeigt.

    Viele Grüße

    Andreas

    Bsp:

      
    #include<stdio.h>  
    #include<string.h>  
    #include<stdlib.h>  
      
    int main(void) {  
      char empfangspuffer[] = "aklsdfjlkasdjflkasjdflkasdj#<start>#6#920FC1CD#Herr#Mustermann";  
      char trennzeichen = '#';  
      
      char *kopie = strdup(empfangspuffer); // Damit Original unveraendert bleibt.  
      char **result;                        // Hier kommen die Pointer auf die Teilstrings hinein  
      int  n=0;                             // ... und hier die Anzahl  
      
      char *tmp;  
      int   i;  
      
      for(tmp=kopie; *tmp; ++tmp)  
        if(*tmp==trennzeichen) { *tmp=(char)0; ++n; }  
      ++n;                                  // Es gibt einen Teilstring mehr als '#'s  
      
      result = (char**)malloc(n*sizeof(char*));  
      tmp = kopie;  
      
      for(i=0; i<n; ++i) {  
        result[i] = tmp;  
        tmp += strlen(tmp)+1;  
      }  
      
      // Ergebnisausgabe  
      
      printf("Anzahl der Teilstrings: %i\n", n);  
      for(i=0; i<n; ++i)  
        printf("Teilstring %i:  %s\n", i+1, result[i]);  
      
      // ggf. aufraeumen  
      free(result);  
      free(kopie);  
      
      return 0;  
    }  
    
    
    1. Moin.

      Falls es wirklich nur ein einzelnes Trennzeichen ist,
      kannst Du es Dir und der CPU auch leicht machen:

      1. Den gesamten String kopieren (nur, falls Du den
           Empfangspuffer noch anderweitig brauchst, ansonsten
           kann die Manipulation direkt im Empfangspuffer geschehen...)
      2. Alle '#' in der Kopie durch (char)0 ersetzen.

      Ich möchte dich jetzt nicht enttäuschen, aber das ist genau das, was Steffanies Lösung bereits tut (strtok ersetzt die Trennzeichen im String, daher legt Steffanie korrekterweise vorher eine Kopie von empfangspuffer in empfangsdaten ab).

      1. Ein Pointer-Array vom typ char** anlegen, welches
           auf die jeweiligen Teilstring-Fragmente zeigt.

      Das macht Steffanie allerdings nicht, sondern sie kopiert (vermutlich unnötigerweise - aber wer kann wissen, wie das ganze weiter verarbeitet werden soll?) den String erneut in ein weiteres Array.

      Meine Lösung arbeitet im übrigen genauso wie deine, nur, dass ich auf Rückgabewerte der malloc's (bei dir strdup) prüfe und im Gegensatz zu dir den String nur einmalig durchlaufe: Du tust dies einmal zum Ersetzen der Trennzeichen, und ein weiteres mal, um die Pointer in result abzulegen. Das ist nicht wirklich effizient...

      Christoph

      1. Hallo Christoph,

        Meine Lösung arbeitet im übrigen genauso wie deine, nur, dass ich auf Rückgabewerte der malloc's (bei dir strdup) prüfe und im Gegensatz zu dir den String nur einmalig durchlaufe: Du tust dies einmal zum Ersetzen der Trennzeichen, und ein weiteres mal, um die Pointer in result abzulegen. »»
        Christoph

        das liegt daran, dass man bei Deiner
        Funktion einen Parameter max_tokens
        angeben muss und überzählige Tokens dann
        einfach ignoriert werden, während meine Routine
        theoretisch beliebig lange Eingangsstrings
        zerlegt (mal von Speicherbegrenzungen
        und den fehlenden Sicherheitsabfragen abgesehen...).
        Der doppelte Durchlauf ergibt sich daraus, dass im
        ersten Durchlauf die Trennzeichen gezählt werden, damit
        result allozieren zu können.

        Viele Grüße und noch ein schönes
        verlängertes Wochenende

        Andreas