Zeigerfeldabfrage auf Inhalt



  • Hallo!

    Ich habe ein kleines Problem mit meinem Programm, dass mich so langsam auf die Palme bringt.
    Im Forum hab ich so gut es ging gesucht aber nxi pasendes gefunden, dass slebe bei Google.

    Also Allgemein betseht das Programm aus mehreren Klassen und soll dazu dienen, ein Girokonto zu verwalten.
    In meinem Main File habe ich ein Konto angelegt und mehrere Buchungen vorgenommen (Gutschrift und Barabhebung sind Kindklassen von Buchung)
    Das Programm soll mir mit der Funktion Kontoauszug alles zu einem bestimmten Konto ausgeben.
    Dazu habe ich ein Pointerfeld angelegt das auf Buchungen weißt und in dem also Betrag und Datum der jeweiligen Buchung stehen.

    Wie kann ich es jetzt machen, dass ich wenn ich nur 2 Buchungen momentan einem Konto zugeordnet habe, ich auch nur diese beiden ausgegeben bekomme und keine Aufforderung kommt, das Programm zu unterbrechen.

    Hier meine Files soweit.. sind jetzt die die meiner Meinung nach wichtig sind:

    //Header Buchung
    class Buchung
    {
    public:
    	double Betrag;
    	Date Datum;
    
    	Buchung(void);
    	Buchung(double Betrag, Date Datum);
    	~Buchung(void);
    	void print();
    	Buchung& operator<<(Buchung umsatz);
    };
    
    #pragma once
    #include "Buchung.h"
    #define MAX_LENGE 4
    
    class Girokonto
    {
    private:
    	double Kontostand;
    	string Besitzer;
    	string Kontonummer;
    
    public:
    	Buchung **ptr; //Zeigerfeld auf Buchungen undefinierter Größe, also dynamisch
    	Girokonto(void);
    	Girokonto(double Kontostand, string Besitzer, string Kontonummer);
    	void Kontoauszug();
    	~Girokonto(void);
    };
    
    //Hier beginnt das Cpp File! Destruktor hab ich weggelassen
    
    #include "Girokonto.h"
    
    Girokonto::Girokonto(void)
    {
    	Kontostand=0;
    	Besitzer=Kontonummer="";
    
    	ptr = new Buchung*[MAX_LENGE]();//legt zeigerfeld von größe 10 an vom typ buchung, mit NULL gefüllt
    }
    
    Girokonto::Girokonto(double kontostand, string besitzer, string kontonummer)
    {
    	int i;
    
    	Kontostand=kontostand;
    	Besitzer=besitzer;
    	Kontonummer=kontonummer;
    
    	ptr = new Buchung*[MAX_LENGE](); //nur zum speicher allocieren wird mit NULL gefüllt (oder?)
    }
    
    void Girokonto::Kontoauszug()
    {
    	cout << "Kontostand: " << Kontostand
    		 << ", Besitzer: " << Besitzer
    		 << ", Kontonummer: " << Kontonummer
     		 <<"\nGetaetigte Buchungen:\n";
    	for (int i=0; i<MAX_LENGE; i++)
    	{
    		if (ptr != NULL)  //Hier weiß ich nicht was ich abfragen muss..
    		{
    			printf("%d.%d.%d, %lf\n", ptr[i]->Datum.Tag, 
    				ptr[i]->Datum.Monat, ptr[i]->Datum.Jahr,
    					ptr[i]->Betrag);
    		}
    		else cout <<"...."; //cout << &ptr   gibt ebenso Wert an
    	}
    }
    
    //TestMain
    #include <stdio.h>
    #include <conio.h>
    #include <stdlib.h>
    #include "Date.h"
    #include "Buchung.h"
    #include "Gutschrift.h"
    #include "Barabhebung.h"
    #include "Girokonto.h"
    
    int main ()
    {
    
    	Date x = Date(8,5,2012);
    	Date y = Date(2,5,2012);
    
    	Buchung umsatz =  Buchung(13.4,x);
    	Buchung umsatz2 = Buchung(400.00,y);
    
    	Girokonto konto1= Girokonto(6000,"Hans Meier","37726638");
    
    	Gutschrift plus = Gutschrift("7632","765876",umsatz.Datum,umsatz.Betrag);
    	Barabhebung minus= Barabhebung(500.00,y,"Erlangen");
    
    	konto1.ptr[0]=&plus;
    	konto1.ptr[1]=&minus;
    	konto1.Kontoauszug();
    	getch();
    }
    

    wenn ich das so eingebe, dann bekomme ich mit dem Kompiler keine Probleme, aber das Programm läuft nicht und das bekomme ich gesagt:

    Unbehandelte Ausnahme bei 0x774c15de in ÜbungsSchulAufgabe.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xfdfdfdfd.

    Ich weiß echt nicht was ich da jetzt machen muss um eben abzufragen, ob jetzt eine Buchung an der Stelle i im Pointerfeld gespeichert ist oder nicht.. also diese Abfrage macht mich kirre 😡

    Wäre für jede Hilfe dankbar!
    Falls was unklar ist versuch ich mich noch genauer auszudrücken.
    Danke im Voraus!

    LG, Meri



  • Meri schrieb:

    ... wird mit NULL gefüllt (oder?)

    Nein.



  • Ah das war nicht das aktuelle in beidenkonstruktoren

    Das steht noch in beiden Konstruktoren drinn:

    Girokonto::Girokonto(void)
    {
        Kontostand=0;
        Besitzer=Kontonummer="";
    
        ptr = new Buchung*[MAX_LENGE];//legt zeigerfeld von größe 10 an vom typ buchung, mit NULL gefüllt
        for (int i=0; i<MAX_LENGE; i++)
        {
            ptr[i]=NULL;
        }   
    }
    


  • Ein paar Anmerkungen von einem Anfänger:

    In Zeile 56 allozierst Du mit new Speicher.
    In den meisten Fällen(meiner Ansicht nach auch hier) braucht man das nicht.

    Davon ab müßte der Speicher mit delete auch wieder freigegeben werden, was Du aber nicht gemacht hast.

    Dann ist mir aufgefallen, daß Du printf in einem C++-Programm benutzt.
    So wie Du es machst, vermischt Du strenggenommen C und C++.
    Optimal wäre, die C++ Bibliothek einzubinden, um printf zu benutzen, also
    #include <cstdio>



  • redrew99 schrieb:

    In Zeile 56 allozierst Du mit new Speicher.
    In den meisten Fällen(meiner Ansicht nach auch hier) braucht man das nicht.

    👍

    redrew99 schrieb:

    So wie Du es machst, vermischt Du strenggenommen C und C++.
    Optimal wäre, die C++ Bibliothek einzubinden, um printf zu benutzen, also
    #include <cstdio>

    Das wäre noch mehr vermischen.
    In C++ bindet man <iostream> ein und verwendet cout .

    Meri schrieb:

    Buchung **ptr; //Zeigerfeld auf Buchungen undefinierter Größe, also dynamisch
    

    Wenn du einen vector nimmst, eliminierst du schlagartig viele Probleme

    std::vector<Buchung> buchungen;
    


  • Meri schrieb:

    Wie kann ich es jetzt machen, dass ich wenn ich nur 2 Buchungen momentan einem Konto zugeordnet habe, ich auch nur diese beiden ausgegeben bekomme und keine Aufforderung kommt, das Programm zu unterbrechen.

    Du könntest die Buchungen in einem KlassenVektor speichern.
    also z.B. (bitte nur den Vektor beachten)

    #include <iostream>
    #include <string>
    #include <vector>
    
    using namespace std;
    //Klassen
    class Spieler    
        public:
        //Eigenschaften
        string Name;
        string Vorname;
        //Funktionsdeklarationen
        void AusgabeVornameName();
        void Funktion(string x,string y);
    
    };
    //Funktionsdefinitionen
    //Ausgabe von Vor- und Nachnahmen
    void Spieler::AusgabeVornameName()
    {
        cout<<Vorname<<" "<<Name<<endl;
    }
    //Änderung der Klasseneigenschaft über eine Funktion
    void Spieler::Funktion(string x, string y)
    {
        Name=x;
        Vorname=y;
    }
    
    int main()
    {
        vector<Spieler>vieleSpieler;
        Spieler a;
        vieleSpieler.push_back(a);
        string x,y;
        cout<<"Name: ";
        cin>>x;
        cout<<"Vorname: ";
        cin>>y;
        //cout<<vieleSpieler[0].Name<<" "<<vieleSpieler[0].Vorname<<endl;
        Spieler* p;
        p=&a;
        p->Funktion(x,y);
        p->AusgabeVornameName();
    }
    


  • Meri schrieb:

    void Girokonto::Kontoauszug()
    {
        cout << "Kontostand: " << Kontostand
             << ", Besitzer: " << Besitzer
             << ", Kontonummer: " << Kontonummer
             <<"\nGetaetigte Buchungen:\n";
        for (int i=0; i<MAX_LENGE; i++)
        {
            if (ptr != NULL)  //Hier weiß ich nicht was ich abfragen muss..
            {
                printf("%d.%d.%d, %lf\n", ptr[i]->Datum.Tag,
                    ptr[i]->Datum.Monat, ptr[i]->Datum.Jahr,
                        ptr[i]->Betrag);
            }
            else cout <<"...."; //cout << &ptr   gibt ebenso Wert an
        }
    }
    

    ptr[i]!= NULL // ?



  • redrew99 schrieb:

    Davon ab müßte der Speicher mit delete auch wieder freigegeben werden, was Du aber nicht gemacht hast.

    Das freigeben tu ich im Destruktor den ich hier nicht mit angegeben habe 🙂

    Aber danke für den Hinweis mit dem Speicherallokieren im Konstruktor, dass hab ich gleich mal geändert.
    ___

    Furble Wurble schrieb:

    ] ptr[i]!= NULL // ?

    funktioniert leider genauso wenig 😕
    ____

    Und Danke auch an dich 'stan viktor' für das mit den Vektoren den Vorschlag.

    Würde die Aufgabe kein Pointerfeld vorgeschrieben, dann könnte ich das wirklich so machen 🕶
    Aber gut, ich setzt mich mal mit den Vektoren auseinander und hoffe das hilft 🙂

    Alles in allem: Danke!! :xmas1:



  • Meri schrieb:

    Furble Wurble schrieb:

    ptr[i]!= NULL // ?

    funktioniert leider genauso wenig 😕

    Hmm...das war natürlich der offensichtliche Fehler.

    Jetzt sehe ich nix ganz klar falsches mehr. Zeig doch mal den Destruktor.
    Ausserdem sehe ich dass es die Methode Buchung::print() gibt, könnte dann nicht Kontoauszug() zusammenschnurren:

    void Girokonto::Kontoauszug()
    {
        cout << "Kontostand: " << Kontostand
             << ", Besitzer: " << Besitzer
             << ", Kontonummer: " << Kontonummer
             <<"\nGetaetigte Buchungen:\n";
        for (int i=0; i<MAX_LENGE; i++)
        {
            if (ptr[i] != NULL)  //Hier weiß ich nicht was ich abfragen muss..
            {
                ptr[i]->print();
            }
            else cout <<"...."; //cout << &ptr   gibt ebenso Wert an
        }
    }
    

    Je weniger Quelltext, desto eher findest Du auch den Fehler.
    In Buchung machst Du nicht noch solche Zeigerspielereien?



  • So sieht mein Destruktor aus:

    Girokonto::~Girokonto(void)
    {
    	cout << "Alle Buchungen werden freigegeben!\n";
    	delete[] ptr;
    }
    

    Wenn ich im Konstruktor das Speicherplatzallokieren sein lasse, dann bekomme ich beim Destruktor nen Fehler.. ist mir eben aufgefallen.

    Das mit dem 'Zusammenschnürren' hat funktioniert, Danke für den Tip, sieht gleich übersichtlicher aus.

    Und nein, sonst arbeite ich nirgendswo mit Pointern

    LG



  • Meri schrieb:

    So sieht mein Destruktor aus:

    Girokonto::~Girokonto(void)
    {
    	cout << "Alle Buchungen werden freigegeben!\n";
    	delete[] ptr;
    }
    

    Wenn ich im Konstruktor das Speicherplatzallokieren sein lasse, dann bekomme ich beim Destruktor nen Fehler.. ist mir eben aufgefallen.

    Das mit dem 'Zusammenschnürren' hat funktioniert, Danke für den Tip, sieht gleich übersichtlicher aus.

    Und nein, sonst arbeite ich nirgendswo mit Pointern

    LG

    Hmm...hmmm...
    Ich sehe da keinen Fehler, wenn die Konstruktoren die ptr[i]s auf NULL setzen (so wie der nachgereichte Konstruktor), und Du jeden ptr[i] prüfst, bevor Du Ihn dereferenzierst...alles in Ordnung.

    Und es ist wirklich nur der Code, der ptr[i]s dereferenziert? Weil Du z.B. von einer Arraylänge von 10 schreibst (im Kommentar) das Makro MAX_LENGE(sic!) allerdings den Wert 4 hat?



  • Nope, das war nur die Ursprüngliche Größe des Feldes wie es in der Aufgabestand aber die hab ich dann zum testen immer herab gesetzt damit ich beim debuggin nicht so oft die schleife durchlaufen muss

    Aber schön das von der Syntax her alles zu passen scheint :'D



  • Meri schrieb:

    Nope

    Schade...

    Meri schrieb:

    Aber schön das von der Syntax her alles zu passen scheint :'D

    Das ist noch das einfachste.

    Ich kann Dir nicht mehr helfen.
    Wenn es immer noch abbricht, obwohl Du den Fehler beseitigt hast, hakt es irgendwo an einer Stelle, die Du nicht gepostet hast.

    Debugger...
    Testausgaben...

    Good Hunting! 🙂


Anmelden zum Antworten