Zeigerverwirrungen

Programmieren in C++
Antworten
Autor
Nachricht
Benutzeravatar
darthcookie
6 Bit
Beiträge: 103
Registriert: So Aug 02, 2009 16:48

Zeigerverwirrungen

#1 Beitrag von darthcookie » Di Jun 01, 2010 12:42

Hallo Leute, ich lern gerade C++ und verzweifle an den Zeigern. Ich hab mir eine Klasse geschrieben, die einen Dezimalbruch speichern soll (und möglichst viele Zeiger benutzt, ich wills ja lernen^^) und mir ein Programm zum testen geschrieben. Es müsste eigentlich 1/2 und 3/4 addieren, aber wenn ich mir die Werte ausgeben lasse ist der 1. Bruch (abc) 9/9, der 2. (def) 0/0 und der 3. (ghi) auch 9/9. (Bitte keinen Kommentar zu den Variablennamen, ist nur nen Testprogramm ;) ) Hier ist der Code

Code: Alles auswählen

#include <iostream>

using namespace std;

class Frac
{
	public:

		Frac(long num = 1, long denom = 1)
		{
		    numerator = new long(num);
            denominator = new long(denom);
        }

		~Frac()
		{
            delete numerator;
            delete denominator;
		}
		long getNum()
		{
            return *numerator;
        }
        long getDenom()
		{
            return *numerator;
        }
        void setNum(long num = 1)
        {
            numerator = &num;
        }
        void setDenom(long denom = 1)
        {
            if (denom != 0)
            {
                denominator = &denom;
            }
        }
        Frac* operator+(Frac sum)
        {
            *numerator = (*numerator * sum.getDenom())+(sum.getNum() * *denominator);
            *denominator *= sum.getDenom();
            return this;
        }

	protected:

	private:
        long *numerator;
        long *denominator;

};


int main()
{
    Frac *abc = new Frac(1,2);
    Frac *def = new Frac(3,4);
    Frac *ghi = new Frac();

    ghi = *abc + *def;


    cout << abc->getNum() << endl;
    cout << abc->getDenom() << endl;
    cout << def->getNum() << endl;
    cout << def->getDenom() << endl;
    cout << ghi->getNum() << endl;
    cout << ghi->getDenom() << endl;

    return 0;
}
"Es gibt kein Problem das sich nicht loesen laesst, indem man die
Benutzerprozesse killt, alle ihre Files loescht, ihre Accounts sperrt
und ihre tatsaechlichen Einnahmen dem Finanzamt zukommen laesst."
Bastard Operator from Hell

KidPaddle
8 Bit
Beiträge: 265
Registriert: So Mai 14, 2006 12:18
Wohnort: Bayern

Re: Zeigerverwirrungen

#2 Beitrag von KidPaddle » Di Jun 01, 2010 15:44

Mir fallen zwei Probelmstellen sofort auf:

Warum sind deine Member Zeiger auf Long?

Im dem Operator "+" verändert Du die Membervariablen des Summanden abc, d. h. du arbeitest nicht mit einer Kopie von abc, sondern manipulierst abc direct. Als nächstes gibst Du einen Zeiger auf dem Summanden abc zurück und nicht auf ein neues Objekt. Daher sind die Werte von abc und ghi gleich. Zudem ist das instanzierte zuvor Objekt in ghi natürlich weg, da Du es ja mit dem Zeiger von abc überschreibst.

Gruß
Thomas

Benutzeravatar
darthcookie
6 Bit
Beiträge: 103
Registriert: So Aug 02, 2009 16:48

Re: Zeigerverwirrungen

#3 Beitrag von darthcookie » Di Jun 01, 2010 18:11

Ah OK danke, jetzt funktionierts :-D .
"Es gibt kein Problem das sich nicht loesen laesst, indem man die
Benutzerprozesse killt, alle ihre Files loescht, ihre Accounts sperrt
und ihre tatsaechlichen Einnahmen dem Finanzamt zukommen laesst."
Bastard Operator from Hell

Benutzeravatar
Evil Azrael
6 Bit
Beiträge: 109
Registriert: Mi Jan 20, 2010 22:14
Wohnort: Rheinkilometer 666 & hinter Heidelberg
Kontaktdaten:

Re: Zeigerverwirrungen

