Forum: Compiler & IDEs strtok Problem


von Martin R. (m-joy)


Lesenswert?

Hallo,

ich möchte eine zeichenkette getrennt von "," aufteilen,
dafür mache ich folgendes:
1
typedef struct MD{
2
         char all[40];
3
         char *Name1;
4
         char *Name2;
5
         char Number;
6
    }DESCRIPTION;
7
8
struct Tree {
9
    DESCRIPTION MD;              ///< Module Description
10
} Tree;
11
12
13
char *buffer;
14
buffer=0;
15
16
17
Tree.MD.Name1 = strtok(Tree.MD.all, ",");
18
Tree.MD.Name2 = strtok(NULL, ",");
19
buffer = strtok(NULL, ",");
20
Tree.MD.Channel=*buffer;

Tree.MD.all wird eingelesen. Kann zb "BLA,BLA123,3" sein....
Ich möchte dass in Tree.MD.Channel jetzt der dritte abschnitt nach den 
komma steht. da steht aber irgendwie immer was anderes drin. Wenn ich 
Name1 und Name2 printe steht da aber das richtige drin.... Auch wenn ich 
Channel ohne buffer auslese und ausgebe steht da das richtige drin..
Ich möchte aber den Wert von Channel haben.

Grüße

von Rene H. (Gast)


Lesenswert?

Du musst den saveptr noch mitgeben:

