String zerlegen funktioniert nicht richtig, 2-dimensionales Array

Gast #1505278
Lesenswert?

Hallo Leute,
folgendes Problem: Ich bekommen einen Pointer auf das erste Element 
eines Strings übergeben. Dieser String ist informell durch Kommas und 
Sterne unterteilt.
Nun versuche ich die jeweiligen Teilstrings mit "strtok" zu zerlegen und 
in einem zwei-dimensionalen Array zu speichern.
Leider funktioniert es nicht so wie ich will.
1
void store_irgendwas (char* ptr_source)
2
{
3
  char Datafield[20][10];
4
  char* ptr_Datafield;
5
  unsigned char counter;
6

7
  counter = 0;
8

9
  strtok (ptr_source, ",*");
10
  while (ptr_Datafield != NULL)
11
  {
12
    ptr_Datafield = &Datafield[counter][0];
13
    ptr_Datafield = strtok(NULL, ",*");
14
    counter++;
15
  }
16
  
17

18
  while(counter)
19
  {
20
    UART2_Transmit((unsigned char*) &Datafield[counter][0], 10);
21
    counter--;
22
  }
23
}

Ich weiß nur nicht warum... denke es liegt irgendwo an dem Zusammenspiel 
zwischen dem Pointer und "strtok".

Vielen Dank schonmal im Voraus.
Gast #1505329
Lesenswert?

Es sieht so aus, also ob der von strtok zurückgegebene String (bzw. die 
Adresse) nicht in meinem Array gespeichert wird.
Wobei es mir solangsam dämmert. Bitte korriegiert mich, wenn ich falsch 
liege:

Der aufruf mit strtok an sich stimmt. Allerdings gibt strtok einen 
Pointer auf die Anfangsadresse des ermittelten Strings zurück. Daher 
funktioniert das Speichern in meinen 2D-Array nicht. Vielmehr müsste ich 
manuell mit strncpy arbeiten...
In etwa so:
1
void store_nmea (unsigned char nmea_msg_id, char* ptr_source)
2
{
3
  char Datafield[20][11];
4
  char strlen_Datafield;
5
  char* ptr_Datafield;
6
  unsigned char counter;
7

8
  counter = 0;
9

10

11
  strtok (ptr_source, ",*");
12
  while (ptr_Datafield != NULL)
13
  {
14
    ptr_Datafield = strtok(NULL, ",*");
15
    strlen_Datafield = strlen(ptr_Datafield);
16
    strncpy ((char*)&(Datafield[counter][0]), ptr_Datafield, strlen_Datafield);
17
    Datafield[counter][strlen_Datafield] = 0x00;
18
    UART2_Transmit((unsigned char*)&Datafield[counter][0], strlen(Datafield[counter]));
19
    counter++;
20
  }
21
  
22
/*  while(counter)
23
  {
24
    UART2_Transmit((unsigned char*) &Datafield[counter][0], 10);
25
    counter--;
26
  }*/
27
}
#1505493
Lesenswert?

Genau!

Mit der Originalversion:
1
    ptr_Datafield = &Datafield[counter][0];
2
    ptr_Datafield = strtok(NULL, ",*");
wird nur der Zeiger ptr_Datafield erst auf ein Array-Element
gerichtet, dann gleich wieder in den zerlegten String.
Letztlich wird kein String in das Array kopiert.
Gast #1505734
Lesenswert?

den hab ich immer noch oder sollte ich über Nacht erblindet sein:
ptr_Datafield = strtok (ptr_source, ",*");
statt
strtok (ptr_source, ",*");

ptr_Datafield ist doch nicht initialisiert, da müsste doch auch der 
Compiler eine Warnung bringen!
#1505738
Lesenswert?

Walter schrieb:
> den hab ich immer noch oder sollte ich über Nacht erblindet sein:
> ptr_Datafield = strtok (ptr_source, ",*");
> statt
> strtok (ptr_source, ",*");
>

Du hast nur einen Pointer!
Du brauchst aber ein Array von Pointern!
1
void store_irgendwas (char* ptr_source)
2
{
3
  char* ptr_Datafield[20];
4
  unsigned char counter;
5

6
  counter = 0;
7

8
  ptr_Datafield[counter] = strtok (ptr_source, ",*");
9
  while (ptr_Datafield[counter] != NULL)
10
  {
11
    counter++;
12
    ptr_Datafield[counter] = strtok(NULL, ",*");
13
  }
14
  
15

16
  while(counter)
17
  {
18
    UART2_Transmit((unsigned char*)ptr_Datafield[counter], 10);
19
    counter--;
20
  }
21
}

und denk drann, dass dir strtok den Originalstring zerstört
Gast #1505744
Lesenswert?

> Jeder Pointer zeigt dann auf den Anfang eines Strings.

Ohne es ausprobiert zu haben, aber ich glaub das geht nicht. 
Vermuteterweise zeigt danach der Pointer auf den Anfang eines tokens 
incl. dem kompletten Reststring.
Man muss also den Teilstring kopieren, denn strtok ist auf den 
Eingabestring nicht destruktiv.


Ansonsten kann ich nur das Buch "C in a Nutshell" v. O'Reilly empfehlen. 
Da wird sowas kompakt beschrieben.


Gruß,
Nick
Gast #1505760
Lesenswert?