#4 Beitrag von Evil Azrael » Di Jun 01, 2010 18:15

KidPaddle hat geschrieben:Warum sind deine Member Zeiger auf Long?
Weil er üben möchte ;) Ist hier aber echt nicht angebracht, da unnötigerweise mit Pointern rum zu hantieren.

Code: Alles auswählen

        long getDenom()
      {
            return *numerator;
        }
*möp* Bitte korrigieren ;)

Ansonsten ist es wie KidPaddle sagt. Mach am ende mal ein

Code: Alles auswählen

   cout << abc << endl << def << endl << ghi << endl;
dann sollte das direkt auffallen. Mit dem verlorenen ghi Objekt hast du auch dein erstes Speicherleck programmiert :p

Code: Alles auswählen

        Frac* operator+(Frac sum)
        {
            *numerator = (*numerator * sum.getDenom())+(sum.getNum() * *denominator);
            *denominator *= sum.getDenom();
            return this;
        }
Das ist übrigens recht "krank" ;)
Du kriegst zwei Objekte (*this und das andere als Value) und gibst einen Pointer auf die Adresse von dem ersten zurück. Wenn du wirklich keinen kuriosen Spezialfall hast, solltest du auch immer ein Objekt zurückgeben. Üblicherweise übergibt man das andere Objekt auch als const reference.
War, War never changes... The end of the world occurred pretty much as we had predicted. Too many humans, not enough space or resources to go around. The details are trivial and pointless, the reasons, as always, purely human ones. A great cleansing, an atomic spark struck by human hands, quickly raged out of control, spears of nuclear fire rained from the skies, continents were swallowed in flames and fell beneath the boiling oceans....

God bless Germany! Bild

Benutzeravatar
darthcookie
6 Bit
Beiträge: 103
Registriert: So Aug 02, 2009 16:48

Re: Zeigerverwirrungen

#5 Beitrag von darthcookie » Di Jun 01, 2010 18:46

hmmmmm Jetzt hab ichs umgeschrieben, aber das Programm schmiert beim Addieren ganz ab (Prozess wurde mit Staus -1073741819 beended. (0 Minuten, 7 Sekunden) laut Code::Blocks)

Code: Alles auswählen

#include <iostream>

using namespace std;

class Frac
{
	public:

		Frac(long num = 1, long denom = 1)
		{
		    numerator = num;
            denominator = denom;
        }

		~Frac()
		{
            delete &numerator;
            delete &denominator;
		}
		long getNum()
		{
            return numerator;
        }
        long getDenom()
		{
            return denominator;
        }
        void setNum(long num = 1)
        {
            numerator = num;
        }
        void setDenom(long denom = 1)
        {
            if (denom != 0)
            {
                denominator = denom;
            }
        }
        Frac operator+(Frac sum)
        {
            
            Frac *fReturn = new Frac(numerator * sum.getDenom()+sum.getNum() * denominator, denominator * sum.getDenom());

            return *fReturn;
        }




	protected:

	private:
        long numerator;
        long denominator;

};


int main()
{
    

    Frac *abc = new Frac(1,2);

    

    Frac *def = new Frac(3,4);

    Frac ghi;

    cout << abc->getNum() << endl;
    cout << abc->getDenom() << endl;
    cout << def->getNum() << endl;
    cout << def->getDenom() << endl;

    ghi = *abc + *def;

    cout << ghi.getNum() << endl;
    cout << ghi.getDenom() << endl;

    
    return 0;

}
Es geht definitiv beim Addieren schief, da ich 4 Ausgaben habe^^ (die ersten 2 Brüche)
"Es gibt kein Problem das sich nicht loesen laesst, indem man die
Benutzerprozesse killt, alle ihre Files loescht, ihre Accounts sperrt
und ihre tatsaechlichen Einnahmen dem Finanzamt zukommen laesst."
Bastard Operator from Hell

Benutzeravatar
Evil Azrael
6 Bit
Beiträge: 109
Registriert: Mi Jan 20, 2010 22:14
Wohnort: Rheinkilometer 666 & hinter Heidelberg
Kontaktdaten:

Re: Zeigerverwirrungen

#6 Beitrag von Evil Azrael » Di Jun 01, 2010 20:19