man strtok
1
           for (j = 1, str1 = argv[1]; ; j++, str1 = NULL) {
2
               token = strtok_r(str1, argv[2], &saveptr1);
3
               if (token == N[LL)
4
                   break;
5
               printf("%d: %s\n", j, token);
6
7
               for (str2 = token; ; str2 = NULL) {
8
                   subtoken = strtok_r(str2, argv[3], &saveptr2);
9
                   if (subtoken == NULL)
10
                       break;
11
                   printf(" --> %s\n", subtoken);
12
               }
13
           }

Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

Huhu, was ist denn ein &saveptr1 ?

von Rene H. (Gast)


Lesenswert?

strtok speichert darin seine letzte Position. Sonst weiss er ja nicht, 
ab welcher Stelle er weitersuchen soll.

Also:
1
   char* saveptr;

Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

und wieso strtok_r statt strtok? ich meine strtok funktioniert ja, ich 
glaube nur dass irgendein pointer anstatt dem gewünschten inhalt 
ausgegeben wird.

von Rene H. (Gast)


Lesenswert?

In Deinem Fall müsste das demnach so aussehen (einfach so getippt uns 
ungetestet):
1
typedef struct MD{
2
         char all[40];
3
         char *Name1;
4
         char *Name2;
5
         char Number;
6
    }DESCRIPTION;
7
8
struct Tree {
9
    DESCRIPTION MD;              ///< Module Description
10
} Tree;
11
12
13
char *buffer;
14
buffer=0;
15
16
char* saveptr;
17
18
Tree.MD.Name1 = strtok(Tree.MD.all, ",");
19
Tree.MD.Name2 = strtok(NULL, ",", &saveptr);
20
buffer = strtok(NULL, ",", &saveptr);
21
Tree.MD.Channel=*buffer;

Grüsse,
René

von Rene H. (Gast)


Lesenswert?

Martin Rox schrieb:
> und wieso strtok_r statt strtok? ich meine strtok funktioniert ja, ich
> glaube nur dass irgendein pointer anstatt dem gewünschten inhalt
> ausgegeben wird.

Das war nur das Beispiel aus der man page. Du kannst natürlich strtok 
nehmen und brauchst nicht strtok_r.

Grüsse,
René

von Rene H. (Gast)


Lesenswert?

Aaargh

Da gehört natürlich der saveptr auch hin:
1
Tree.MD.Name1 = strtok(Tree.MD.all, ",", &saveptr);

Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

char *token;
char *saveptr1;


token = strtok_r(Tree.MD.all, ",",&saveptr1);


 error: assignment makes pointer from integer without a cast

von Rene H. (Gast)


Lesenswert?

hmm...

da gehts:
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdint.h>
4
#include <string.h>
5
#include <math.h>
6
7
8
9
int main (int argc, char *argv[])
10
{
11
  char* saveptr;
12
  char* tok;
13
  char val[127];
14
15
  strcpy (val,  "12,34,56,78");
16
17
18
  tok = strtok_r(val, ",", &saveptr);
19
  fprintf (stdout, "Tok: %s\n", tok);
20
21
  tok = strtok_r(NULL, ",", &saveptr);
22
  fprintf (stdout, "Tok: %s\n", tok);
23
24
  return (0);
25
}


:~/gcctest> gcc -o tmp2 tmp2.c
:~/gcctest> ./tmp2
Tok: 12
Tok: 34

Grüsse,
René

von Rolf Magnus (Gast)


Lesenswert?

Um es klarzustellen. Den saveptr gibt es nur bei strtok_r. strtok 
benötigt ihn nicht.

Martin Rox schrieb:
> Ich möchte dass in Tree.MD.Channel

Es gibt in Tree.MD kein Member mit Namen "Channel". Es wäre sinnvoll, 
den Code zu posten, den du tatsächlich probiert hast.


Martin Rox schrieb:
> token = strtok_r(Tree.MD.all, ",",&saveptr1);
>
>  error: assignment makes pointer from integer without a cast

Entweder hast du den Header vergessen, oder der Compiler ist in einen 
Modus geschaltet, in dem er strtok_r nicht kennt (z.B. C89 oder C99).

von Frank M. (ukw) (Moderator) Benutzerseite


Lesenswert?

Martin Rox schrieb:
>  error: assignment makes pointer from integer without a cast

Kein Wunder, denn Du hast offenbar ein

#include <string.h>

vergessen.

von Martin R. (m-joy)


Lesenswert?

komisch. bei mir nicht... benutze MPLAB 8 von microchip mit C32 
compiler...

von Martin R. (m-joy)


Lesenswert?

string.h ist included.

von Rolf Magnus (Gast)


Lesenswert?

Dann gibt's da wohl kein strtok_r. Dann eben doch strtok.

von Rene H. (Gast)


Lesenswert?

Poste mal den ganzen Code. Du hast da bei der Zuweisung einen Fehler 
(struct definition).

Rolf Magnus schrieb:
> Um es klarzustellen. Den saveptr gibt es nur bei strtok_r. strtok
> benötigt ihn nicht.

Das ist korrekt, dann muss man das Handling selber machen und jeweils 
den letzten Pointer als erster Parameter mitgeben.

Grüsse,
René

von Rene H. (Gast)


Lesenswert?

Dann eben mit strtok (nicht schön programmiert, nur um aufzuzeigen wie):
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <stdint.h>
4
#include <string.h>
5
#include <math.h>
6
7
8
9
int main (int argc, char *argv[])
10
{
11
  char* saveptr;
12
  char* tok;
13
  char val[127];
14
15
  strcpy (val,  "12,34,56,78");
16
17
18
  tok = strtok(val, ",");
19
  fprintf (stdout, "Tok: %s\n", tok);
20
21
  tok = strtok(tok+strlen(tok)+1, ",");
22
  fprintf (stdout, "Tok: %s\n", tok);
23
24
  // etc.....
25
26
  return (0);
27
}

Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

Huhu, also in meiner string.h gibt es:
char  *strtok_r (char *, const char *, char **);

ich habe zum testen deinen code kopiert, der klappt aber auch 
nicht...ich teste nochmal...

von Rene H. (Gast)


Lesenswert?

Definiere: "das klappt aber auch nicht".

Grüsse,
René

von Peter II (Gast)


Lesenswert?

Rene H. schrieb:
> Dann eben mit strtok (nicht schön programmiert, nur um aufzuzeigen wie):

warum nicht das richtige beispiel aus der doku verwenden, deine Lösung 
ist unsinn.

http://www.cplusplus.com/reference/cstring/strtok/

von Martin R. (m-joy)


Lesenswert?

ich glaube strtok_r ist verbuggt in meinem compiler. habe im microchip 
forum gelesen dass da paar string funktionen wohl buggy sind. ich widme 
mich also dem normalen strtok ^^ sooo mal gucken ob ich das 
hinbekomme....

von Rene H. (Gast)


Lesenswert?

Peter II schrieb:
> warum nicht das richtige beispiel aus der doku verwenden, deine Lösung
> ist unsinn.

Stimmt, hast völlig recht :-)

Grtüsse,
René

von Rene H. (Gast)


Lesenswert?

Das geht auch so:
1
  tok = strtok(val, ",");
2
  fprintf (stdout, "Tok: %s\n", tok);
3
4
  tok = strtok(NULL, ",");
5
  fprintf (stdout, "Tok: %s\n", tok);


Grüsse,
René

PS: getestet

von Rolf Magnus (Gast)


Lesenswert?

Rene H. schrieb:
> Rolf Magnus schrieb:
>> Um es klarzustellen. Den saveptr gibt es nur bei strtok_r. strtok
>> benötigt ihn nicht.
>
> Das ist korrekt, dann muss man das Handling selber machen und jeweils
> den letzten Pointer als erster Parameter mitgeben.

