Probleme mit map.insert



  • Hallo Forum,
    ich bin leider über die Suchenfunktion nicht auf eine passende Antwort gestoßen, vllt. kann mir jemand helfen.

    Ich habe eine Datei, aus der ich Zustände einlesen muss. Die Zustände sind wie folgt abgespeichert: "(x,x,x,x,x) y" wobei x integer sind und y float/double.

    Die Schleife durchläuft eine Datei zeilenweise.

    Die komplette Schleife funktioniert an für sich, also der liest die Zustände richtig ein und legt die in dem inputVector ab. Auch den double Wert liest der richtig ein.

    Aber, wenn ich den vector und die double dann in eine map einfügen will, stürzt das Programm ab.

    Das interessante ist, dass ich durch die zwei cout's dadrüber und dadrunter die "Fehlerquelle" eingrenzen wollte, weil ich dachte, dass der Fehler durch den insert Befehl kam. Aber der Fehler tritt an irgendeiner anderen Stelle auf, weil der sowohl den temporary Wert ausgibt, als auch die Meldung "after insertion".

    Der Aufruf direkt ist es also anscheinend nicht, aber ohne den Aufruf funktioniert die Schleife problemlos. Ich bin quasi mit meinem Latein am Ende.

    Als Fehlermeldung bekomme ich "Process returned -1073741819 (0xC0000005)"

    Kann mir jemand helfen???

    while (!f.eof())
        {
            f.getline(cstring, sizeof(cstring));
            string lineString(cstring);
            flag = true;
            lastMarking=0;
            for (int i = 2; flag != false; i++)
                {
                    if (lineString[i]==',')
                        {
                            temporary = lineString.substr(lastMarking+1, i-lastMarking);
                            inputVector.push_back(atoi(temporary.c_str()));//(lineString.substr(lastMarking, i-lastMarking));
                            lastMarking = i;
                        }
                    if (lineString[i]==')')
                        {
                            temporary = lineString.substr(lastMarking+1, i-lastMarking);
                            inputVector.push_back(atoi(temporary.c_str()));
                            lastMarking = i;
                            for(j = lastMarking;lineString[j]!='\n';j++){}
                            temporary = lineString.substr(lastMarking+2, j-lastMarking);
                            probabilityValue = atof(temporary.c_str());
                            flag = false;
                        }
                }
    
            cout<<temporary<<endl;
            //inputMap[inputVector]=0;
            //inputMap.insert(pair<vector<int>,double>(inputVector, probabilityValue));
            cout<<"after insertion"<<endl;
            inputVector.clear();
            lineString.clear();
        }
    


  • Ich würde mal vermuten, du machst schon beim Einlesen und Verarbeiten der Daten etwas kaputt.

    PS: Wozu eigentlich die Zwischenspeicherung in ein char-Array? Es gibt auch eine (globale) Funktion getline(), die mit std::string funktioniert.



  • Hallo nochmal,
    ich habe den Fehler gefunden,
    ich habe die map als "std::map<std::vector<int>, double>" initialisiert, während der vector als "vector<int>" initialisiert wurde.

    Ich habe zuerst ausprobiert den vector als "std::vector<int>" zu initialisieren mit dem Ergebnis, dass das Programm noch schneller abstürzte als zuvor.
    Als ich dann die map auf "std::map<vector<int>, double>" geändert habe, hat es funktioniert.

    Schön, dass es jetzt funktioniert, aber ich wüsste trotzdem gerne, warum das vorher nicht funktioniert hat. Kann mir das jemand näher bringen?


  • Mod

    Sehr viele handfeste Fehler und viele weitere unnötige potentielle Fehlerquellen in deinem Programm (lernst du zufällig mit einem Buch von Jürgen Wolf? Der Stil würde passen), die erkläre ich dir nicht alle im Detail. Woran dein spezieller Fehler jetzt liegt, mag ich auch nicht rausfinden, es lohnt einfach nicht, dein Programm zu verbessern. Lieber neuschreiben:

    #include<iostream>
    
    template <unsigned N, typename T> class SimpleVector
    {
      T data[N];
    public:
      const T& operator[](unsigned x) const {return data[x];}
      T& operator[](unsigned x) {return data[x];}
      friend std::ostream& operator<<(std::ostream& out, const SimpleVector<N, T> &rhs)
        {
          out << '(';
          for (unsigned i=0; i < N-1; ++i) out << rhs.data[i] << ',';
          out << rhs.data[N-1] << ')';
          return out;
        }
      friend std::istream& operator>>(std::istream& in, SimpleVector<N, T> &rhs)
        {
          char delimiter=0;
          in >> delimiter;
          if (delimiter == '(')
            {
              for (unsigned i=0; i < N-1; ++i) 
                {
                  in >> rhs.data[i] >> delimiter;
                  if (delimiter != ',') break;
                }
              in >> rhs.data[N-1] >> delimiter;
              if (delimiter == ')')
                return in;        
            }
          // Fail
          in.setstate(std::ios::failbit);
          return in;
        }
      bool operator<(const SimpleVector<N, T> &rhs) const
      {
        for(unsigned i = 0; i < N; ++i)
          {
            if (data[i] < rhs.data[i]) 
              return true;
            else if(data[i] > rhs.data[i])
              return false;
          }
        return false;
      }
    };
    
    typedef SimpleVector<5, int> Int5D;
    
    #include<fstream>
    #include<iostream>
    #include<map>
    
    using namespace std;
    
    int main()
    {
      typedef map<Int5D, double> MapType;
    
      ifstream in("test.dat");
    
      MapType my_map;
      Int5D key;
      double value;
      while (in >> key >> value)
        my_map.insert(make_pair(key, value));
    
      cout << "Die Map enthält diese Schlüssel-Wert-Paare:\n";
      for(MapType::const_iterator it = my_map.begin(); it != my_map.end(); ++it)
        cout << it->first << ' ' << it->second << '\n';
    }
    

    Bis auf ein noch fehlendes statisches assert, ob N!=0, sollte das sicher sein.

    test.dat:

    (1,2,1,2,1) 1.4
    (2,5,5,1,5) 2.4
    (1,3,5,1,5) 2.3
    (3,5,6,7,8) 3.8
    

    Ausgabe:

    Die Map enthält diese Schlüssel-Wert-Paare:
    (1,2,1,2,1) 1.4
    (1,3,5,1,5) 2.3
    (2,5,5,1,5) 2.4
    (3,5,6,7,8) 3.8
    

    edit: Beachte die geänderte Einleselogik in der main. eof ist etwas, was erreicht wird, nachdem über das Dateiende gelesen wurde. Das heißt so wie du es bisher hattest, würdest du im Fehlerfall irgendwelche falsche Daten abspeichern, da du erst auf eof prüfst, dann liest, dann verarbeitest. Du musst erst lesen, dann prüfen, dann verarbeiten.
    Beachte auch, wie hübsch aufgeräumt und leicht zu lesen das Hauptprogramm ist, wenn man die komplizierte Funktionalität wegkapselt.
    Und die (gefährlichen) Umwege über char-Arrays brauchst du auch nicht, wie von CStoll vorgeschlagen, durch std::string zu ersetzen, sondern man kann direkt auf den Streams operieren. Die haben schließlich die gleichen mächtigen Möglichkeiten wie ein Stringstream oder die von die benutzten (und sogar weniger mächtigen) C-Funktionen. Mein Beispielprogramm ist nur doppelt so groß wie deine Einleseroutine allein, zeigt aber eine (semi-)vollständige Vektorklasse mit Einlesen, Ausgabe, und Vergleichen und ein komplettes Beispiel zu allen diesen Funktionen.

    edit2: Und noch zu deinem vorherigen Fehler: Wie hast du es denn gemacht, dass die map einen vector<int> als Schlüssel annimmt? Da hast du doch irgendeine Vergleichsfunktion angeben müssen. Vielleicht liegt da der Fehler.


  • Mod

    SeppJ schrieb:

    Wie hast du es denn gemacht, dass die map einen vector<int> als Schlüssel annimmt? Da hast du doch irgendeine Vergleichsfunktion angeben müssen. Vielleicht liegt da der Fehler.

    Überladene Vergleichsoperatoren gibt es für alle Standardcontainer. Und außerdem gibt es noch std::lexicographical_compare 😉



  • Danke SeppJ für deine Bemühung.

    Da die Maps bei mir bisher die Vektoren ohne meckern angenommen haben, habe ich mir darüber keine Gedanken gemacht.

    Der sortiert das dann komponentenweise. Also erst aufsteigend nach der ersten Komponenten, dann die zweite untergeordnet zur ersten, usw.

    Das mein Programmierstil "stümperhaft" ist, weiß ich auch, aber in anbetracht meiner langfristigen Ambitionen was programmieren angeht, bin ich nicht sooo motiviert mich in die Tiefen von C++ reinzufressen.

    Ich beiße mich anhand von Online Tutorials und der C++ Referenzseite durch, templates habe ich bisher nicht genutzt. Ich nutze dann eher die Möglichkeit Funktionen zu schreiben, die das machen (und auch nur das können) was ich brauche.


Anmelden zum Antworten