hallo leute,
folgenden prozedur liefert auf grund da input nur " 51 " ist müll
zurück!
darunter findet ihr dann ein beispiel welches läuft, aber ich verstehe
fgets anscheinend nicht richtig! warum funktionieren nicht beide?
denn der wert wie gross der string ist, sollte doch mir überlassen
sein! woran scheitert es?
BSP1.:
--------------------------------------------------------------------
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX 51
char *eingabe(char *str){
char input[MAX];
printf("bitte \"%s\" eingeben!\n",str);
fgets(input, MAX, stdin);
return strtok(input, "\n");
}
int main(void){
char *ptr;
ptr = eingabe("vorname");
printf("hallo %s\n", ptr);
getchar();
return EXIT_SUCCESS;
}
BSP2.:
---------------------------------------------------------------
diese hier bei welcher MAX den wert 255 (also sehr gross zum obigen
beispiel wo der wert nur auf 51 war) hat, läuft korrekt!
/* ptr13.c */
#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;
}
WARUM laufen nicht beide programme einwandfrei?
danke schon im voraus für eure hilfe
>Raphael
Beide Beispiele sind fehlerhaft. Der Puffer char input[MAX]; ist bei deinen Beispielen nicht statisch. Sobald eingabe() verlassen wird, darf darauf nicht mehr zugegriffen werden!
Du gibst in der Funktion "eingabe" einen Pointer auf eine lokale Variable dieser Funktion zurück. Die liegt auf dem Stack und ist nach Verlassen der Funktion ungültig. Entweder das Array "input" als "static" oder aber außerhalb der Funktion "eingabe" deklarieren.
ich weiss was ihr meint! jedoch, da das programm funktioniert (zumindest programm nummer 2, in welchem MAX 255 gross ist, wobei ich nicht verstehe warum programm 1 nicht funktioniert in dem MAX relativ klein 51 ist) kann anscheinend doch auf die variable auch nach ende des funktionsaufrufes zurückgegriffen werden!!! das programm BSP2.: stammt aus dem buch c von a bis z. ich weiss, dass normalerweise auf eine
fortsetzung: ich weiss, dass normalerweise auf eine lokale variable nach beendigung der funktion in welcher sie deklariert wurde nicht mehr zugegriffen werden kann... aber hier geht es!!! warum?
aber erstmals vielen dank
nun mit der GLOBAL deklarierten variable "char input[MAX]" läuft auch
programm BSP1.
dürfte ein komischer zufalle gewesen sein, dass BSP2 auch so richtig
gelaufen ist!!!
komisch
liebe grüße und danke
>Raph
Hi, > dürfte ein komischer zufalle gewesen sein, dass BSP2 auch so > richtig gelaufen ist!!! Ja, das war Zufall. Sowas klappt nur dann, wenn die Information noch auf Stack vorhanden ist, worauf man sich aber nie verlassen kann und auch nicht sollte. Grüße mplusplus
ALLES FALSCH jetzt hab ichs!!! in diesem beispiel wurde ein Zeiger als Argument übergeben! darum muss die variable "char input[MAX]" nicht als STATIC oder GLOBAL deklariert sein! Die Funktion eingabe() gibt eben einen solchen Speicherbereich (lokales Feld) zurück, der sich ebenfalls auf diesem Stack-Frame befindet bzw. befand und somit bei Beendigung der Funktion nicht mehr vorhanden ist. Wollen Sie also einen Zeiger auf einen Speicherbereich zurückgeben, haben Sie folgende Möglichkeiten. Sie verwenden ... -einen statischen Puffer (static). -einen beim Aufruf der Funktion als Argument übergebenen Puffer. -einen mittels malloc() reservierten Speicher Bsp.: Hierzu ein Beispiel, welches alle drei Möglichkeiten demonstrieren soll: /* ptr14.c */ #include <stdio.h> #include <stdlib.h> #include <string.h> /* Fehler: Funktion gibt die Adresse * einer lokalen Variablen zurück */ char *test1(void){ char buffer[10]; strcpy(buffer, "testwert"); return buffer; } /* Möglichkeit1: Statische Variable */ char *test2(void){ static char buffer[10]; strcpy(buffer, "testwert"); return buffer; } /* Möglichkeit2: Speicher vom Heap verwenden */ char *test3(void){ char *buffer = (char *) malloc(10); strcpy(buffer, "testwert"); return buffer; } /* Möglichkeit3: Einen Zeiger als Argument übergeben */ char *test4(char *ptr){ char buffer[10]; ptr = buffer; strcpy(buffer, "testwert"); return ptr; } int main(void) { char *ptr; ptr = test1(); printf("test1: %s\n", ptr); // Datenmüll ptr = test2(); printf("test2: %s\n", ptr); ptr = test3(); printf("test3: %s\n", ptr); test4(ptr); printf("test4: %s\n", ptr); return EXIT_SUCCESS; } das war nun die erklärung/lösung meines problems!!! lg >Raphael
Nein, Du hast es nicht. Möglichkeit 4 unterscheidet sich inhaltlich nicht von der fehlerhaften Möglichkeit 1, denn der Puffer, auf den der Pointer verweist, ist nach wie vor ein lokaler Puffer. Und ist damit ebenso falsch. Mäßig korrekt sind somit nur 2 und 3, wobei bei 3 nach Aufruf der Funktion tunlichst der per malloc angeforderte Speicher auch wiederfreigegeben werden sollte, sonst gibt es Speicherlecks.
@ Raphael Reu > das programm BSP2.: stammt aus dem buch c von a bis z. In der aktuellen 2. Druckauflage oder in der Online-Version ( http://www.pronix.de/pronix-4.html )? Wenn ja, schreibe dem Jürgen Wolf, dass du einen Fehler gefunden hast ;-)
> das programm BSP2.: stammt aus dem buch c von a bis z.
Ich hoffe es ist dort als abschreckendes Beispiel gezeigt, das
verdeutlicht das 'undefiniertes Verhalten' (so heist das in
der C-Fachsprache) auch bedeuten kann: "Sieht auf den ersten
Blick so aus als ob es gehen würde, ist aber trotzdem falsch."
hi leute,
ist in der online fassung und in meinem buch gleich! also wenn es
tatsächlich ein fehler ist, dann in allen versionen!
ich hab ja den "fehler" nicht gefunden! den habt ja ihr gefunden :-)
leute ich weiss was undefiniertes verhalten bedeutet... das einzige was
ich nicht kann ist anständig zu programmieren!!! darum arbeite ich ja
hart daran :-)
es war mich auch unklar, aber ich dachte durch
return strtok(variable, "\n"); /* auch wenn sie "nur" in der
aufgerufenen funktion deklariert ist, bleibt der speicher erhalten!
... da jürgen wolf in seinem buch ja auch extra angegeben hatte EINEN
ZEIGER ALS ARGUMENT ÜBERGEBEN .. dachte ich dies ist eine andere
vorgehensweise!
nun gut, ich werde jürgen wolf darauf aufmerksam machen
mal sehn was er dazu sagt...
:-) in zukunft werd ich mit static oder GLOBAL arbeiten!!!
danke leute
>Raphael
Warte noch! Es ist deutlich als ein abschreckendes Beispiel gekennzeichnet, so wie Karl Heinz Buchegger gemeint hat! Auszug aus dem Text: "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." http://www.pronix.de/pronix-743.html
Aber im "Hierzu ein Beispiel, welches alle drei Möglichkeiten demonstrieren soll:" sind Fehler und Unschönheiten drin, wie Rufus T. Firefly schon geschrieben hat.
ja leute war mein fehler, sehr peinlich ich dachte er meinte als abschreckendes beispiel folgenden auszug welcher kurz nach dem eigentlich programm kam char *eingabe(char *str){ char input[MAX]; printf("Bitte \"%s\" eingeben: ", str); fgets(input, MAX, stdin); return input; } tut mir total leid leute ich hab mir diese zeilen auch gelesen... nur ich dachte er meinte das folgende ich tip die listen chronologisch ab, und das buch find ich auch sehr gut und ausführlich, nur er gibt oft negativbeispiele an... in diesem fall hab ichs nicht erkannt!!! sorry leute!!! bin normal vorsichtig beim posten
@Stefan dieser Satz bezieht sich auf den Fall, dass die lokal definierte Zeichenkette input direkt als Rückgabewert verwendet wird, also ohne strtok(). Kann es vieleicht sein, dass strtok() den extrahierten String selber nochmal als static speichert und den Zeiger auf diese (noch gültigen Daten) zurückgibt? strtok() verwendet ja je nach Übergabewerten Daten aus vorherigen Aufrufen. Ein Link dazu: http://ivs.cs.uni-magdeburg.de/bs/lehre/wise0102/usp/seminare/seminar3.shtml Grüße mplusplus
das hab ich ja anfangs auch vermutet!!! aber da anscheinend BSP2 zufällig richtig läuft und BSP1 nicht denke ich nicht dass strtok() den extrahierten string selber nochmal als static speichert! aber ich weiss es nicht... ich sollt mich mit was leichterem befassen!!! soweit bin ich wie man merkt noch nicht :-)
Diese Beschreibung ist nicht eindeutig. Ich würde hierzu empfehlen nach mehr Beschreibungen und Codebeispielen zu suchen. Ich lese die Beschreibung in der Weise, dass strtok() sich die Adresse des Strings merkt und mit der gemerkten Adresse arbeitet, solange wie als erstes Argument NULL übergeben wird. Ich entnehme das aus dem Hinweis, dass der übergebene Puffer manipuliert wird. Die Funktion setzt nämlich ein Nullbyte an die Stelle des gefundenen Trennzeichens im *Original*-Puffer.
> :-) in zukunft werd ich mit static oder GLOBAL arbeiten!!!
Beides sind Varianten, die du nicht machen solltest!
DIe Methode: Einen Zeiger auf die Speicherfläche in die Funktion
hinein zu übergeben, ist die Methode, die du benutzen solltest.
/* Möglichkeit3: Einen Zeiger als Argument übergeben */
char *test4(char *ptr){
strcpy(ptr, "testwert");
return ptr;
}
Aber wenn du das schon so machst, dann falle nicht in die
gets() - fgets() Falle hinein:
Frage: Was ist falsch an gets() und wurde mit fgets() behoben?
Antwort: Man hat verabsäumt bei gets() einen weiteren Parameter
mit aufzunehmen, der gets darüber informiert wie gross den nun
der Buffer ist, in den es schreiben darf.
Genau wie bei test4()
test4 hat keine Möglichkeit festzustellen, wie gross den die Speicher-
fläche ist, auf die es einen Pointer bekommen hat. Daher kann test4
sich nicht davor schützen, diesen Buffer zu überlaufen.
Richtig wäre:
/* Möglichkeit3: Einen Zeiger als Argument übergeben */
char *test4(char *ptr, size_t BufferSize){
if( BufferSize < 9 )
return NULL;
strcpy(buffer, "testwert");
return ptr;
}
Und auf der Aufrufseite folgerichtig:
int main()
{
char Buffer[4];
if( test4( Buffer, sizeof( Buffer ) ) == NULL )
printf( "Fehler: Buffer zu klein. Machen Sie das Array
groesser\n" );
}
@Stefan am 25.09.2006 14:31 Ja, das sehe ich jetzt nach einem Blick in den K&R auch so. Dann wird wohl nur der Zeiger auf den Original-Puffer statisch gespeichert, nicht aber der Puffer selber in einen statischen Puffer kopiert. Die Rückgabe des Zeigers über strtok() ist im hier diskutierten Fall demnach also genauso sinnlos wie den lokal definierten String direkt zurückzugeben. Grüße mplusplus
@karl heinz buchegger
ok werd ich machen!!!
denn wie heissts so schön:
---> "so LOKAL wie möglich, so GLOBAL wie nötig!!!"
lg und danke
>Raph
@Karl Heinz B.: Frage: Was ist falsch an strcpy() und wurde mit strncpy() behoben? Antwort: ___________(Wissen wir alle) Schönen Tag noch! Klaus
... die Liste ließe sich fortsetzen: strcat / strncat sprintf / snprintf
Beitrag #6958931 wurde von einem Moderator gelöscht.
Beitrag #6958947 wurde von einem Moderator gelöscht.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.