Datei formatiert einlesen



  • Hi,
    ich würde gern aus einer Datei
    Datei.txt
    a(2,2) = -1.835417e+06 [1/s]
    a(3,2) = 1.835417e+06 [1/s]
    die Zahlen auslesen.
    Versucht habe ich es mit 3 Schleifen durchläufe von

    scan = fscanf(datei,"a(%d,%d) = %e [1\\s] ",&(Zeile[i]),&(Spalte[i]),&(Wert[i]));

    printf("a(%d,%d) = %e und scan: %d \n",Zeile[i],Spalte[i],Wert[i],scan);

    Doch das Ergebnis war:

    a(1,1) = -2.849212e-41 und scan: 3
    a(0,-1216006536) = 4.852668e-270 und scan: 0
    a(0,134513496) = -3.044647e-41 und scan: 0

    Meine Fragen sind : Was muss ich korrigieren und wie hätte man es eleganter machen können. Ich würde mich sehr über eine Antwort freuen und nach google zu urteilen auch einige andere. Vielen Dank



  • 1. ist es 1/s und nicht 1\\s, dein scan ist also falsch
    2. ist Wert vermutlich ein double-Array, du liest und schreibst hier aber floats.


  • Mod

    white flow schrieb:

    wie hätte man es eleganter machen können.

    Falls du hier nicht versehentlich im falschen Unterforum geschreieben hast (hier ist C++, nicht C): Mit C++ Mittel dürfte sich das, wenn auch nicht unbedingt eleganter, so doch auf jeden Fall allgemeiner machen lassen. Und das ist dann doch auch wieder eine Form von Eleganz.



  • Vielen Dank für eure Hilfe:

    Mit

    scan = fscanf(datei,"a(%d,%d) = %lf [1/s] ",&(Zeile[i]),&(Spalte[i]),&(Wert[i]));

    hat es funktioniert.

    P.S. Falsches Forum ? Ich glaube nicht 😉 ihr konntet mir doch helfen.



  • SeppJ schrieb:

    white flow schrieb:

    wie hätte man es eleganter machen können.

    Falls du hier nicht versehentlich im falschen Unterforum geschreieben hast (hier ist C++, nicht C): Mit C++ Mittel dürfte sich das, wenn auch nicht unbedingt eleganter, so doch auf jeden Fall allgemeiner machen lassen. Und das ist dann doch auch wieder eine Form von Eleganz.

    So etwa?

    #include <iostream>
    #include <fstream>
    #include <streambuf>
    
    struct text
    {
        text( const char* txt ) : m_txt( txt ) {}
        friend std::istream& operator>>( std::istream& in, const text& t )
        {
            using namespace std;
            istream::sentry ok( in );
            if( ok )
            {
                ios_base::io_state state = ios_base::goodbit;
                const char* ref = t.m_txt;
                for( istream::int_type m = in.rdbuf()->sgetc(); *ref; ++ref, m = in.rdbuf()->snextc() )
                {
                    typedef istream::traits_type traits;
                    if( traits::eq_int_type( m, traits::eof() ) )
                    {
                        state |= ios_base::eofbit | ios_base::failbit;
                        break;
                    }
                    if( traits::to_char_type( m ) != *ref )
                    {
                        state |= ios_base::failbit;
                        break;
                    }
                }
                in.setstate( state );
            }
            return in;
        }
    private:
        const char* m_txt;
    };
    
    int main()
    {
        using namespace std;
        ifstream datei("Datei.txt");
        int zeile, spalte;
        for( double wert; datei >> text("a(") >> zeile >> text(",") >> spalte >> text(") =") >> wert >> text("[1/s]"); )
            cout << "a(" << zeile << "," << spalte << ") = " << wert << " [1/s]" << endl;
        return 0;
    }
    

    Gruß
    Werner



  • Werner fielen Dank für dein wahrscheinlich
    sehr elegante Struktur, die im Moment noch meine Kenntnisse, der verwendeten
    Klassen überflügelt, doch einige Anregungen zum Vertiefen gibt.

    Leider bin ich bin mit einem weitern etwas merkwürdigen C++ Problem konfrontiert.
    Die aus der Datei ausgelesen Daten werden durch die Funktion einlesen() wie gewollt zur Kontrolle ausgegeben, doch die main Funktion gibt nichts aus.
    Benutze ich aber den konkreten Pfad funktioniert es, was ich sehr merkwürdig finde.

    Ist die Art und Weise wie ich in der main Funktion auf die Matrix zu greife, ok?

    struct Matrix {
    int dim;
    double **Wert;
    };

    Matrix* einlesen(void)
    {

    int Zeile[400];
    int Spalte[400];
    double Datenwert[400];

    char* Dateipfad;// = "/konkreter Dateipfad";
    cout<<"Geben Sie bitte den Dateipfad ein."<<endl;
    scanf("%s",Dateipfad);

    FILE datei;
    datei = fopen(Dateipfad/
    "/konkreter Dateipfad"*/,"r");

    int i = 0;

    while(fscanf(datei,"a(%d,%d) = %lf [1/s] ",&(Zeile[i]),&(Spalte[i]),&(Datenwert[i])) != 0 ){

    printf("a(%d,%d) = %e [1/s] \n",Zeile[i],Spalte[i],Datenwert[i]);
    i++;
    }

    fclose(datei);

    cout<<"Es sind: "<<i<<" Datensaetze."<<endl;

    int AnzahlDaten;
    AnzahlDaten = i;

    double Zwischenspeicher;
    Zwischenspeicher = ((i - 4)/3) +2;

    int Anz_Dia_Ele;
    Anz_Dia_Ele = (int)Zwischenspeicher;

    cout << "Es sollen "<< Anz_Dia_Ele <<" Eigenwerte berechnet." <<endl;
    cout<<endl;

    Matrix* DatenMatrix;
    DatenMatrix = new Matrix;
    DatenMatrix->dim = Anz_Dia_Ele;

    DatenMatrix->Wert = new double*[Anz_Dia_Ele];

    for(int i = 0;i<Anz_Dia_Ele;i++){
    *(DatenMatrix->Wert + i) = new double[Anz_Dia_Ele];
    }

    for(int t=0;t < AnzahlDaten; t++)
    {
    ((DatenMatrix->Wert + (Zeile[t]-1))+(Spalte[t]-1))= Datenwert[t];
    }

    return DatenMatrix;
    }

    int main()
    {
    cout<<((einlesen()->Wert+0)+0)<<((einlesen()->Wert+1)+1)<<((einlesen()->Wert+2)+2)<<endl;
    }



  • Nur mal eben in die richtigen Tags:

    struct Matrix {
        int dim;
        double **Wert;
    };
    
    Matrix* einlesen(void)
    {
    
    	 int Zeile[400];
    	 int Spalte[400];
         double Datenwert[400];
    
    	 char* Dateipfad;// = "/konkreter Dateipfad";
            cout<<"Geben Sie bitte den Dateipfad ein."<<endl;
         scanf("%s",Dateipfad);
    
    	 FILE *datei;
    	 datei = fopen(Dateipfad/*"/konkreter Dateipfad"*/,"r");
    
    	 int i = 0;
    
    	 while(fscanf(datei,"a(%d,%d) = %lf [1/s] ",&(Zeile[i]),&(Spalte[i]),&(Datenwert[i])) != 0 ){
    
    	  		 printf("a(%d,%d) = %e [1/s] \n",Zeile[i],Spalte[i],Datenwert[i]);
    	  		 i++;
    	  }
    
         fclose(datei);
    
         cout<<"Es sind: "<<i<<" Datensaetze."<<endl;
    
         int AnzahlDaten;
         AnzahlDaten = i;
    
         double Zwischenspeicher;
         Zwischenspeicher = ((i - 4)/3) +2;
    
         int Anz_Dia_Ele;
         Anz_Dia_Ele = (int)Zwischenspeicher;
    
         cout << "Es sollen "<< Anz_Dia_Ele <<" Eigenwerte berechnet." <<endl;
         cout<<endl;
    
         Matrix* DatenMatrix;
         DatenMatrix = new Matrix;
         DatenMatrix->dim = Anz_Dia_Ele;
    
         DatenMatrix->Wert = new double*[Anz_Dia_Ele];
    
         for(int i = 0;i<Anz_Dia_Ele;i++){
         *(DatenMatrix->Wert + i) = new double[Anz_Dia_Ele];
         }
    
         for(int t=0;t < AnzahlDaten; t++)
              {
        	   *(*(DatenMatrix->Wert + (Zeile[t]-1))+(Spalte[t]-1))= Datenwert[t];
              }
    
         return DatenMatrix;
    }
    
    int main()
    {
      cout<<*(*(einlesen()->Wert+0)+0)<<*(*(einlesen()->Wert+1)+1)<<*(*(einlesen()->Wert+2)+2)<<endl;
    }
    


  • white flow schrieb:

    Die aus der Datei ausgelesen Daten werden durch die Funktion einlesen() wie gewollt zur Kontrolle ausgegeben, doch die main Funktion gibt nichts aus.
    Benutze ich aber den konkreten Pfad funktioniert es, was ich sehr merkwürdig finde.

    Das ist nicht merkwürdig, wenn man sich darüber Gedanken hat, wo die Zeichen aus dem String 'DateiPfad' überhaupt hingespeichert werden. Du hast dafür keinerlei Memory zur Verfügung gestellt.
    Da wir hier in der C++-Ecke sind - schlage ich Dir folgendes Vorgehen vor (ab Zeile 13 in Fellhuhns Posting):

    // #include <string> // noch inkludieren
        string Dateipfad;// = "/konkreter Dateipfad";
        cout<<"Geben Sie bitte den Dateipfad ein."<<endl;
        getline( cin, Dateipfad );
    

    Bitte inkludiere noch <string> damit es funktioniert. Die std::string-Klasse nimmt Dir das Besorgen des benötigten Speichers ab und viel einfacher zu benutzten, als wenn Du selbst mit new/alloc versuchst es zu organisieren.

    white flow schrieb:

    Ist die Art und Weise wie ich in der main Funktion auf die Matrix zu greife, ok?

    Nicht so ganz. Jedes mal, wenn Du einlesen() aufrufst, wird es auch ausgeführt. D.h. Die Matrix wird im besten Fall auch dreimal gelesen, was ja völlig unnötig ist, außerdem wird für drei Matrizen Speicher allokiert, der auch nie wieder frei gegeben wird.

    Besser Du änderst zunächst die Matrix so ab, dass Du Dich um den Speicher nicht mehr sorgen musst.

    #include <vector>
    #include <cassert>
    
    struct Matrix
    {
        explicit Matrix( std::size_t dim )
            : m_anzSpalten( dim )
            , m_werte( dim * dim )
        {}
        double* operator[]( std::size_t idxZeile )
        {
            assert( idxZeile < m_werte.size() / m_anzSpalten );
            return &m_werte[ idxZeile * m_anzSpalten ];
        }
    private:
        std::size_t m_anzSpalten;
        std::vector< double > m_werte;
    };
    

    Der Zugriff auf ein Element funktioniert dann einfach mit

    Matrix mx(20);
        mx[4][1] = 3.14; // Element mit Index Zeile 4 und Index Spalte 1 setzen
    

    Der Code ab Zeile 44 vereinfacht sich dann zu:

    Matrix DatenMatrix( Anz_Dia_Ele );
        for(int t=0;t < AnzahlDaten; ++t )
        {
            assert( Zeile[t] <= Anz_Dia_Ele ); // Indizes checken
            assert( Spalte[t] <= Anz_Dia_Ele );
            DatenMatrix[ Zeile[t]-1 ][ Spalte[t]-1 ] = Datenwert[t];
        }
    
        return DatenMatrix;
    

    Die Signatur von einlesen muss dann noch angepasst werden

    Matrix einlesen()
    { // usw.
    

    und schließlich wird das main() zu:

    int main()
    {
        using namespace std;
        Matrix mx = einlesen();
        cout << mx[0][0] << " " << mx[1][1] << " " << mx[2][2] << endl;
    }
    

    Gruß
    Werner


Anmelden zum Antworten