Pointerfunktion, Normale Funktion, gleiche Adresse

desaster0505

Erfahrenes Mitglied
Hallo zusammen!
Über C++ und habe ein Verständnissproblem : Zuerst der Code:

C++:
#include <iostream>
using namespace std;


struct bigone{
	
	int zahl;
	char text[1000];

} 

bo={123, "Eine grosse Struktur"};


void valfunc (bigone wert);
void ptrfunc (const bigone *pointer);
void reffunc (const bigone &referenz);



int main(){

valfunc (bo);
ptrfunc (&bo);
reffunc (bo);

cout <<"\n"<<&bo <<"\n";
}



void valfunc (bigone v){

cout << "\n" << v.zahl << v.text;
cout << " " << &v;

}

void ptrfunc (const bigone *p){

cout << "\n" << p->zahl << p->text;
cout << " " << &p;

}

void reffunc (const bigone &v){

cout << "\n" << v.zahl << v.text;
cout << " " << &v;

}


Die Frage ist:
Wieso verwendet ptrfunc und valfunc die selbe Adresse?
valfunc müsste doch eine Kopie der Struktur verwenden und somit einen anderen Adressbereich.

Kann mir das einer erklären?
 
Hallo,
Hallo zusammen!
Über C++ und habe ein Verständnissproblem : Zuerst der Code:

C++:
#include <iostream>
using namespace std;


struct bigone{
	
	int zahl;
	char text[1000];

} 

bo={123, "Eine grosse Struktur"};


void valfunc (bigone wert);
void ptrfunc (const bigone *pointer);
void reffunc (const bigone &referenz);



int main(){

valfunc (bo);
ptrfunc (&bo);
reffunc (bo);

cout <<"\n"<<&bo <<"\n";
}



void valfunc (bigone v){

cout << "\n" << v.zahl << v.text;
cout << " " << &v;

}

void ptrfunc (const bigone *p){

cout << "\n" << p->zahl << p->text;
cout << " " << &p;

}

void reffunc (const bigone &v){

cout << "\n" << v.zahl << v.text;
cout << " " << &v;

}


Die Frage ist:
Wieso verwendet ptrfunc und valfunc die selbe Adresse?
valfunc müsste doch eine Kopie der Struktur verwenden und somit einen anderen Adressbereich.

Kann mir das einer erklären?

ptrfunc und valfunc verwenden nicht die selbe Adresse, sondern du gibst in deiner Funktion ptrfunc die Adresse des Pointers aus aber nicht den Pointer selber. Und da beide Parameter also sowohl der Parameter v in valfunc als auch der Parameter p in ptrfunc jeweils die erste Variable auf dem Stackframe ist, wird beides mal die selbe Adresse ausgegeben.

Gruß,
RedWing
 
Ah okay. Danke.

Aber kannst du mir das mit dem Stackframe vielleicht noch etwas genauer erklären?

Es wundert mich schon, dass der Pointer auf die Adresse von v zeigt, obwohl ich ja der ptrfunc bo übergebe und das v doch eine Kopie von bo in einem anderen Adressbereich erstellen sollte.

Demnach sollte das doch trotzdem verschiedene Adressen anzeigen?!

Wo is denn da mein Denkfehler?
 
Ah okay. Danke.

Aber kannst du mir das mit dem Stackframe vielleicht noch etwas genauer erklären?

Es wundert mich schon, dass der Pointer auf die Adresse von v zeigt, obwohl ich ja der ptrfunc bo übergebe und das v doch eine Kopie von bo in einem anderen Adressbereich erstellen sollte.

Demnach sollte das doch trotzdem verschiedene Adressen anzeigen?!

So ganz ok scheint es demnach noch nicht zu sein ;). Also pass auf:
Ein Programm besitzt ja für gewöhnlich EINEN Stack der ab einer bestimmten Adresse anfängt. Dieser Stack wird bei Funktionsaufrufen auf - und abgebaut.
Nun wie sieht so ein Stackaufbau im Allgemeinen nach einem Funktionsaufruf (also wenn wir uns in der aufgerufenen Funktion befinden) aus?:
Code:
|---------------------------|
| funktionslokale Parameter | (je nachdem wieviele lokale Parameter in der Funktion deklariert sind)
|---------------------------|
| Framepointer  (FP)          | (4 bytes)
|---------------------------|
| Programcounter  (PC)      | (4 bytes)
|---------------------------|
| aktuelle Parameter        | (je nachdem was für welche und wieviele Paras übergeben werden)
|---------------------------|
Die Begriffe kurz erläutert:
Die aktuellen Parameter: sind die Parameter, die der Funktion übergeben werden. Sie werden bei einem Funktionsaufruf zuerst auf den Stack kopiert damit die Funktion auch darauf zugreifen kann.
Die Restaurierung des Programcounter (der Zeiger der in deiner CPU immer auf den aktuellen Befehl zeigt)(PC) dient dazu damit, wenn die Funktion via return zurückkehrt, der Prozessor weiß wo er mal aufgehört hat um dort dann weiter zu machen.
Der Framepointer wird dazu benutzt um auf Funktionslokale- und aktuelle Parameter zugreifen zu können.
Die Funktionslokalen Parameter sind die Variablen die innerhalb der Funktion deklariert wurden.

