D
Kanikkl schrieb:
Dieses Programm vertauscht ja die Werte X und Y über die Funktion swap(), indem die HeapStandpunkte von X und Y mit &X und Y& an die swap() weitergegeben. Dort werden aber lediglich die Argumente Vertauscht und nicht die tatsächlichen HeapStandpunkte.
"HeapStandpunkte", tolles Wort ...
Unter einem Heapstandpunkt stelle ich mir die Adresse des Prozessorheaps unter Windows vor, so wie:
#include <windows.h>
#include <iostream>
using std::cout;
int main()
{
cout<<"Der Heap des Programms liegt bei: "<<GetProcessHeap()<<'\n';
return 0;
}
Tatsächlich redet man aber eher von Adressen ...
Zu deinem Problem: Wenn man Zeiger übergibt, muss man sich erst mal klarmachen, was Zeiger überhaupt sind. Zeiger sind ganz normale Variablen. Theoretisch könnte man durch einen Cast jeden Zeiger in eine unsigned __int32 - oder (wenn der Prozess 64 Bit unterstützt) unsigned __int64 -Variable packen - auch Funktionszeiger (habe ich selbst mal gemacht, weil eine Scriptsprache keine Zeiger kannte, aber, wenn die Adressen bekannt sind, Funktionen im Speicher aufrufen konnte). Dadurch untergräbst du allerdings die Typensicherheit des Compilers ...
Zeiger sind Variablen. Ihre Werte können allerdings als Adressen interpretiert werden, und diese Adressen beinhalten unter Umständen wichtige Daten. Worauf ein Zeiger zeigt, weiß er selbst nicht, das tut nur der Compiler, der dafür sorgt, dass man nicht unachtsam den Zeiger ändert. Daher kann ein Zeiger die Adresse eines Objekts beinhalten, welches auf dem Stack liegt - aber auch auf Elemente auf dem Heap.
Parameterübergabe bedeutet, dass das angegebene Objekt kopiert (!) wird und an die aufgerufene Funktion übergeben wird - das passiert bei allen Objekten, die man übergibt, auch bei Zeigern (außer bei Referenzen, glaube ich, aber die verwende ich nie, daher kann ich wenig über DIE sagen).
Folgendes Beispiel:
#include<iostream>
using std::cout;
void CopyPointer(int*Pointer)
{
cout<<"Der Wert des Objektes: "<<*Pointer<<'\n';
cout<<"Der Wert des Zeigers (Adresse des gesicherten Objekts): "<<Pointer<<'\n';
cout<<"Die Adresse des Zeigers: "<<&Pointer<<"\n\n";
}
int main()
{
int First=5,*Second=&First,*Third=new int(10);
cout<<"Der Wert des Objektes: "<<First<<'\n';
cout<<"Der Wert des Zeigers (Adresse des gesicherten Objekts): "<<&First<<"\n\n";
cout<<"Der Wert des Objektes: "<<*Second<<'\n';
cout<<"Der Wert des Zeigers (Adresse des gesicherten Objekts): "<<Second<<'\n';
cout<<"Die Adresse des Zeigers: "<<&Second<<"\n\n";
cout<<"Der Wert des Objektes: "<<*Third<<'\n';
cout<<"Der Wert des Zeigers (Adresse des gesicherten Objekts): "<<Third<<'\n';
cout<<"Die Adresse des Zeigers: "<<&Third<<"\n\n";
CopyPointer(&First);//Adresse der Variablen.
CopyPointer(Second);//Wert des Zeigers, entspricht der Adresse von First.
CopyPointer(Third);//Adresse des Objektes auf dem Heap.
delete Third;//Zeigt auf Speicher auf dem Heap ...
return 0;
}
In beiden Funktionen bleiben die Werte der dereferenzierten Objekte und die Werte der Zeiger gleich, aber die Adressen der Zeiger selbst sind in main und CopyPointer unterschiedliche. Die Objekte, auf die die Zeiger zeigen, bleiben die selben und werden NICHT kopiert, aber die Zeiger selbst werden kopiert. Daher kann man in CopyPointer Pointer alles zuweisen, was man will, auf den Zeiger in main hat das keine Auswirkungen (es sei denn, man manipuliert das Objekt, auf das die Zeiger verweisen, aber selbst dann bleibt der Zeiger auf dieses Objekt fixiert).
Wenn man also die Werte der Zeiger ändern will, sodass auch main davon weiß, braucht man Referenzen auf Zeiger (habe ich zumindest in Erinnerung):
#include<iostream>
using std::cout;
void swap(int*&X,int*&Y)//Oder '&*'? Ich versuche normalerweise, Referenzen so weit wie möglich zu vermeiden ...
{
int*Temp;
std::cout<<"swap - vor Vertauschung: *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"swap - vor Vertauschung: X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"swap - vor Vertauschung: &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
Temp=X;
X=Y;
Y=Temp;
std::cout<<"swap - nach Vertauschung: *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"swap - nach Vertauschung: X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"swap - nach Vertauschung: &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
}
int main()
{
//X und Y brauchen wir auf dem Heap, da wir richtige Zeiger übergeben
//müssen. Funktionen, die Referenzen verwenden, brauchen ein Objekt, auf
//das sie sich mit einer Adresse beziehen können, und ein temporär
//übergebenes Objekt reicht da nicht, wir brauchen Speicher ...
int*X=new int(5),*Y=new int(10);
std::cout<<"main - vor Vertauschung. *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"main - vor Vertauschung. X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"main - vor Vertauschung. &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
//Jetzt übergeben wir eine Referenz auf die Werte der Zeiger ...
//Das ist jetzt schon ziemlich komplexes C++ ...
swap(X,Y);//Übergibt die Adressen als Referenzen. Alles, was wir den Zeigern in swap machen, hat Auswirkungen auf die Zeiger in main ...
std::cout<<"main - nach Vertauschung. *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"main - nach Vertauschung. X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"main - nach Vertauschung. &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
return 0;
}
Ich habe es nicht ausprobiert oder kompiliert, aber es sollte so funktionieren. Vielleicht ein oder zwei Rechtschreibfehler oder das "&" in "&" ändern, aber das Grundgerüst steht.
Hierbei übergibt man die Adressen der Objekte als Referenzen - wenn man diese ändert, ändert sich auch das Original. Aber moment mal, während ich das schreibe, fällt mir ein, dass das Ganze auch mit Zeigern auf Zeiger funktioniert ...
#include<iostream>
using std::cout;
void swap(int**X,int**Y)
{
int*Temp;
//ACHTUNG: X ist ein Zeiger auf unsere Zeiger in main, X in swap gleicht
//also der Adresse von X in main ... ziemlich komplex eben.
std::cout<<"swap - vor Vertauschung: **X: "<<**X<<", **Y: "<<**Y<<'\n';
std::cout<<"swap - vor Vertauschung: *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"swap - vor Vertauschung: &(*X): "<<&(*X)<<", &(*Y): "<<&(*Y)<<"\n\n";
*Temp=*X;
*X=*Y;
*Y=*Temp;
std::cout<<"swap - nach Vertauschung: **X: "<<**X<<", **Y: "<<**Y<<'\n';
std::cout<<"swap - nach Vertauschung: *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"swap - nach Vertauschung: &(*X): "<<&(*X)<<", &(*Y): "<<&(*Y)<<"\n\n";
}
int main()
{
int*X=new int(5),*Y=new int(10);
std::cout<<"main - vor Vertauschung. *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"main - vor Vertauschung. X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"main - vor Vertauschung. &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
//Jetzt übergeben wir die Adressen der Zeiger, also Zeiger auf Zeiger ...
//Das ist noch komplexer, zumindest von der Syntax her ...
swap(&X,&Y);
std::cout<<"main - nach Vertauschung. *X: "<<*X<<", *Y: "<<*Y<<'\n';
std::cout<<"main - nach Vertauschung. X: "<<X<<", Y: "<<Y<<'\n';
std::cout<<"main - nach Vertauschung. &X: "<<&X<<", &Y: "<<&Y<<"\n\n";
return 0;
}
Hierbei werden die Adressen der Zeiger (nicht die Werte) übergeben. Dadurch werden die Adressen der Zeiger nicht kopiert, und Manipulationen betreffen auch das Original. Allerdings wirst du es nicht schaffen, einen Zeiger auf X in main zu erstellen und ihn dann in swap zu manipulieren, dafür brauchst du Zeiger auf Zeiger auf Zeiger ...
Mir egal, welche Version du verwendest, beide sollten funktionieren. Ich hoffe nur, ich konnte helfen ...