Klasse die aus einer Datei Daten einließt



  • The architect schrieb:

    Die Aufgabe stammt aus einer Fachhochschule.
    Darf man fragen wieso dich dies interessiert?

    Ääh - ich arbeite gerade an einem Vortrag über guten und schlechten Stil bzw. Design und die richtige Wahl von Schnittstellen. Das Thema steht noch nicht so genau fest. Und diese Aufgabenbeschreibung deckt sich fast zu 100% mit meinem Negativ-Beispiel - also wie man es genau nicht machen soll. 🙄

    :xmas2: Werner



  • The architect schrieb:

    Zu der Aufgabe:

    Ich habe versucht nun eure beiden (drakon und Nexus) Vorschläge zu integrieren, aber es klappt noch nicht. ( nur bezogen auf das Einlesen)
    Ich komme auch leider nicht drauf, könnt ihr mir nochmal nen Anhaltspunkt geben?
    Bitte nicht das Ergebnis sagen, nur darauf hin leiten.

    Hier habe ich es nun so gemacht wie Drakon beschrieben hat:

    float* px = new float[n];
    	float* py = new float[n];
    	for(int i=0; i<n; i++)
    		input2 >> *px[i] >> *py[i];
    

    Überlege durch welche Operatoren [] bzw. * welcher Typ in was umgewandelt wird.
    Schau Dir nochmal genau das letzte Posting von Nexus an - da steht die Lösung.

    The architect schrieb:

    ich könnte dies evtl. auf andere Weise lösen indem ich den Zeiger um 1Stelle immer verschiebe. px++;
    Aber dies ist eher nicht so gut da ich am schluss den Zeiger dann wieder korrigieren müsste.

    Das kannst Du schon so machen, wenn Du vorher eine Kopie der Zeiger anlegst und die Kopie zum iterieren benutzt.

    Gruß
    Werner



  • Werner Salomon schrieb:

    ich arbeite gerade an einem Vortrag über guten und schlechten Stil bzw. Design und die richtige Wahl von Schnittstellen.

    Veröffentlichst du den Vortrag, wenn er fertig ist? Hört sich wirklich interessant!



  • Badestrand schrieb:

    Werner Salomon schrieb:

    ich arbeite gerade an einem Vortrag über guten und schlechten Stil bzw. Design und die richtige Wahl von Schnittstellen.

    Veröffentlichst du den Vortrag, wenn er fertig ist? Hört sich wirklich interessant!

    Normal nicht, da es sich um eine firmeninterne Veranstaltung handelt.

    Gruß
    Werner



  • Nexus schrieb:

    Zweitens erwartet der >>-Operator hier ein float und keinen Zeiger auf float.

    Werner Salomon schrieb:

    Überlege durch welche Operatoren [] bzw. * welcher Typ in was umgewandelt wird.
    Schau Dir nochmal genau das letzte Posting von Nexus an - da steht die Lösung.

    Also damit der operator>> damit arbeiten kann muss ich ihm einen float und nicht einen *float übergeben.
    Momentan bekommt er durch px[i] einen Zeiger.
    px ist mein Zeiger auf den Arrayanfang, mit *px komme ich auf den Bereich auf den der Zeiger zeigt. ( Dereferenzieren).

    Ich kann leider nicht genau beurteilen ob meine jetztige Lösung stimmt, da ein Laufzeitfehler auftritt beim debuggen.

    Fehler schrieb:

    Unbehandelte Ausnahme bei 0x68ef31ea (msvcr90d.dll) in testreihe.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0xccccccc0.

    float* px = new float[n];
    float* py = new float[n];
        for(int i=0; i<n; i++)
            input2 >> *(px+i) >> *(py+i);
    


  • Ne. Du hast keinen Zeiger. Du hast ein Array von floats und mit dem []-Operator kommst du auf die richtigen Werte..

    float a[5];
    std::cout << a [ 0 ];
    std::cin >> a [ 1 ];
    

    War ein wenig ungeschickt von mir das Beispiel mit Zeigern zu machen. Das war vlt. die Verwirrung. (auch wenn es schlussendlich das gleiche ist. ;))



  • Deine Lösung stimmt.

    Jedoch ist

    *(px+i)
    

    genau äquivalent zu

    px[i]
    

    Mit dem Index-Operator [] wird also auch dereferenziert.



  • Okay dann ist also die Definition des char* Parameterkonstruktors auch richtig

    testreihe::testreihe():n(0),px(0),py(0){}
    testreihe::testreihe(char* dateiname):n(0),px(0),py(0)
    {
    	//Anzahl der Wertepaare bestimmen
    	ifstream input;
    	input.open(dateiname);
    	if(!input) cerr << "FAILURE: File not opened";
    	float temp;
    	while(input>>temp) n++;
    	input.close();
    
    	//Werte in px und py schreiben
    	ifstream input2;
    	input2.open(dateiname);
    	if(!input2) cerr << "FAILURE: File not opened";
    	float* px = new float[n];
    	float* py = new float[n];
        for(int i=0; i<n; i++)
            input2 >> px[i] >> py[i];	
    
    	input2.close();
    }
    

    Beim Kopierkonstruktor taucht noch ein Fehler auf.

    testreihe::testreihe(const testreihe& t):n(t.n)
    {
    	float* px = new float[n];
    	float* py = new float[n];
    
    	for(int i=0; i<n; i++)
    	{
    		px[i]=t.px[i];
    		py[i]=t.py[i];
    	}
    }
    

    Fehler schrieb:

    Unbehandelte Ausnahme bei 0x00c41a52 in testreihe.exe: 0xC0000005: Zugriffsverletzung beim Lesen an Position 0x00000000.

    Jemand eine Ahnung was ich hier wieder falsch mache?



  • Ich würde mal sagen, dass t.px[] ungültig, weil leer ist.
    Schau dir das mal mit dem Debugger an, dann siehst dus.



  • The architect schrieb:

    Jemand eine Ahnung was ich hier wieder falsch mache?

    Im Kopierkonstruktor erstmal nichts, Du solltest noch abfragen, ob t.n==0 ist. Falls ja kann man das Codesegment überspringen. Außerdem solltest Du die Zeiger immer in der Initialisierungsliste mit 0 initialisieren.
    Der Fehler kann z.B. dann auftreten, wenn n>0 ist, aber die Zeiger px,py noch 0 sind.

    Im Konstruktor zählt n die Anzahl der Zahlen, aber Du brauchst die Anzahl der Paare! Aber das löst den von Dir genannten Fehler nicht aus.

    :xmas2: Werner



  • The architect schrieb:

    Die Datei TESTREIHE.TXT sieht so aus:

    38,5 148,08
    33,6 103,51
    41,2 143,76
    46,4 171,27
    ...
    35,9 128,56
    37,9 142,79
    37,7 141,54

    Wenn die Zahlen mit Komma als Dezimaltrenner versehen sind, so muss man die entsprechende locale setzen. Im MS-Umfeld (z.B. VC8) sieht das etwa so aus:

    ifstream datei("TESTREIHE.TXT");
        datei.imbue( locale("german") ); // in der Folge werden Zahlen mit Komma als Dezimaltrennzeichen gelesen
    

    Gruß
    Werner



  • Danke Werner, das mit dem Einlesen klappt jetzt wunderbar.
    er ließt nun alle Werte ein, diese Anzahl nehme ich dann einfach durch 2

    ( mein File hat z.b 8 Werte)

    Der Fehler von dem ich gesprochen habe, besteht aber noch immer.

    Das was du vorhin geschrieben hast habe ich nun so umgesetzt:

    testreihe::testreihe(const testreihe& t):n(t.n),px(0),py(0)
    {
    	if(t.n!=0)
    		{
    			float* px = new float[n];
    			float* py = new float[n];
    			for(int i=0; i<n/2; i++)
    			{
    				px[i]=t.px[i];
    				py[i]=t.py[i]; 
    			}
    		}
    }
    

    Falls also n=0 ist wird das Codesegement übersprungen.



  • -Anzahl n der Zahlenpaare

    testreihe::testreihe(const testreihe& rhs)
       : n(t.n), px(0), py(0)
    {
        if(! n)//n == 0
             return;
    
        float* px = new float[n];
        float* py = new float[n];
        for(int i=0; i != n; ++i)
        {
             px[i]=rhs.px[i];
             py[i]=rhs.py[i]; 
        }
    }
    

    so kann man das doch schon mal lesen... dann gibts noch ne schöne stl-funktion:

    testreihe::testreihe(const testreihe& rhs)
       : n(t.n), px(0), py(0)
    {
        if(! n)//n == 0
             return;
    
        float* px = new float[n];
        float* py = new float[n];
        std::copy(px, px+n, rhs.px); //von rhs.px n werte nach px kopieren
        std::copy(py, py+n, rhs.py); //von rhs.py n werte nach py kopieren
    }
    

    Als kleine Anmerkung: Für Pointer würde ich im Übrigen nicht 0 nehmen - ich würd nullptr nehmen und das zunächst als NULL definen oder gleich den workaround bis zum nächsten standard nehmen, aber das sei nur mal so nebenebbei erwähnt

    testreihe::testreihe(const char* dateiname) //const zeigt dem aufrufenden an, dass seine zeichenkette nach dem funktionsaufruf die gleiche ist, wie zuvor
       n(0), px(0), py(0)
    {
        //Anzahl der Wertepaare bestimmen
        std::ifstream input;
        input.exceptions (std::ifstream::eofbit | std::ifstream::failbit | std::ifstream::badbit); //es werden exceptions geworfen, falls etwas schief geht - die fangen wir aber zunächst mit dem try / catch selbst auf und werfen ne andere exception weiter:
        try
        {
          input.open(dateiname);
          float temp;
          for(float temp; !input.eof(); ++n)
              input >> temp;
          input.seekg(std::ios_base::beg); //wir nehmen den gleichen stream wieder - brauchen ja keinen anderen...
    
          if(!n)
             return; //evtl fehlermeldung?
    
          //Werte in px und py schreiben
          float* px = new float[n];
          float* py = new float[n];
          for(int i=0; i != n; ++i)
              input >> px[i] >> py[i];
       }
       catch (...)//evtl TODO ^^
       {
         //TODO
       }
    }
    

    Sehr nützliche Referenz (vor allem zu Streams nutze ich sie auch sehr gerne ^^):
    http://www.cplusplus.com/reference/

    ich würd ja gern weitermachen aber ich geh dann erstmal frühstücken 😉

    bb



  • unskilled schrieb:

    so kann man das doch schon mal lesen... dann gibts noch ne schöne stl-funktion:

    std::copy(px, px+n, rhs.px); //von rhs.px n werte nach px kopieren
        std::copy(py, py+n, rhs.py); //von rhs.py n werte nach py kopieren
    

    Die "schöne STL-Funktion" wurde hier aber falsch angewandt. 😉

    Richtig wäre Folgendes, du willst schliesslich von rhs nach *this kopieren:

    std::copy(rhs.px, rhs.px + n, px);
    


  • vielen dank an alle die mir bei dieser Aufgabe geholfen haben.
    Ich habe das Programm nun fertig

    gruß architect


Anmelden zum Antworten