Nein. Das ist im Prinzip genau das, was man bei strtok_r macht. Bei 
strtok übergibt man einfach NULL. Den letzten Pointer merkt sich die 
Funktion intern, weshalb sie nicht reentrant ist. Dafür steht dann auch 
das _r bei strtok_r.

von Martin R. (m-joy)


Lesenswert?

huhu, jaaa das mit dem strtok geht bei mir auch. aber der trick ist ja, 
dass ich aus dem string die einzelnen wörter in variablen speicher will. 
und da speichert der irgendwie nichts gutes rein.
Beispiel:

String -> "Bla1,Bla2,123"

jetzt will ich dass 123 in meiner variablen "Nummer" steht...
wenn ich aber

 tok = strtok(val, ",");
Nummer=*tok;

mache, steht in nummer etwas anderes.... Also genauer ist der code am 
anfang den ich gepostet habe... Der fehler scheint bei der zuweisung zu 
entstehen, kann es sein dass hier:
Nummer=*tok;

nicht der inhalt ab dem komma, sondern nur der zeiger übergeben wird?

von Rene H. (Gast)


Lesenswert?

Martin Rox schrieb:
> tok = strtok(val, ",");
> Nummer=*tok;

Äaaah? Was ist Nummer? Ein int?
1
  uint8_t nummer = atoi(tok);


Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

Renee !!! ES KLAPPT das war der trick ich raste aus....

von Rene H. (Gast)


Lesenswert?

lol

Glückwunsch :-).

Grüsse,
René

von Martin R. (m-joy)


Lesenswert?

und wie ist der trick wenn ein Text im tok steht?

von Martin R. (m-joy)


Lesenswert?

seltsam, eigentlich ist nummer auch ein char. die sind eigentlich alle 
char :D aber mit atoi klappt es mit der nummer. wenn text drin steht 
dann klappt es nicht mit

Nummer=*tok;

von Rolf Magnus (Gast)


Lesenswert?

Martin Rox schrieb:
> seltsam, eigentlich ist nummer auch ein char. die sind eigentlich alle
> char :D aber mit atoi klappt es mit der nummer. wenn text drin steht
> dann klappt es nicht mit
>
> Nummer=*tok;

Was willst du denn nun drin speichern? Ein char kannst du verwenden, um 
genau ein Zeichen zu speichern, oder um eine Zahl im Bereich bis 127 (je 
nach CPU, aber 127 ist der sichere Wert) zu speichern.
Wenndu also Nunmmer=*tok schreibst, speicherst du das erste Zeichen von 
tok in Nummer. Wenn du atoi benutzt, wird das, was in tok steht, 
umgewandelt in eine Zahl, und die wird in Nummer gespeichert. Du kannst 
halt nicht beides haben.

von Rene H. (Gast)


Lesenswert?

Hi Martin,

ich habe den Eindruck, das nicht strtok Dein Problem war/ist. Kann es 
sein, dass Du ein Durcheinander machst mit Zeichenketten und Zahlen?

Falls ich Dich damit unterfordere, einfach ignrorieren.

ein
1
    char a;

stellt ein ASCII Zeichen dar und kann den numerischen Wert von -127 bis 
+127 annehmen. Im Speicher ist das ein Byte üblicherweise.

1
   char string[128];
2
3
   strcpy (string, "Meine Zeichenkette");

ist ein Zeiger auf eine Zeichenkette, also eine Anreihung von char's. Im 
Speicher braucht sie 128 Byte, benutzt davon werden aber lediglich  19 
Byte (inkl. der abschliessenden Null-Terminierung).

Wenn Du nun die Zuweisung machst:
1
    char aChar = *string;

steht in aChar ein M. Oder als Zahlenwert: 0x4d. Du dereferenzierst 
lediglich den char*, somit das erste Zeichen.


Wie willst Du Deine Tokens weiter verabeiten? Mit welchem Datentyp?
Du hast die Wahl Deine Tokens als String oder Wert zu verarbeiten:
1
    char    zahlenWert;
2
    uint8_t einByte;
3
4
    char tokenA[16];
5
    char tokenB[16];
6
7
    char* strZahl;
8
9
    strcpy (tokenA, "abc");
10
    strcpy (tokenB, "123");
11
12
    zahlenWert = *tokenA; // ergibt ASCII 0x61 oder 'a' als Zeichen
13
    zahlenWert = atoi(tokenA); // falsch, weil in Token A steht abc
14
15
    einByte = atoi(tokenB); // ergibt einByte = 123 als Zahl
16
    zahlenWert = *tokenB; // ergibt ASCII 0x31 oder '1' als Zeichen

