mikrocontroller.net

Forum: Mikrocontroller und Digitale Elektronik String zerlegen funktioniert nicht richtig, 2-dimensionales Array


Autor: Michl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.
void store_irgendwas (char* ptr_source)
{
  char Datafield[20][10];
  char* ptr_Datafield;
  unsigned char counter;

  counter = 0;

  strtok (ptr_source, ",*");
  while (ptr_Datafield != NULL)
  {
    ptr_Datafield = &Datafield[counter][0];
    ptr_Datafield = strtok(NULL, ",*");
    counter++;
  }
  

  while(counter)
  {
    UART2_Transmit((unsigned char*) &Datafield[counter][0], 10);
    counter--;
  }
}

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

Vielen Dank schonmal im Voraus.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ein Fehler ist schon Mal in
    UART2_Transmit((unsigned char*) &Datafield[counter][0], 10);
sollte
    UART2_Transmit((unsigned char*) &Datafield[counter-1][0], 10);
heißen!

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
einen hab ich noch:
ptr_Datafield = strtok (ptr_source, ",*");
statt
strtok (ptr_source, ",*");

Autor: Michl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ne das erste kann verworfen werden, das is ok.
Das mit dem counter wieder um 1 dekrementieren ist wohl wahr^^ nichts 
desto trotz werden die anderen Strings falsch ausgegeben

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Walter:
nee, das stimmt schon.
Ab dem zweiten Aufruf gibt man strtok doch NULL als
Zeiger, dann läuft es intern weiter.

Mir fehlt so ein bißchen eine vernünftige Fehlerbeschreibung...

Autor: Michl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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:
void store_nmea (unsigned char nmea_msg_id, char* ptr_source)
{
  char Datafield[20][11];
  char strlen_Datafield;
  char* ptr_Datafield;
  unsigned char counter;

  counter = 0;


  strtok (ptr_source, ",*");
  while (ptr_Datafield != NULL)
  {
    ptr_Datafield = strtok(NULL, ",*");
    strlen_Datafield = strlen(ptr_Datafield);
    strncpy ((char*)&(Datafield[counter][0]), ptr_Datafield, strlen_Datafield);
    Datafield[counter][strlen_Datafield] = 0x00;
    UART2_Transmit((unsigned char*)&Datafield[counter][0], strlen(Datafield[counter]));
    counter++;
  }
  
/*  while(counter)
  {
    UART2_Transmit((unsigned char*) &Datafield[counter][0], 10);
    counter--;
  }*/
}

Autor: Klaus Wachtler (mfgkw)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Genau!

Mit der Originalversion:
    ptr_Datafield = &Datafield[counter][0];
    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.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du brauchst gar kein 2D Array.
Du brauchst ein Array von Pointern in welche du die Pointer, die dir 
strtok liefert, abspeicherst.
Jeder Pointer zeigt dann auf den Anfang eines Strings.

Autor: Walter (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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!

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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!
void store_irgendwas (char* ptr_source)
{
  char* ptr_Datafield[20];
  unsigned char counter;

  counter = 0;

  ptr_Datafield[counter] = strtok (ptr_source, ",*");
  while (ptr_Datafield[counter] != NULL)
  {
    counter++;
    ptr_Datafield[counter] = strtok(NULL, ",*");
  }
  

  while(counter)
  {
    UART2_Transmit((unsigned char*)ptr_Datafield[counter], 10);
    counter--;
  }
}

und denk drann, dass dir strtok den Originalstring zerstört

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Michl (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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 :-/

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Michl (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mir gehts darum ,dass mit der
 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).

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht 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

Autor: P. S. (Gast)
Datum:

Bewertung
0 lesenswert
nicht 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.

Autor: Nick Müller (muellernick)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Geht's noch?!? Du hast Nichts gefragt, du hast Unsinn verbreitet.

Auf der Boxerzeitung geschlafen?
Oder bist du MaWin?


Explizit grußlos,
Nick

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.