Problem mit zeigern!



  • Ich denke wir sind hier:

    int func3(int& number, int& number2)
    {
        number=130;
        number2=240;
        return number, number2;
    }
    

    Das mit fun1 hatten wir gestern schon geklärt 🙂



  • Wie schon mehrfach gesagt, das ist Quatsch. Du kannst nicht mehrere Werte zurückgeben. Geht nicht. Im Ernst. Du kannst einen Zeiger auf ein Array zurückgeben, oder du kappselst deine Werte in einer Struktur.



  • Du kannst (egal in welcher Deiner Funktionen) so nicht zwei Werte mit return zurückgeben. Dennoch ist der Ausdruck

    return number1, number2;
    

    legal. Zurückgegeben wird aber nur number2. Siehe Komma-Operator.

    Funktionen dieser Art können nur einen Wert zurückgeben. Dabei ist es egal wieviele Parameter sie bekommt und ob das Zeiger oder Referenzen sind. Als Rückgabewert bezeichnet man im Allgemeinen den von return zurückgegebenen Wert

    int func()  // diese Funktion gibt genau einen int zurück
    {
       return 120;
    }
    
    // Aufruf
    int a = func();
    cout << a << "\n";
    

    Wenn Du tatsächlich zwei Werte zurückgeben möchtest, kannst zu z.B. std::pair<int, int> verwenden oder Dir einen Struct basteln. Das muss aber zum Rückgabewert der Funktion passen:

    std::pair<int,int> func()
    {
       return std::pair<int, int>( 3, 4);
    }
    

    Deine func3 ändert Werte per Referenz, d.h. Du übergibst Ihr Variablen und die Funktion schreibt (möglicherweise) das Ergebnis in diese Variablen.

    void func3(int& number, int& number2) // diese Funktion gibt gar nichts zurück, darf aber die ihr übergebenen Variablen ändern
    {
        number=130;
        number2=240;
    }
    
    // Aufruf
    int a = 1;
    int b = 2;
    cout << a << ", " << b << "\n";
    func3( a, b);
    cout << a << ", " << b << "\n";
    

    Für Deine func4 kannst Du folgendes machen:

    void func4( int** number1, int** number2)
    {
       *number1 = new int;
       **number1 = 130;
       *number2 = new int;
       **number2 = 240;
    }
    
    // Aufruf
    int *a = 0;
    int *b = 0;
    // *a darfst Du noch nicht schreiben, da a noch auf keinen gültigen Speicher zeigt
    func4( a, b);
    cout << *a << ", " << *b << endl;
    delete a;  // Speicher wieder freigeben
    delete b;  // Speicher wieder freigeben
    

    Sowas wie func4 versucht man aber zu vermeiden, da der Aufrufer den Speicher wiederfreigeben muss. Das wird aber oft vergessen und schon hat man ein Speicherleck.

    Wenn Du eine Funktion hast:

    int a = berechneWas(1, 2);
    

    weisst Du, dass a danach einen Wert hat. Du kannst Dich darauf verlassen, ohne den Code der Funktion zu lesen (Exceptions sind eine Ausnahme, dann wird aber auch Dein Code nicht weiter ausgeführt).

    Bei

    int a = 0; 
    int b = 0;
    berechneWas( a, b);
    

    weisst Du nicht, ob a und b durch den Aufruf verändert werden. Selbst wenn die Werte per Referenz übergeben werden (also wie in func3), muss die Funktion sie nicht ändern. Es ist völlig legal, einfach nichts zu tun. Du kannst Dich also nicht darauf verlassen, dass a und b verändert werden.

    Deswegen versucht man Änderungen über Referenzen nur dann zu machen, wenn es nicht anders geht (z.B. um mehr als einen Wert zu ändern). Und wenn man Referenzen nicht ändern will, dann sollte man das Schlüsselwort const zu benutzen (bzw. bei PODs (also int, short und co) lässt man die Referenz weg), um dem Aufrufer zu sagen: Da wird nichts verändert



  • Okay also func4 werde ich mal umschreiben. und auch func3 und nochmals danke für die hilfe 🙂

    Okay hier mal der fast funktionierende code:

    #include<iostream>
    using namespace std;
    /*Zeiger test*/
    void func1(int, int);
    int* func2(int*, int*);
    int func3(int&, int&);
    void func4(int*, int*);
    
    int main()
    {
    	int zahl;
    	int zahl2;
    	int* pzahl;
    	int* pzahl2;
    	pzahl=&zahl;
    	pzahl2=&zahl2;
    
    	cout<<"Geben sie 2 zahlen ein"<<endl;
            cin>>zahl;
    	cin>>zahl2;
    
    	cout<<"Geben sie nun die zeiger art ein die sie haben wohlen"<<endl
    		<<"Hier die Uebersicht(1=Werteuebergabe, 2=Zeigerwerteuebergabe, "<<endl
    		<<"3=Uebergabe per Reference, 4=heapspeicher nutzung"<<endl;
    
    	int choice;
    	cin>>choice;
    
    	switch(choice)
    	{
    	case 1:
    		func1(zahl, zahl2);
    			cout<<zahl<<endl
    				<<zahl2<<endl;
    		break;
    	case 2:
    		func2(&zahl, &zahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 3:
    		func3(zahl, zahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 4:
    		int *zahl;
    		int *zahl2;
    		func4(zahl, zahl2);
    		cout<<*zahl<<endl
    			<<*zahl2<<endl;
    		delete *zahl;
    		delete *zahl2;
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    		break;
    	default:
    		cout<<"Eingabe Ungueltig"<<endl;
    			break;
    	}
    	system("PAUSE");
    }
    
    void func1(int number, int number2)
    {
    	number=100;
    	number2=200;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    int* func2(int* pnumber, int* pnumber2)
    {
    	*pnumber=110;
    	*pnumber2=220;
    	return pnumber, pnumber2;
    }
    
    int func3(int& number, int& number2)
    {
    	number=130;
    	number2=240;
    	return number, number2;
    }
    
    void func4(int** number, int** number2)
    {
    	*number=new int;
    	*number2=new int;
    	**number=140;
    	**number=260;
    	cout<<**number<<endl
    		<<**number2<<endl;
    }
    


  • Sorry, aber dein

    return number, number2
    

    ist immernoch Nonsense. Wie schon viele meiner Vorredner gesagt haben, kannst du nur einen einzigen Wert zurückgeben.
    Lass dir mal erklären, was deine Funktionen genau machen:

    - func1:

    Beim Aufruf dieser Funktion wird auf dem Stack Platz für zwei int-Variablen reserviert, nämlich number und number2. Diese beiden Speicherplätze werden mit den Werten belegt, die du der Funktion übergibst. Danach werden diese beiden Speicherplätze sofort geändert, das hat aber keine Wirkung auf die Variablen, die du beim Funktionsaufruf übergeben hast. Diese beiden Variablen wurden nämlich in die neuen Speicherpläze kopiert; eine Veränderung der Kopien verändert nicht die Originale. Du könntest also func1 genausogut ohne Parameter definieren.

    - func2:

    Du übergibst der Funktion zwei Zeiger, also Verweise auf Speicherbereiche, wo jeweils ein int drin ist. Danach veränderst du dei Speicherbereiche (was auch Auswirkungen außerhalb der Funktion hat).
    Die dann folgende return-Anweisung erwartet ein einziges Argument. Dieses Argument ist in deinem Falle (pnumber, pnumber2). Es enthält den Komma-Operator, der von links nach rechts ausgewertet wird, bevor das Ergebnis der return-Anweisung übergeben wird. Der Rückgabewer des Kommaoperators ist das ergebnis der Auswertung des rechten Arguments. Die Auswertung läuft also wie folgt:
    - Werte pnumber aus -> Auswirkungen: keine. Ergebnis: Wert von pnumber
    - Werte pnumber2 aus -> Auswirkungen: keine. Ergebnis: Wert von pnumber2
    - gebe das Ergebnis des zweiten Arguments zurück: Wert von pnumber2
    Fazit: die returnanweisung gibt nur den Wert von pnumber2 zurück, das pnumber davor hat keinerlei Auswirkungen und wird vermutlich vom Compiler wegoptimiert.

    - func3:

    Das gleiche Spiel wie func2, nur dass diesmal Referenzen statt Zeigern benutzt werden. Der Unterschied ist, dass man bei Referenzen nicht immer dereferenzieren muss (also kein * voranstellen), und dass Referenzen einmal an eine Variable gebunden werden und danach nicht mehr verändert werden können. Man könnte auch sagen, sie sind eine Art idiotensichere Zeiger. (Ich weiß, sie sind noch mehr und teils auch weniger als das...)
    Die Auswirkungen sind wie bei func2: Da du nur mit Referenzen auf Zahlen arbeitest, die an die Funktion übergeben werden, wird kein extra Speicher reserviert und die Zahlen ändern sich auch (anders als im ersten beispiel, wo du nur die Kopien veränderst). Bei der return-Anweisung wieder der gleiche Mist wie bei func2: du gibst im Endeffekt nur den Wert von number2 zurück.

    - func 4

    Du übergibst der Funktion einen zeiger auf einen zeiger auf Ints. Sofort danach belegst du den Zeiger, auf den der Zeiger zeigt (toll, ne?) per "new" mit einem neuen Wert. Was aber, wenn der zeiger vorher auf einen anderen, dynamisch allokierten Bereich im speicher gezeigt hat? Dann verwaist dieser Bereich, weil niemand mehr auf ihn zeigt. Tolles Speicherleck... (ein delete *number hilft übrigens nicht, könnte ja sein, dass der Zeiger nicht auf dynamischen speicher sondern auf den heap zeigt, dann kriegst du einen Laufzeitfehler)
    Als nächstes veränderst du den neu geschaffenen Speicher, gibst die Werte aus und kehrst zum Aufrufer zurück. der weiß normalerweise aber nicht, dass du neuen Speicher geholt hast, und deshalb wird er den Speicher auch nicht wieder freigeben. Speicherleck Nummer 2...

    Du solltest dir echt nochmal ein wenig Literatur zum Thema Arbeit mit Zeigern und vor allem zum Thema Funktionen, Parameterübergabe und Rückgabewerte durchlesen. Es gibt hunderte von guten und weniger guten, ausführlicheren und knapperen, leicht verständlichen und weniger einfachen einführenden Büchern zu den Themen...



  • Sorry gab nur vergesen es zulöschen 🙂



  • Hier mal ein code update mit func4:

    #include<iostream>
    using namespace std;
    /*Zeiger test*/
    void func1(int, int);
    int* func2(int*, int*);
    void func3(int&, int&);
    int* func4();
    
    int main()
    {
    	int zahl;
    	int zahl2;
    	int* pzahl;
    	int* pzahl2;
    	pzahl=&zahl;
    	pzahl2=&zahl2;
    
    	cout<<"Geben sie 2 zahlen ein"<<endl;
    	cin>>zahl;
    	cin>>zahl2;
    
    	cout<<"Geben sie nun die zeiger art ein die sie haben wohlen"<<endl
    		<<"Hier die Uebersicht(1=Werteuebergabe, 2=Zeigerwerteuebergabe, "<<endl
    		<<"3=Uebergabe per Reference, 4=heapspeicher nutzung"<<endl;
    
    	int choice;
    	cin>>choice;
    
    	switch(choice)
    	{
    	case 1:
    		func1(zahl, zahl2);
    			cout<<zahl<<endl
    				<<zahl2<<endl;
    		break;
    	case 2:
    		func2(pzahl, pzahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 3:
    		func3(zahl, zahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 4:
    		int* pzahl2;
    		pzahl2=func4();
    		delete pzahl2;
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    		break;
    	default:
    		cout<<"Eingabe Ungueltig"<<endl;
    			break;
    	}
    	system("PAUSE");
    }
    
    void func1(int number, int number2)
    {
    	number=100;
    	number2=200;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    int* func2(int* pnumber, int* pnumber2)
    {
    	*pnumber=110;
    	*pnumber2=220;
    	return pnumber, pnumber2;
    }
    
    void func3(int& number, int& number2)
    {
    	number=130;
    	number2=240;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    int* func4()
    {
    	int* pnumber=new int;
    	*pnumber=10;
    	cout<<*pnumber<<endl;
    	return pnumber;
    }
    

    Wenn noch fehler drin sind bitte melden 🙂



  • Deine func2() soll immer noch 2 Werte zurückgeben, das geht nicht und wird auch in Zukunft mit C++ nicht gehen. Eine Funktion gibt immer nur maximal!!!! 1 Element ihres Rückgabetyps zurück. Natürlich ist es sinnlos einen Rückgabetyp (ungleich void) zu vereinbaren und dann nicht zu nutzen. Auch wenn der Compiler solche Konstrukte mit dem Komma-Operator vielleicht zulässt wird die Funktion so wie sie dort steht nicht das zurückgeben was du von ihr eigentlich zurückgeben lassen willst.



  • Danke für die info 🙂 hab ich wieder mal gepennt 🙂 bin ja noch am anfang und lehrne ja noch welche sachen man meiden muss 🙂



  • Mal ne dumme Frage: Was macht der Komma Operator?
    Ich weiß das man nur ein Wert zurückgeben kann, aber mir ist bis jetzt schleihaft warum sich so ein Qwatsch kompelieren lässt.



  • Wie pumuckl schon sagte:

    pumuckl schrieb:

    Es enthält den Komma-Operator, der von links nach rechts ausgewertet wird, bevor das Ergebnis der return-Anweisung übergeben wird.
    ...
    Fazit: die returnanweisung gibt nur den Wert von pnumber2 zurück, das pnumber davor hat keinerlei Auswirkungen und wird vermutlich vom Compiler wegoptimiert.



  • lol



  • Okay versuch nummer 103 🙂 :

    #include<iostream>
    using namespace std;
    /*Zeiger test*/
    void func1(int, int);
    void func2(int*, int*);
    void func3(int&, int&);
    int* func4();
    
    int main()
    {
    	int zahl;
    	int zahl2;
    	int* pzahl;
    	int* pzahl2;
    	pzahl=&zahl;
    	pzahl2=&zahl2;
    
    	cout<<"Geben sie 2 zahlen ein"<<endl;
    	cin>>zahl;
    	cin>>zahl2;
    
    	cout<<"Geben sie nun die zeiger art ein die sie haben wohlen"<<endl
    		<<"Hier die Uebersicht(1=Werteuebergabe, 2=Zeigerwerteuebergabe, "<<endl
    		<<"3=Uebergabe per Reference, 4=heapspeicher nutzung"<<endl;
    
    	int choice;
    	cin>>choice;
    
    	switch(choice)
    	{
    	case 1:
    		func1(zahl, zahl2);
    			cout<<zahl<<endl
    				<<zahl2<<endl;
    		break;
    	case 2:
    		func2(pzahl, pzahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 3:
    		func3(zahl, zahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 4:
    		int* pzahl2;//deklaration des zeigers auf int zahl2
    		pzahl2=func4();//zeiger an func 4 übergeben
    		delete pzahl2;//speicher löschen
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    		break;
    	default:
    		cout<<"Eingabe Ungueltig"<<endl;
    			break;
    	}
    	system("PAUSE");
    }
    
    void func1(int number, int number2)
    {
    	number=100;
    	number2=200;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    void func2(int* pnumber, int* pnumber2)
    {
    	*pnumber=110;
    	*pnumber2=220;
    }
    
    void func3(int& number, int& number2)
    {
    	number=130;
    	number2=240;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    int* func4()
    {
    	int* pnumber=new int;//speicherplatz holen
    	*pnumber=10;//speicher wert zuweisen
    	cout<<*pnumber<<endl;//wert ausgeben
    	return pnumber;//zeiger zurückgeben 
    }
    


  • Er hats endlich kapiert 😃
    Nix für ungut, aber zusehen, dass endlich kein return nummer1, mummer2 in deinem Code steht ist echt schön.



  • Jo trotz meines Realschulabschlusses(@WIP) stand ich ne weile auf der leitung 🙂
    Ferien halt 😛



  • MartinMilbret schrieb:

    trotz meines Realschulabschlusses(@WIP) stand ich ne weile auf der leitung 🙂

    lol?



  • hätte ich anders schreiben sollen. Korektur:
    Trotz meines vorhabens einen erweiterten Realschulabschluss zu erreichen stand ich dur die ferien extrem auf der leitung 😛

    EDIT: Hier mal das programm mit header datei(mit header daten bin ich noch am anfang :P):
    header:

    int zahl;
    int zahl2;
    int* pzahl;
    int* pzahl2;
    int choice;
    
    void func1(int, int);
    void func2(int*, int*);
    void func3(int&, int&);
    int* func4();
    

    cpp datei:

    #include<iostream>
    #include"Crap.h"
    using namespace std;
    /*Zeiger test*/
    
    int main()
    {
    	pzahl=&zahl;
    	pzahl2=&zahl2;
    	cout<<"Geben sie 2 zahlen ein"<<endl;
    	cin>>zahl;
    	cin>>zahl2;
    
    	cout<<"Geben sie nun die zeiger art ein die sie haben wohlen"<<endl
    		<<"Hier die Uebersicht(1=Werteuebergabe, 2=Zeigerwerteuebergabe, "<<endl
    		<<"3=Uebergabe per Reference, 4=heapspeicher nutzung"<<endl;
    	cin>>choice;
    
    	switch(choice)
    	{
    	case 1:
    		func1(zahl, zahl2);
    			cout<<zahl<<endl
    				<<zahl2<<endl;
    		break;
    	case 2:
    		func2(pzahl, pzahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 3:
    		func3(zahl, zahl2);
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    			break;
    	case 4:
    		int* pzahl2;//deklaration des zeigers auf int zahl2
    		pzahl2=func4();//zeiger an func 4 übergeben
    		delete pzahl2;//speicher löschen
    		cout<<zahl<<endl
    			<<zahl2<<endl;
    		break;
    	default:
    		cout<<"Eingabe Ungueltig"<<endl;
    			break;
    	}
    	system("PAUSE");
    }
    
    void func1(int number, int number2)
    {
    	number=100;
    	number2=200;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    void func2(int* pnumber, int* pnumber2)
    {
    	*pnumber=110;
    	*pnumber2=220;
    }
    
    void func3(int& number, int& number2)
    {
    	number=130;
    	number2=240;
    	cout<<number<<endl
    		<<number2<<endl;
    }
    
    int* func4()
    {
    	int* pnumber=new int;//speicherplatz holen
    	*pnumber=10;//speicher wert zuweisen
    	cout<<*pnumber<<endl;//wert ausgeben
    	return pnumber;//zeiger zurückgeben 
    }
    

    Falls noch mehr in die header kann bitte antworten 🙂



  • Okay nochmal ein anderes zeiger problem:

    #include<iostream>
    using namespace std;
    char* wahl(int);
    
    int main()
    {
    	int months;
    	cout<<"Welchen monat wollen sie haben(1-12)\n";
    	cin>>months;
    	wahl(months);
            cout<<months<<"\n";
    	system("PAUSE");
    }
    
    char* wahl(int monat)
    {
    	if(monat<1||monat>12)
    	{
    		return "ungültig";
    	}
    	char* pszmonate[]={"ungültig", "Januar", "Februar", "Maerz", 
    						"April", "Mai", "Juni", "Juli",
    						"August", "September", "Oktober", 
    						"November", "Dezember"}; 
    	cout<<monat<<"\n";
    	return pszmonate[monat];
    }
    

    Das Programm ansich läuft aber er soll ja die namen der monate zurückgeben und dann ausgeben aber er gibt nur die zahl die eingegeben wurde aus 😢



  • Dann mußt du auch den Rückgabewert von wahl() weiterverarbeiten (in der Funktion gibst du wirklich nur die Zahl aus und schickst den Monatsnamen per return an's Hauptprogramm - nur das vergisst diesen Wert sofort wieder).

    btw, ich weiß nicht, ob der Wert noch gültig ist, wenn du aus der Funktion rauskommst - kann genausogut sein, daß sich inzwischen der Stack aufgräumt hat und der zurückgegebene Pointer auf einen Haufen Datenmüll zeigt.



  • also sollte ich die ausgabe wohl mal auf die funktion eingrenzen oder?
    aber wenn ich das mache gibt er auch nur die zahl aus 😞


Anmelden zum Antworten