Vielleicht hilft das etwas.

Grüsse,
René

von DirkB (Gast)


Lesenswert?

Das Problem wird die Unwissenheit über den Unterschied zwischen Ziffer 
und Zahl oder konkret zwischen 3 und '3' und "3"

Bzw. das eine Zeichenkette nicht durch eine einfache Zuweisung zu einem 
Zahlenwert führt sondern erst mit Hilfe einer Funktion gewandelt werden 
muss.

Das ist halt C und keine Typenlose Scriptsprache.

von Martin R. (m-joy)


Lesenswert?

Hallo Rene, ich glaube auch dass ich da was durcheinander wurschtel... 
danke für den beitrag, werde ich mir heute anschauen =)

grüße

von Martin R. (m-joy)


Lesenswert?

oah jetzt hab ichs hinbekommen.

Also erstmal ist es so, dass dieser strtok befehl irgendwie meinen 
strink zerhackt. Also habe ich den string vorher in eine neue variable 
kopiert, und die größen den chars definiert:
1
typedef struct MD{
2
         char all[40];
3
         char Name1[10];
4
         char Name2[20];
5
    }MD;
6
7
char all[40],*buffer;
8
strcpy(all,Tree.MD.all); //hier mache ich eine kopie um den string zu schützen

dann fange ich an:
1
buffer = strtok((char*)all, ",");
2
strcpy(Tree.MD.Name1,buffer);    //in meine variable speichern

und dann gehts weiter mit den nächsten teilen:
1
buffer = strtok(NULL, ",");
2
strcpy(Tree.MD.Name2,buffer);

und so weiter. dann habe ich den text in meinen variablen.
Spitze, danke für die hilfe.

von Rolf Magnus (Gast)


Lesenswert?

Rene H. schrieb:
> ein
>     char a;
>
> stellt ein ASCII Zeichen dar und kann den numerischen Wert von -127 bis
> +127 annehmen.

Ich weiß nicht, wie es beim C32 ist, aber prinzipiell sollte man char 
höchstens für den Bereich 0 bis 127, oder besser noch, einfach gar nicht 
für das Speichern von Zahlen verwenden. Es ist dem Compiler überlassen, 
ob char mit oder ohne Vorzeichen ist. Übrigens: Wenn es ein Vorzeichen 
hat, ist der Bereich meistens eher -128 bis 127.

> Im Speicher ist das ein Byte üblicherweise.

Es ist immer ein Byte, denn genau so ist in C das Byte definiert - als 
die Speichermenge, die ein char belegt.

von Martin R. (m-joy)


Lesenswert?

hallo rolf, meinstu, dass ich meine zeichenketten lieber als u8 als char 
definieren sollte?

Grüße

von Rolf Magnus (Gast)


Lesenswert?

Martin Rox schrieb:
> hallo rolf, meinstu, dass ich meine zeichenketten lieber als u8 als char
> definieren sollte?

Du kannst auch einfach signed oder unsigned char nehmen, also explzit 
angeben, ob Vorzeichen oder nicht.

von Rolf Magnus (Gast)


Lesenswert?

Martin Rox schrieb:
> Also erstmal ist es so, dass dieser strtok befehl irgendwie meinen
> strink zerhackt.

Das ist so bei strtrok. Steht normalerweise auch in der Doku drin.

von Klaus W. (mfgkw)


Lesenswert?

Martin Rox schrieb:
> Also erstmal ist es so, dass dieser strtok befehl irgendwie meinen
> strink zerhackt.

Das ist das erwartete Verhalten von strtok(), steht auch in jeder Doku 
dazu drin.

Ansonsten würden die gelieferten Zeiger auf die einzelnen Token ja nicht 
auf jeweils nullterminierte Strings zeigen - die dafür notwendige 
Terminierung der einzelnen Token muß von strtok() in den String 
geschrieben werden anstelle des gefundenen Trennzeichens.

von Klaus W. (mfgkw)


Lesenswert?

Fast wörtliche Übereinstimmung, gut gemacht! :-)

von Rene H. (Gast)


Lesenswert?

Rolf Magnus schrieb:
>> Im Speicher ist das ein Byte üblicherweise.
>
> Es ist immer ein Byte, denn genau so ist in C das Byte definiert - als
> die Speichermenge, die ein char belegt.

Ok, ich kannte die Definition nicht, resp. war mir unsicher, deshalb 
meine vorsichtige Aussage. Vorstellen hätte ich mir können, dass es 
irgendeinen Compiler gibt der per default oder Option w_char macht o.ä.
Ich meine, dass das hier auch schon Thema war.

Grüsse,
René

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.