Hi, hab hier n C-Problem, bin wohl zu lange aus der Übung... Ich möchte in einer Test-Funktion nen String erzeugen und dann in main auf nem Standard 4x20LCD ausgeben. Etwa so: in test: char * test(void) { char *Xstring = "abc"; char Ystring[3] = "ABC"; return Xstring; // return Ystring; } in main: strcpy (buffer, test()); putsXLCD (buffer); Das ganze läuft auf nem PIC 18 mit MPLAB C18. Es wird nur Speichermüll oder gar nichts angezeigt.
Die Funktion gibt einen Pointer auf lokalen Speicher zurück, also auf einen Speicherbereich, der nach Beenden der Funktion nicht mehr zur Verfügung steht.
Rufus Τ. Firefly schrieb: > Die Funktion gibt einen Pointer auf lokalen Speicher zurück, also auf > einen Speicherbereich, der nach Beenden der Funktion nicht mehr zur > Verfügung steht. Nicht die gepostete Variante.
XString ist eine lokale Variable, die hat nur in der Funktion test Gültigkeit. Mach entweder ein static davor oder zieh' sie aus der Funktion heraus und mach sie global.
radiostar schrieb: > XString ist eine lokale Variable, die hat nur in der Funktion test > Gültigkeit. Mach entweder ein static davor oder zieh' sie aus der > Funktion heraus und mach sie global. Auch falsch. Es wird ja der Pointer selber (also eine Kopie von ihm) zurückgegeben, und nicht etwa ein Pointer auf den Pointer. An der geposteten Version der Funktion gibt es nichts auszusetzen.
Jonas Biensack schrieb: > C kann keinen String als Rückgabewert! Argh, noch einer. Es wird ein Pointer auf einen globalen String zurückgegeben! Das ist absolut kein Problem.
Stefan Ernst schrieb: > Nicht die gepostete Variante. Richtig, gut erkannt. Die nächste Frage ist, wie hier > strcpy (buffer, test()); > putsXLCD (buffer); "buffer" deklariert ist. Dieses völlig irrelevante Detail hat joachim leider unterschlagen.
Stefan Ernst schrieb: > An der > geposteten Version der Funktion gibt es nichts auszusetzen. Und wo wird der String abgelegt? Auf dem Heap. Sobald die Funktion Test abgearbeitet ist, wird dieser Speicher wieder freigegeben und kann durch andere Daten überschrieben werden. Oder täusche ich mich?
Und überhaupt braucht man für 3 Zeichen im String ein Feld mit 4 Elementen (wg. abschließender 0), falls du mal YSTRING verwenden willst.
Oh man nehm doch mal ein Buch zur Hand, so Fragen würd ich mich nicht trauen hier zu stellen, das impliziert immer das man vorher keine Mühe geopfert hat es mal selber auszuprobieren... Trotzdem Gruß Jonas
radiostar schrieb: > Und wo wird der String abgelegt? Auf dem Heap. Nein. Im Konstantenpool. Der Pointer ist am Heap, aber es wird ja eine Kopie des Pointers zurückgegeben. Die gepostete Variante ist genau wie ein return "Test"; zulässig.
radiostar schrieb: > Stefan Ernst schrieb: >> An der >> geposteten Version der Funktion gibt es nichts auszusetzen. > > Und wo wird der String abgelegt? Auf dem Heap. Sobald die Funktion Test > abgearbeitet ist, wird dieser Speicher wieder freigegeben und kann durch > andere Daten überschrieben werden. Oder täusche ich mich? Nein. String-Lieterale sind immer statische global Objekte. Und Xstring ist ein Pointer darauf.
Na gut... Bleibt trotzdem anzumerken, daß Strings nicht die Stärke von C sind. Meine auch nicht :-(
Εrnst B✶ schrieb: > Εrnst B✶ schrieb: >> Der Pointer ist am Heap, > > Am Stack natürlich... Halb im Blindflug abgetippt... Ich habe wohl auch im Blindflug getippt, "Lieterale", peinlich. ;-)
Uuups... was hab ich losgetreten...? 20 min und tausend Leutchen haben geantwortet... danke. Allerdings auch vieele verschiedene Meinungen dazu... Hab eben noch mal in nem Buch geschaut, da steht ebenfalls, daß XString nur im "scope" der lokalen Funktion liegt.Hmmm. Aber wie bekomm ich die jetzt von "innen" nach "aussen"?
Ich würds mal so sagen: Der gepostete Code ist hart an der Kippe. Es gibt eine Reihe von potentiellen Fehlermöglichkeiten bei einer Codeänderung (zb durch Auskommentieren eines anderen Codepfades oder die unbekannte Definition einer Variablen), aber noch ist das Gepostete soweit in Ordnung.
Rufus Τ. Firefly schrieb: > "Am" auch nicht, "auf". Na ja eher "im", da obendrüber noch "char Ystring[3]" liegt :-) (Duck und weg)
Halb im Blindflug == Pirat mit Augenklappe lernt Fliegen ? Ach...gleich ist Feierabend! Gruss Jonas
Joachim ... schrieb: > Allerdings auch vieele verschiedene Meinungen dazu... Stefan, Rufus und Karl Heinz sagen dir das richtige.
Joachim ... schrieb: > Hab eben noch mal in nem Buch geschaut, da steht ebenfalls, daß XString > nur im "scope" der lokalen Funktion liegt.Hmmm. Aber wie bekomm ich die > jetzt von "innen" nach "aussen"? Das Problem ist nicht das XString. Das ist einfach nur eine Pointervariable, deren Inhalt zurückgegeben wird. Das Problem ist das worauf der Pointer zeigt. Solange der auf ein Text-Literal zeigt char* XPointer = "ABC"; ist alles in Ordnung. Das Literal existiert auch nach dem Funktionsaufruf noch. Ist das aber die Adresse eines lokalen Strings char String[] = "ABC"; char* XPointer = String; dann existiert der nach dem Funktionsaufruf nicht mehr. Der zurückgelieferte Adresswert verweist auf ein Objekt im Speicher, welches nicht mehr existiert -> Kaboom.
standart C ist bei mir auch schon ein paar Tage laenger her, aber darf man char * wirklich so initialisieren? ich haette char *XString = mallo( sizeof(char) * 3 ); *XString = "ABC"; return XString; erwartet.
Studiere String-Verarbeitung in C speziell den Abschnitt 4, wenn auch die anderen Abschnitte nicht schaden dürften.
Florian schrieb: > standart C ist bei mir auch schon ein paar Tage laenger her, aber darf > man char * wirklich so initialisieren? Gegenfrage: Warum sollte man das nicht dürfen? Ein String-Literal "ABC" ist ein Objekt, welches für die Dauer des Programmlaufs irgendwo im Speicher rumlungert. Wo genau ist Sache des Compilers/Linkers. Und als solches hat es selbstverständlich auch eine Adresse im Speicher. Das unterscheidet es von zb einem Integer-Literal, welches keine hat, ist aber der Tatsache geschuldet, dass ein String-Literal den Datentyp const char[] hat und Arrays als Literal auf den meisten Architekturen zur Verarbeitung im Speicher liegen müssen, weil es keine Assembler Befehle dafür gibt. Eine Pointervariable auf der anderen Seite, ist eine Variable, welche eine Speicheradresse speichern kann. Passt alles perfekt zusammen und es gibt soweit keinen Einwand. Als Purist könnte man noch einwenden, dass der exakte Datentyp eines String-Literals eigentlich ein const beinhaltet, welches hier implizit weggecastet wird, da allerdings die ISO-C-Väter diesen Fall explizit erlaubt haben, spricht nichts dagegen, die saloppe Formulierung char* PointerX = "ABC"; anstelle des eigentlich richtigen const char* PointerX = "ABC"; zu verwenden. (Solange man sich bewusst ist, dass dieses String-Literal nicht verändert werden darf)
> char *XString = mallo( sizeof(char) * 3 );
Yep, mein Buch zielt in etwa auf die gleiche Lösung. Werd wohl n paar
Basics auffrischen müssen...
1 | char *XString = mallo( sizeof(char) * 3 ); |
2 | *XString = "ABC"; |
3 | |
4 | return XString; |
da sind dann gleich so ziemlich alle Probleme versammelt, in die man als C-Programmierer zum Thema "Strings" tappen kann. Auch dir lege ich den Link von ein paar Posts weiter oben dringenst ans Herz.
Florian schrieb: > standart C ist bei mir auch schon ein paar Tage laenger her, aber darf > man char * wirklich so initialisieren? > ich haette > > char *XString = mallo( sizeof(char) * 3 ); > *XString = "ABC"; > > return XString; > > erwartet. Der Vorschlag ist so falsch, daß man ihn nicht unbedingt verbreiten muß. Joachim ... schrieb: >> char *XString = mallo( sizeof(char) * 3 ); > Yep, mein Buch zielt in etwa auf die gleiche Lösung. Schlechte Idee. > Werd wohl n paar > Basics auffrischen müssen... Bessere Idee.
Ahhh, wenn ich gerade keinen Denkfehler hab liegt der String im DATA-Segment und der Code sollte eigentlich funktionieren... Da ist nix lokal.... Nur der Pointer auf den String ist lokal, macht aber nix, der wird ja beim return "kopiert"... Also sollte das Beispiel eigentlich gehen... Viel eher ist da was im LCD-Teil oder in der Deklaration von buffer falsch....
Uli Trautenberg schrieb: > Ahhh, wenn ich gerade keinen Denkfehler hab liegt der String im > DATA-Segment und der Code sollte eigentlich funktionieren... Jein. In Standard-C: ja. Nur gibt es auch auf dem PIC Compiler, die String-Literale anders behandeln um kostbaren SRAM Speicher zu sparen.
Okay, funktioniert das dann ähnlich wie bei den ATMELs mit Strings im Flash?? Dann wäre aber eigentlich nur die Pointer zuweisung falsch....
>XString ist eine lokale Variable, die hat nur in der Funktion test >Gültigkeit. Mach entweder ein static davor [...] static char Ystring[3] = "ABC"; return Ystring; hat funktioniert. Aber wieso? Ist somit Ystring gewissermaßen an jeder Stelle, in jeder Funktion des Programms sichtbar/aufrufbar?
Joachim ... schrieb: >>XString ist eine lokale Variable, die hat nur in der Funktion test >>Gültigkeit. Mach entweder ein static davor [...] > > static char Ystring[3] = "ABC"; > return Ystring; > hat funktioniert. Aber wieso? Zufall. Die Konstellation war im Moment für dich einfach günstig. Wenn Ystring innerhalb der Funtktion zerstört wird, dann existiert ja der physische Speicher nach wie vor und die Bytes haben auch noch ihren Wert. Nur: Der Speicher gehört niemandem mehr und kann daher jederzeit von etwas anderem überschrieben werden. Genauso wie es Zufall war, dass du am LCD ABC gesehen hast und nicht hinter ABC noch eine Reihe anderer Zeichen :-) Um den String "ABC" zu speichern brauchst du ein Array der Länge 4. Wenn das allerdings das gewünschte aufs LCD zaubert (trotz der beiden Fehler) und bei const char* Xstring = "ABC" nicht, dann hast du den Fall vorliegen, dass String-Literale von deinem Compiler speziell behandlet werden und du die Compilerdoku zu diesem Thema studieren musst.
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.