C++ Pointer übergeben - Verständnisproblem?

s0nny

Ensign
Registriert
März 2012
Beiträge
185
Hi,
ich experimentiere gerade etwas mit Pointern rum und bin dabei auf ein Problem gestoßen was ich mir gerade einfach nicht erklären kann. Ich will einen binären Baum basteln (unter jeden Knoten folgen 2 weitere Knoten, links kleiner als der jeweilige Knoten, rechts größer) an den ich dann neue Knoten Hinzufügen kann, Knoten löschen kann, Knoten ausgeben kann etc.

Code:
struct tree {                               /*Datentyp für jeden Knoten*/
	int data;                             /*Der Wert des Knotens*/
	struct tree *pLeft;              /*Knoten eine Ebene tiefer links (kleiner)*/
	struct tree *pRight;            /*Knoten eine Ebene tiefer rechts (größer)*/
	struct tree *pRoot;             /*der Knoten über dem aktuellen Knoten*/
};

typedef struct tree tree_t;

static tree_t *first;

void init_tree(){
	first = NULL;
	if(first == NULL)
		printf("SUCCESS! first wurde NULL gesetzt\n\n");
	else
		printf("ERROR!first wurde nicht NULL gesetzt\n\n");
}

void addDataToTree(int data){
	addDataToTree(first, data);
}
void addDataToTree(tree_t *node, int data){
	printf("\nnode: %p first: %p\n", &node, &first);  /*Müsste nun nicht 2x exakt die gleiche Adresse angezeigt werden?*/

	/*hier folgt dann Code...*/
}

int main(void){
     init_tree();
     addDataToTree(5);
}

Der Code der darin steht ist denk ich erstmal irrelevant, weil nach meiner Auffassung schon da eine diskrepanz entsteht.
Ich deklariere also einen Zeiger first der auf den Typ tree_t zeigt und initialisiere ihn mit NULL. first zeigt nun also an eine Stelle im Speicher, an der nichts (NULL) steht.
Wenn ich nun aus der main die Funktion addDataToTree(int data) aufrufe, ruft diese die überladene Funktion addDataToTree(tree_t *node, int data) auf und übergibt ihr zum einen den Integerwert von data, und zum Anderen, den Pointer first, also die Adresse im Speicher wo der Baum "beginnen" soll.
Nach meiner Auffassung her, müssten first und node nun auf die gleiche Adresse zeigen oder? Das tun sie aber nicht! Beide zeigen auf eine andere Adresse (via printf ermittelt)
Ich habe auch schon probiert, die überladene Funktion statt mit addDataToTree(first, data) mit addDataToTree(&first, data) aufzurufen, aber da meckert VisualStudio rum ("IntelliSense: Keine Instanz von Überladene Funktion "addDataToTree" stimmt mit der Argumentliste überein. Argumenttypen sind: (tree_t **, int)")
Habe ich da einen Denkfehler? ODer ist es einfach schon zu spät? :rolleyes:

Grüße
 
Da handelt es sich wohl wirklich um ein klassisches Verständnisproblem, denn

first zeigt nun also an eine Stelle im Speicher, an der nichts (NULL) steht.
Nein, first ist NULL, d.h. es zeigt auf die Speicherstelle 0x0000000000000000. Da steht erst einmal gar nichts, denn beim Dereferenzieren gibt es einen Absturz.

/*Müsste nun nicht 2x exakt die gleiche Adresse angezeigt werden?*/
Nein, weil du die Addressen der Pointer an printf übergibst, also quasi die Addressen, an denen die Addressen gespeichert sind - einmal ist das die Addresse von first, das irgendwo auf dem Heap liegt, und einmal die von node, das auf dem Stack liegt. Oder anders gesagt, du gibst Zeiger von dem Typen tree_t** aus.
Lösung: &-Operator weglassen. Denn die Zeiger enthalten ja selbst schon die Addresse.


Geht es jetzt eigentlich um C++ (Thread-Präfix) oder um C? Der Code da ist jedenfalls reinrassiges C.
 
