C-Problem Funktionsaufruf

OP #2581509
Lesenswert?

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.
#2581525
Lesenswert?

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.
#2581544
Lesenswert?

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.
OP #2581567
Lesenswert?

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"?
#2581568
Lesenswert?

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.
#2581594
Lesenswert?

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.
Gast #2581595
Lesenswert?

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.
#2581606
Lesenswert?

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)
#2581616
Lesenswert?

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.
#2581618
Lesenswert?

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.
#2581628
Lesenswert?

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....
OP #2581730
Lesenswert?

>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?
#2581892
Lesenswert?

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.

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