www.mikrocontroller.net

Forum: Compiler & IDEs strtok aus Galileo Computing C von A bis Z


Autor: gert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
im buch 'C von A bis Z' steht folgendes geschrieben:

---------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 255
char *eingabe(char *str) {
   char input[MAX];
   printf("Bitte \"%s\" eingeben: ",str);
   fgets(input, MAX, stdin);
   return strtok(input, "\n");
}
int main(void) {
   char *ptr;
   ptr = eingabe("Vorname");
   printf("Hallo %s\n", ptr);
   ptr = eingabe("Nachname");
   printf("%s, interssanter Nachname\n", ptr);
   return EXIT_SUCCESS;
}

Der Funktion eingabe() wird hierbei als Argument die Adresse eines 
Strings übergeben. In der Funktion werden Sie aufgefordert, einen Namen 
einzugeben. Die Anfangsadresse des Strings geben Sie mit folgender Zeile 
zurück:
return strtok(input, "\n");

Die Funktion strtok() liefert ja selbst als Rückgabewert einen 
char-Zeiger zurück. Da die Funktion fgets() beim Einlesen von der 
Standardeingabe das Newline-Zeichen mit einliest, haben Sie hierbei 
gleich zwei Fliegen mit einer Klappe geschlagen. Das Newline-Zeichen 
wird mit strtok() entfernt, und die Funktion liefert auch gleich die 
Anfangsadresse des Strings input als Rückgabewert zurück, welchen Sie 
gleich mit return weiterverwenden. Doch Vorsicht, Folgendes funktioniert 
nicht:
char *eingabe(char *str) {
   char input[MAX];
   printf("Bitte \"%s\" eingeben: ", str);
   fgets(input, MAX, stdin);
   return input;
}

Normalerweise sollte hier der Compiler schon meckern, dass etwas nicht 
stimmt. Spätestens aber, wenn Sie das Beispiel ausführen, werden Sie 
feststellen, dass anstatt des Strings, den Sie in der Funktion eingabe() 
eingegeben haben, nur Datenmüll ausgegeben wird.
---------------------------------------------

die strtok funktion liefert ja auch nur einen pointer auf den 
übergebenen string , dh. der test mittels return strtok(input, "\n"); 
sollte auch nur datenmüll liefern ?

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

Bewertung
0 lesenswert
nicht lesenswert
gert wrote:

>
char *eingabe(char *str) {
>    char input[MAX];
>    printf("Bitte \"%s\" eingeben: ", str);
>    fgets(input, MAX, stdin);
>    return input;
> }
>
> Normalerweise sollte hier der Compiler schon meckern, dass etwas nicht
> stimmt. Spätestens aber, wenn Sie das Beispiel ausführen, werden Sie
> feststellen, dass anstatt des Strings, den Sie in der Funktion eingabe()
> eingegeben haben, nur Datenmüll ausgegeben wird.

Das Problem an dieser Stelle ist, dass hier ein Pointer auf eine lokale 
Variable (nämlich input) zurückgegeben wird. Lokale Variablen werden 
aber beim Verlassen einer Funktion zerstört. Damit liefert die Funktion 
einen Pointer auf eine Variable die nicht mehr existiert.

> die strtok funktion liefert ja auch nur einen pointer auf den
> übergebenen string , dh. der test mittels return strtok(input, "\n");
> sollte auch nur datenmüll liefern ?

Genau. Der retournierte Pointer ist im Prinzip immer noch ein Pointer 
auf input. strtok ändert daran nichts. Wenn die angegebene Lösung als 
Musterlösung präsentiert wird, dann ist diese Musterlösung fehlerhaft.

Autor: gert (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ok danke - ja im buch wird dies tatsächlich als lösung vorgeschlagen, 
und da ja strtok zb keinen neuen speicher vom heap anfordert (als return 
value ), kann dies nicht gehen ...

Autor: Εrnst B✶ (ernst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die übliche Quick-n-Dirty Lösung wäre, einfach das input-array als 
static zu deklarieren, dann bleibt der Pointer gültig.

Ist aber keine schöne Lösung, spätestens wenn jemand das ganze mit 
Threads verwenden will fliegt er auf die Schnauze…

Autor: tuppes (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja ja, Zeichenketten in C, immer wieder leidiges Thema.

Am besten, man verabschiedet sich von dem Dogma, dass das Ergebnis als 
Returnwert zurückgegeben werden muss, und baut etwas in dieser Art:
void eingabe(char * input, const char *message) {
   printf("Bitte \"%s\" eingeben: ", message);
   fgets(input, MAX, stdin);  // Achtung: Buffer-Overrun-Check fehlt hier!
}

Das Ergebnis wird über einen Aufrufparameter herausgereicht, den 
Speicher dafür stellt der Aufrufer zur Verfügung und weiß daher auch, 
ob der Speicher ggfs. wieder weggeräumt werden muss.

Das Beispiel ist natürlich nur als Demonstration gedacht. Es prüft nicht 
auf Buffer Overrun (muss unbedingt gemacht werden!).

Außerdem ists vom Design her etwas merkwürdig, dass eine Routine, die 
"eingabe" heißt, als allererstes eine Ausgabe macht. Aber ich wollte 
nicht zu sehr von der Vorlage abweichen.

--------------------------------------------------

Ein anderer Ansatz wäre, eine Art "String-Objekt" zu definieren, dass 
return-fähig ist und das ganze Speichermanagement intern kapselt. Aber 
das geht über Anfängerstoff eindeutig hinaus.

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.