Zeit, debuggen zu lernen. Also mal schön im debugging modus starten und schritt für schritt ausführen. ansonsten kleistere alles mit cout << "Ich bin in Zeile " << __line__ << endl; zu ;)

Code: Alles auswählen

        Frac operator+(Frac sum)
        {
            
            Frac *fReturn = new Frac(numerator * sum.getDenom()+sum.getNum() * denominator, denominator * sum.getDenom());

            return *fReturn;
        }
Das wäre wieder ein Speicherleck. Du gibst ein Objekt zurück, und nicht einfach nur ein Objekt, sondern ein Kopie. Es wird hier also ein Objekt auf dem Heap erstellt. Der Zeiger fReturn zeigt drauf. Im return wird eine Kopie von dem Objekt erstellt, und die Variable fReturn die auf den Speicher zeigt, geht verloren, weil der Scope zu ende ist. Folglich zeigt nix mehr auf den Speicher und du kommst nicht mehr ran.
Was du machen kannst, das ist

Code: Alles auswählen

        Frac& operator+(Frac sum) //wir geben eine referenz zurück. 
        {
            
            Frac *fReturn = new Frac(numerator * sum.getDenom()+sum.getNum() * denominator, denominator * sum.getDenom());

            return *fReturn;
        }
, weil das referenzierte Objekt ja weiterhin im Speicher lebt. Aber schön ist das auch nicht.

Und klar das du aus dem Programm fliegst:

Code: Alles auswählen

     ~Frac()
      {
            delete &numerator;
            delete &denominator;
      }
delete wird nur auf adressen angewendet die du mit new erzeugt hast. Was soll er da denn löschen? :nope:
Sobald er das Frac Objekt abbauen soll, steigt er aus.

(Interessanterweise hatte ich heute das gleiche Problem in einem Quelltext auf der Arbeit gefunden)
War, War never changes... The end of the world occurred pretty much as we had predicted. Too many humans, not enough space or resources to go around. The details are trivial and pointless, the reasons, as always, purely human ones. A great cleansing, an atomic spark struck by human hands, quickly raged out of control, spears of nuclear fire rained from the skies, continents were swallowed in flames and fell beneath the boiling oceans....

God bless Germany! Bild

Benutzeravatar
darthcookie
6 Bit
Beiträge: 103
Registriert: So Aug 02, 2009 16:48

Re: Zeigerverwirrungen

#7 Beitrag von darthcookie » Di Jun 01, 2010 20:44

Evil Azrael hat geschrieben: Und klar das du aus dem Programm fliegst:

Code: Alles auswählen

     ~Frac()
      {
            delete &numerator;
            delete &denominator;
      }
delete wird nur auf adressen angewendet die du mit new erzeugt hast. Was soll er da denn löschen? :nope:
Sobald er das Frac Objekt abbauen soll, steigt er aus.

(Interessanterweise hatte ich heute das gleiche Problem in einem Quelltext auf der Arbeit gefunden)
Ups, das hab ich vergessen, als ich die die Member von long* in long umgeschrieben habe :dash:.
"Es gibt kein Problem das sich nicht loesen laesst, indem man die
Benutzerprozesse killt, alle ihre Files loescht, ihre Accounts sperrt
und ihre tatsaechlichen Einnahmen dem Finanzamt zukommen laesst."
Bastard Operator from Hell

Benutzeravatar
Evil Azrael
6 Bit
Beiträge: 109
Registriert: Mi Jan 20, 2010 22:14
Wohnort: Rheinkilometer 666 & hinter Heidelberg
Kontaktdaten:

Re: Zeigerverwirrungen

#8 Beitrag von Evil Azrael » Di Jun 01, 2010 20:59

Das glaub ich nicht... der address-of operator (&) hat sich da bestimmt nicht von selber reingeschmuggelt :nope:

http://www.mi.uni-koeln.de/c/mirror/f7a ... /heap.html
Den Artikel find ich ganz gut.
War, War never changes... The end of the world occurred pretty much as we had predicted. Too many humans, not enough space or resources to go around. The details are trivial and pointless, the reasons, as always, purely human ones. A great cleansing, an atomic spark struck by human hands, quickly raged out of control, spears of nuclear fire rained from the skies, continents were swallowed in flames and fell beneath the boiling oceans....

God bless Germany! Bild

Antworten

Zurück zu „C++“

Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 1 Gast