Du dereferenzierst den Pointer node auf Zeile 24. Entweder einfach nur (richtig) node nutzen oder korrekt, aber sinnloserweise &(*node) (die Adresse erst referenzieren um den Inhalt zu bekommen und dann dereferenzieren, um die Adresse zu bekommen) verwenden. Du bekommst bereits eine Adresse über die Funktion und willst dann also die Adresse der Adresse?! Das klappt natürlich nicht.
 
Alles klar, jetzt machts klick! Danke für die schnelle Hilfe, dadurch konnte ich jetzt den Fehler im Code finden und die Funktion läuft soweit :-)

@VikingGe: Theoretisch lerne ich C. Allerdings verwende ich in VS den C++ Compiler und einige Funktionen die es soweit ich weiß erst in C++ gibt. Ich nutze zum Beispiel new statt malloc und das überladen der Funktionen ist in C soweit ich weiß auch noch nicht möglich gewesen. Antwort also, es handelt sich um C++ :-)
 
und das überladen der Funktionen ist in C soweit ich weiß auch noch nicht möglich gewesen
Du hast Recht, ja.

Allerdings ist das dann doch ein Mischmasch, den man sich besser niemals angewöhnt - wenn du ohnehin eher C schreibst, dann auch lieber richtiges C mit malloc/free und Initialisierungen von Hand, und wenn du wirklich C++ schreiben willst, dann am besten auch richtig (i.e. ohne Typedefs, Nutzen von Konstruktoren/Destruktoren etc., new/delete, ...) - es sind zwei verschiedene Sprachen, das sollte man trotz der teilweise Kompatibilität nicht vergessen.
 
s0nny schrieb:
Ich deklariere also einen Zeiger first der auf den Typ tree_t zeigt und initialisiere ihn mit NULL. first zeigt nun also an eine Stelle im Speicher, an der nichts (NULL) steht.
Nein, first selbst ist NULL und zeigt damit auf eine RAM Adresse die unglütig ist, jeder Zugriff darauf ist ein Fehler.

s0nny schrieb:
Wenn ich nun aus der main die Funktion addDataToTree(int data) aufrufe, ruft diese die überladene Funktion addDataToTree(tree_t *node, int data) auf und übergibt ihr zum einen den Integerwert von data, und zum Anderen, den Pointer first, also die Adresse im Speicher wo der Baum "beginnen" soll.
Nein, da diese Adresse noch gar nicht existiert, es fehlt ein first = new struct tree damit überhaupt mal ein Speicherbereich für die Struktur angelegt wird.
s0nny schrieb:
Nach meiner Auffassung her, müssten first und node nun auf die gleiche Adresse zeigen oder? Das tun sie aber nicht! Beide zeigen auf eine andere Adresse (via printf ermittelt)
Nein, &node, &first sind die Adressen der Pointer die jeweils auf den gleichen Wert (NULL) zeigen aber der eine Pointer ist eine globale Variable, der andere eine lokale und daher liegen sie auch in unterschiedlichen Speicherbereichen.
s0nny schrieb:
Ich habe auch schon probiert, die überladene Funktion statt mit addDataToTree(first, data) mit addDataToTree(&first, data) aufzurufen, aber da meckert VisualStudio rum ("IntelliSense: Keine Instanz von Überladene Funktion "addDataToTree" stimmt mit der Argumentliste überein. Argumenttypen sind: (tree_t **, int)")
Dann musst void addDataToTree nicht als (tree_t *node, int data) sondern als void addDataToTree(tree_t **node, int data) definiert sein, dann sollte es gehen. Du hast noch viel Über Pointer und Speicherverwaltung zu lernen!

Auch würde ich bei C++ statt eines Struktes eine Klasse machen und den Constructor und den Destuktor so bauen, dass die Werte gleich korrekt initialisiert werden, so hängen pLeft, pRight und pRoot in der Luft.
 
Zuletzt bearbeitet:
Zurück
Oben