Forum: PC-Programmierung Pointer nach Rückkehr aus Funktion null?


von c-noob (Gast)


Lesenswert?

Hallo,

bin grade etwas verwirrt:

habe folgende funktion:
1
void init(Objekt1 * obj);
2
{
3
    // irgendwelcher code der ein paar parameter setzt
4
    obj = new Objekt( irgendwelche Parameter );
5
}

wenn ich jetzt
1
Objekt *obj = 0;
2
init(Objekt * obj);
ausführe und in die Funktion init reindebugge wird das Objekt alloziert 
und der Pointer zeigt drauf, soweit alles klar.
Nach der Rückkehr aus der Funktion ist der Pointer aber wieder Null.

Wieso?

von (prx) A. K. (prx)


Lesenswert?

Das wird kaum
  init(Objekt * obj);
gewesen sein. Sondern
  init(obj);

C übergibt als Parameter den Wert, keine Referenz auf die Variable. 
Daher kann in der aufgerufenen Funktion der Parameter beliebig geändert 
werden, ohne aber in der aufrufenden Funktion etwas zu ändern.

von Sebastian V. (sebi_s)


Lesenswert?

Weil beim Aufruf eine Kopie deines Pointers erzeugt wird. Der Pointer an 
der Aufrufstelle bleibt vom Funktionsaufruf unverändert. Das ist wie:
1
void foo(int i) {
2
    i = 5;
3
}
4
5
int x = 2;
6
foo(x);
7
// x ist immer noch 2

Entweder Pointer auf Pointer benutzen oder Pointer als Rückgabewert. 
Oder im Idealfall gar keine rohen Pointer benutzen wenn man schon C++ 
nutzt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Weil auch Zeiger per Wert übergeben werden.  Also entweder &obj 
übergeben oder eine Referenz darauf — nach Anpassung des Interface etc.

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Wenn du
  void init(Objekt1 & obj) { ... }
draus machst, sieht es besser aus. Denn dann wird nicht der Wert 
übergeben, sondern eine Referenz.

NB: Auch hier ist in deinem Beispiel ein Syntaxfehler.

von Andreas S. (Firma: Schweigstill IT) (schweigstill) Benutzerseite


Lesenswert?

Gegenfrage: Warum sollte er einen anderen Wert haben?

Der Wert des Pointers wird an die Funktion übergeben, d.h. Call by 
value. Für die von Dir gewünschte Funktionalität musst Du also einen 
Zeiger auf Deinen Zeiger übergeben, d.h.:
1
void init(Objekt1 ** obj)
2
{
3
    // irgendwelcher code der ein paar parameter setzt
4
    *obj = new Objekt( irgendwelche Parameter );
5
}
6
7
...
8
9
Objekt *obj = 0;
10
init(&obj);

Falls Du mit C++ arbeiten solltest, könntest Du auch mit Referenzen 
statt Pointern arbeiten (, wobei hinter den Referenzen aber eigentlich 
auch Pointer stecken).

von c-noob (Gast)


Lesenswert?

@  A. K.

Entschulding, der Aufruf ist natürlich
1
init(obj);

ok stimmt, habs glaube ich verstanden, der Pointer wird ja geändert.

so würde es dann funktionieren oder?
1
void init(Objekt1 ** obj);
2
{
3
    // irgendwelcher code der ein paar parameter setzt
4
    *obj = new Objekt( irgendwelche Parameter );
5
}

mit dem Aufruf:
1
init(&obj);

von Theor (Gast)


Lesenswert?

Das hat mit dem Geltungsbereich (Scope) von Parametern zu tun.

Es gibt bei Deinem Beispiel die Besonderheit, dass der Name der 
Variablen im globalen Geltungsbereich gleich dem Namen im 
Geltungsbereich der Funktion ist. Das hat hier aber keinerlei Bedeutung.

Zur Klarheit hier eine für Dein Problem äquivalente Variable und 
Funktion:
1
int * a = NULL;    // Der Standardwert für Zeiger die auf nichts zeigen (nicht 0!=
2
3
void function (int * b) {
4
   b = malloc (sizeof(int));
5
}
6
7
...
8
9
function (a);

Auch wenn die Funktion gleich aussieht, tritt hier das selbe Problem 
auf, das wie folgt formuliert werden kann:

Alle Werte innerhalb einer Funktion haben nur Geltung innerhalb der 
Funktion.

Du würdest ja (vermutlich) auch nicht erwarten, das folgender Code
1
int a = 0;
2
3
void function (int b) {
4
   b = 7;
5
}
6
7
function (a);
den Wert von a in der Weise verändert, dass nach dem Ende der Funktion 
immer noch a = 7 gilt.

Analoges gilt auch für Zeiger.

Ein Zeiger ist an sich nur ein Wert, für den die Regeln des 
Geltungsbereichs genauso gelten, wie für andere Variablen. Das der 
Zeiger auf eine Speicherstelle zeigt ist an sich erstmal nichts 
besonderes.

Zwar wird in der Funktion oben ein Speicher für b alloziiert, aber das 
wirkt sich nicht auf a aus, obwohl es als Parameter übergeben wurde.

Um einen Zeiger, der innerhalb einer Funktion alloziiert werden soll, im 
Geltungsbereich der aufrufenden Funktion (z.B. main) zugreifen zu 
können, muss der Funktion eine Zeiger, auf einen Zeiger übergeben 
werden, nicht nur ein Zeiger.
1
int * a = NULL;
2
3
void function (int * * b) {
4
   *b = malloc(sizeof(int));
5
}
6
7
function (& a);

In neuerem C gibt es dazu noch einen anderen Operator. Aber dazu guckst 
Du vielleicht erstmal in einem C-Buch nach Zeigern auf Zeiger; und dann 
nach "Referenzen".

von PittyJ (Gast)


Lesenswert?

Ich benutze immer eine Referenz, wenn ich in der Funktion den Parameter 
verändert haben möchte.

Also so etwas wie

int * a = NULL;

void function (int * & b)
{
   b = malloc(sizeof(int));
}

function ( a);


Das erspart 'Stern' und 'Und'.

Statt gcc einfach g++ eintippen, und schon mag der Compiler das.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Um ein Problem in Programmiersprache X zu lösen, nehme ich immer 
Programmiersprache Y.

Ist das hilfreich?

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
Noch kein Account? Hier anmelden.