Ich hab dir das mal versucht ASCII Art mäßig darzustellen:
Stackaufbau wenn die Abarbeitung des Programmes Zeile 22 erreicht hat:
Code:
 |                                             |  höhere Adressen
|---------------------------------------------|
| in main deklarierte Variablen               |
|---------------------------------------------|
| FP (main)                                   |
|---------------------------------------------|
| PC (auf die Stelle wo main aufgerufen wird) |
|---------------------------------------------|
| argc                                        |
|---------------------------------------------|
| argv                                        |  niedere Adressen
|---------------------------------------------|

jetzt nachdem dein Programm Zeile 33 erreicht hat (also sich in valfunc befindet):
Code:
|                                        |  höhere Adressen
| in valfunc deklarierte Variablen       |
|----------------------------------------|
| FP (für Funktion valfunc)              |
|----------------------------------------|
|  PC (zeigt auf den Befehl in Zeile 15) |
|----------------------------------------|
| bigone v                               | <--- das ist die Adresse &v (*)
|----------------------------------------|
| in main deklarierte Variablen          |
|----------------------------------------|
| FP (main)                              |
|----------------------------------------|
| PC (auf die Stelle vor main)           |
|----------------------------------------|
| argc                                   |
|----------------------------------------|
|argv                                    |  niedere Adressen
|----------------------------------------|

Nachdem valfunc erfolgreich beendet wurde (also mit return zurückgesprungen ist) und der Stack wieder abgebaut wurde sieht der Stack wieder so aus:
Code:
|                                             |  höhere Adressen
|---------------------------------------------|
| in main deklarierte Variablen               |
|---------------------------------------------|
| FP (main)                                   |
|---------------------------------------------|
| PC (auf die Stelle wo main aufgerufen wird) |
|---------------------------------------------|
| argc                                        |
|---------------------------------------------|
| argv                                        |  niedere Adressen
|---------------------------------------------|
dein Programm hat Zeile 40 erreicht (befindet sich also in ptrfunc):
Code:
|                                        |  höhere Adressen
| in ptrfunc deklarierte Variablen       |
|----------------------------------------|
| FP (für Funktion ptrfunc)              |
|----------------------------------------|
|  PC (zeigt auf den Befehl in Zeile 15) |
|----------------------------------------|
| bigone *p                              | <---- das ist die Adresse &p (**)
|----------------------------------------|
| in main deklarierte Variablen          |
|----------------------------------------|
| FP (main)                              |
|----------------------------------------|
| PC (auf die Stelle vor main)           |
|----------------------------------------|
| argc                                   |
|----------------------------------------|
|argv                                    |  niedere Adressen
|----------------------------------------|

Wie man sieht sind (*) und (**) beides mal dieselben Adressen, obwohl es 2 unterschiedliche Objekte sind! v ist nämlich definitiv eine Kopie auf dem Stack von deinem gglobalen bo, und p definitiv ein Pointer auf dein globales bo. Wenn du die Unterschiede zeigen willst musst du anstatt:

C++:
//in valfunc
cout << &v << endl;

//in ptrfunc
cout << &p << endl;

C++:
//in valfunc
cout << &v << endl;

//in ptrfunc
cout << p << endl;
schreiben.

So du wolltest es wissen :).
Siehe dazu auch http://www.tutorials.de/forum/linux-unix/252183-suse-9-0-speicherreservierung-fuer-char-stack.html

HTH,
RedWing
 
Zuletzt bearbeitet:
Ahhhh, deswegen also.

Danke für deine tolle Erklörung, jetzt kann ich mich wieder beruhigen. Das hatte mir keine Ruhe gelassen :-)

Bin wieder ein wenig schlauer.
 
Zurück