Klar das würde auch gehn. Aber dann müste ich doch mit "malloc" Speicher 
allokieren, damit mir die Strings nicht irgendwo im Speicher stehn. 
Zumal ich strtok ja immer wieder aufrufe.
Der Quellstring ändert sich auch immer, auch in seiner Länge sowie der 
Länge der jeweiligen Teistrings.
Mit der obigen Variante geh ich dabei schon eher auf Nummer Sicher.
Gast #1505761
Lesenswert?

Walter schrieb:

> den hab ich immer noch oder sollte ich über Nacht erblindet sein:

Keine Angst, du hast schon recht. Vor Allem mit der Warning - leider 
scheinen gerade Anfaenger Warnings keinerlei Bedeutung beizumessen :-/
#1505763
Lesenswert?

Nick Müller schrieb:
>> Jeder Pointer zeigt dann auf den Anfang eines Strings.
>
> Ohne es ausprobiert zu haben, aber ich glaub das geht nicht.
> Vermuteterweise zeigt danach der Pointer auf den Anfang eines tokens
> incl. dem kompletten Reststring.

Nein tut es nicht.

> Man muss also den Teilstring kopieren, denn strtok ist auf den
> Eingabestring nicht destruktiv.

Doch, ist es.


Bitte, lest die Doku zu strtok.

strtok manipuliert den Originalstring, indem es an den Trennungsstellen 
(die durch das Delimiter Token gegeben sind) '\0' einfügt!

Aus
  "Hallo World"

macht strtok (mit einem Blank als Delimiter

   "Hallo\0World"

Beim ersten Aufruf von strtok kriegt man einen Pointer auf das 'H' 
zurück (und gleichzeitig wird das \0 eingefügt). Beim nächsten Aufruf 
kriegt man einen Pointer auf das 'W' und beim dritten Aufruf kommt dann 
NULL zurück.

strtok darf niemals auf String-Literale angewendet werden, weil ja der 
Originalstring manipuliert wird.
Gast #1505778
Lesenswert?

Nick Müller schrieb:
>> Jeder Pointer zeigt dann auf den Anfang eines Strings.
> Ohne es ausprobiert zu haben, aber ich glaub das geht nicht.

Ich verstehe ehrlich gesagt nicht, warum man sein Nichtwissen auch noch 
postet, wenn man sich dessen eigentlich schon bewusst ist.

Wenn wir schon dabei sind: strtok wuerde ich mir gar nicht erst 
angewoehnen, sondern gleich seinen reentranten Vetter strtok_r. Auch in 
nicht parallelen Applikationen kann man mit nicht-reentranten Funktionen 
sehr schnell auf die Nase fallen.
Gast #1505785
Lesenswert?

Mir gehts darum ,dass mit der
1
 char* ptr_Datafield[20]
-Methode die einzelnen Strings irgendwo im Speicher des µC stehn und 
evtl. andere Daten überschrieben werden könnten. Oder legt mir strtok 
bei jedem Aufruf reservierte Speicherbereiche an, die NACH(!) der 
while-Schleife noch existent sind? Weil erst da werden die einzelnen 
Tokens weiterverarbeitet (hier zu Testzwecken eine UART-Ausgabe).
Gast #1505793
Lesenswert?

strtok gibt dir Nichts neu allokiertes zurueck, sondern lediglich einen 
Pointer auf eine Position in dem String, den du uebergeben hast. 
Ausserdem sucht es das Ende des Teilstuecks (anhand der uebergebenen 
Tokentrenner) und setzt dort eine 0 als Terminator - es veraendert also 
den String, den du uebergeben hast. Und zuguter Letzt merkt es sich, wo 
es beim naechsten Aufruf weitersuchen muss.
Gast #1505796
Lesenswert?

> Bitte, lest die Doku zu strtok.

Hab ich doch. Dann ist das Buch doch nicht so toll :-) Denn das steht 
da nicht drinnen. Zumindest nicht explizit.
Im "The Standard C Library" v. P.J. Plauger wirds dann klarer...


> strtok manipuliert den Originalstring, indem es an den Trennungsstellen
> (die durch das Delimiter Token gegeben sind) '\0' einfügt!

War mir nicht bewusst, ist mir nie aufgefallen.


Gruß,
Nick
Gast #1505798
Lesenswert?

> Ich verstehe ehrlich gesagt nicht, warum man sein Nichtwissen auch noch
> postet, wenn man sich dessen eigentlich schon bewusst ist.

Reichlich bekloppte Aussage! Damit dürften nach deiner Vorschrift keine 
Fragen gestellt werden.


Dennoch Gruß,
Nick
Gast #1505807
Lesenswert?

Nick Müller schrieb:
>> Ich verstehe ehrlich gesagt nicht, warum man sein Nichtwissen auch noch
>> postet, wenn man sich dessen eigentlich schon bewusst ist.
> Reichlich bekloppte Aussage! Damit dürften nach deiner Vorschrift keine
> Fragen gestellt werden.

Geht's noch?!? Du hast Nichts gefragt, du hast Unsinn verbreitet.

Ich bin mit Karl-Heinz oft nicht einer Meinung, aber an seinem 
Fachwissen gibt es wenig zu bezweifeln, das hat er oft genug bewiesen. 
Und du stellst dich da hin und erklaerst, dass du zwar keine Ahnung 
hast, aber seine Ausfuehrungen einfach mal nicht glaubst. Das finde ich, 
mit Verlaub gesagt, ziemlich frech.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren