Forum: Mikrocontroller und Digitale Elektronik strtok_r: Ergebnis unerwartet


von Holger M. (nezaya)


Lesenswert?

Hallo,

Ich habe einen String, den ich mit der C-Funktion strtok_r in 
Teilstrings zerlegen will.
In folgendem Beispiel funktioniert das auch wie gewünscht.
1
char string[50] = "wert1,wert2,wert3,wert4,..."
2
char *tmp;
3
char *feld1;
4
char *feld2;
5
char *feld3;
6
...
7
feld1=strtok_r(string,",",&tmp);
8
feld2=strtok_r(NULL,",",&tmp);
9
feld3=strtok_r(NULL,",",&tmp);
10
...
Ergebnis ist feld1 zeitgt auf wert1, usw...

Laut Beschreibung ersetzt die Funktion ja nur alle Trennzeichen durch \0 
und gibt bei jedem Aufruf einen Pointer auf den nächsten Stringteil 
zurück.

Also sieht der String im Speicher vorher so aus:
wert1,wert2,wert3,...wertn\0
Und nachher:
wert1\0wert2\0wert3\0...wertn\0
|      |      |         |

Die zurückgelieferten Zeiger zeigen dann immer auf die mit | 
gekennzeichneten Stellen im Speicher.

Nur wenn jetzt im String ein Wert fehlt, also der String z.B. wir folgt 
aussieht:
wert1,,wert3,...wertn\0
Dann ist das Ergebnist nicht mehr das von mir erwartete.

Meine Überlegung war, dass dann feld2 am Schluss auf einen leeren String 
'\0' zeigen würde und alle anderen Felder ihren eigentlichen "Inhalt" 
hätten.
wert1\0\0wert3\0...wertn\0
|      | |         |

Leider sind jedoch stattdessen alle Felder um eins verschoben, da der 
doppelte Trenner übersprungen wird.
wert1\0\0wert3\0...wertn\0
|        |         |

Ist das ein Bug, oder gewollt? Wenn gewollt, kennt jemand eine andere 
Funktion, die das so erledigt, wie ich es machen will? Sonst muss ichs 
halt selbst schreiben.

Compiler ist WinAVR in Version 20070122. Laufen soll das auf nem Mega 
32(4).

Gruß Holger

von holger (Gast)


Lesenswert?

Hallo Namensvetter :)

Ein Bug ist das sicher nicht. Wo kein Teilstring steht
kann man auch kein \0 dranhängen.

Du musst jetzt aber nicht gleich strtok_r()
komplett neu schreiben.

Prüfe deinen String auf ",," Stellen bevor du sie an
strtok_r() übergibst. Füge eine 0 ein wenn du so eine
Stelle findest. ",0,". Das sollte gehen.

Kommen deine Strings aus einem GPS ?

von Werner Hoch (Gast)


Lesenswert?

Such dir eine andere Funktion raus:

man strtok_r sagt:

BUGS
       Avoid using these functions.  If you do use them, note that:

              These functions modify their first argument.

              These functions cannot be used on constant strings.

              The identity of the delimiting character is lost.

              The  strtok()  function  uses  a static buffer while 
parsing, so
              it's not thread safe. Use strtok_r() if this matters to 
you.

von Uhu U. (uhu)


Lesenswert?

strtok_r frißt auch mehrere direkt aufeinanderfolgende Trennzeichen.

Deshalb ist sie für Strings, in denen Werte fehlen, nicht geeignet. 
(Generell sind diese Funktionen nicht nur unsicher, sondern auch von 
ziemlich beschränktem Nutzen.)

Ich würde in einer Schleife einen Pointer über den String laufen lassen 
und die Zerteilerei zu Fuß machen.

von Holger M. (nezaya)


Lesenswert?

Danke für eure Antworten.

@Werner Hoch: Naja, die Bugs sind nicht wirklich Bugs, sondern eher 
Nachteile. Die Spielen bei mir aber alle keine Rolle, da die Funktion an 
sich genau das tut, was sie sollt. Bis auf das fressen der doppelten 
Trennzeichen.

@holger: Zeichen hinzufügen ist problematisch, der String ist lang. Bis 
zu 150 Zeichen oder evt. auch mehr. Das ist schon etwas Aufwand soviel 
im Speicher rumzukopieren, wenn ich da jeweils pro Fehlstelle ein 
Zeichen anhängen muss. Außer ich könnte das schon in der Leseroutine 
machen, da ginge es schneller. Müsste ich mal prüfen.
GPS ist es nicht, aber die Daten sind NMEA ähnlich.

> Ich würde in einer Schleife einen Pointer über den String laufen lassen
> und die Zerteilerei zu Fuß machen.

strtok_r ist da schon etwas eleganter, und wohl auch schneller.

Ich werde wohl den Code aus der String-Lib etwas modifizieren. Und 
einfach den Teil rauslassen, der die mehrfachen Trennzeichen 
überspringt. Dann hätte ich genau was ich suche.

Gruß Holger

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.