Fragen zu Datentyp und Array



  • Hallo.

    Ich habe ein kleines Stück Code mit welchem ich eine CSV-Datei einlese. Mein Problem ist, dass ich bei der Ausgabe in der Konsole falsche Zahlenwerte bekomme. Ich habe es mit verschiedenen Datentypen probiert, aber es hat mir jedesmal falsch dargestellt. Findet jemand mein Fehler? Meine andere Frage ist, ich habe nicht in jeder CSV-Datei eine bestimmte Länge von den Daten vorgegeben. Deshalb wollte ich wissen ob jemand eine elegante Lösung kennt wie ich mein Array so deklarieren kann, dass es sich der Dateigröße anpasst.
    Danke im Voraus

    #include<iostream>
    #include<fstream>
    
    using namespace std;
    
    int main()
    {
       ifstream in;
       in.open("Route.csv");
       int long lat[99], lon[99], ele[99];
    
       for (int i = 0; i < 23; i++) {
           in >> lat[i] >> lon[i] >> ele[i];
    	printf("Coord.: %ld, %ld, %ld \n",  lat[i], lon[i], ele[i]);
       }
       return 0;
    }
    

    CSV-Datei
    1.Zeile: Latitude;Longitude;Elevation
    2.Zeile: 4.755.035.480;9.729.761.481;404.0
    3.Zeile: ...

    Ausgabe in der Konsole
    Coord.: 0, 288268618540598560, 140666644349792
    Coord.: 140664473911296, 2104, 140666650117328
    ...



  • Das Problem tritt schon beim ersten Zeichen in der ersten Zeile auf.

    Das passt nicht zu einem long. Daher wird das Einlesen abgebrochen und das Zeichen zurückgestellt.

    Was du da ausgibst, ist der (zufällige) Inhalt deiner nicht initialisierten Arrays.

    Du musst die erste Zeile überlesen, die Tausendertrennzeichen (der .) und das CSV-Trennzeichen (das 😉 richtig behandeln



  • Hallo TL27, willkommen im Forum.

    Erstmal sei gesagt, dass printf aus C ist und in C++ geächtet wird, weil es nicht typsicher ist. Nutze stattdessen std::cout .
    Auch für das Array mit variabler Länge haben wir in C++ eine elegante Lösung: std::vector
    Wenn du die gelesenen Werte einfach direkt wieder ausgeben willst, dann musst du gar nichts speichern. Aber ich gehe davon aus, dass du sonst schon noch etwas damit anstellen möchtest.

    Wie du in der CSV-Datei siehst, bestehen die Koordinaten aus mehreren, durch Punkte getrennten Zahlen: 4.755.035.480
    Daraus folgt, dass ein einzelner long int nicht mehr hinreichend ist; du musst einen anderen Datentyp verwenden. Daher würde ich an deiner Stelle einen eigenen Typ definieren, der Längen- und Breitengrad speichern kann. Elevation hingegen würde ich als float speichern. Diese drei können wir dann wiederum zu einem eigenen Typ zusammenfassen: coordinate

    Damit du weißt, wovon ich spreche: Hier eine grobe Skizze des Codes:

    #include <iostream>
    #include <fstream>
    #include <limits>
    #include <vector>
    
    using namespace std;
    
    struct geodetic_itude {
    	int degrees;
    	int minutes;
    	float seconds;
    };
    ostream& operator<<(ostream& stream, geodetic_itude const& object) {
    	return stream << object.degrees << '.' << object.minutes << '.' << object.seconds;
    }
    istream& operator>>(istream& stream, geodetic_itude& object) {
    	// Code zum Einlesen hier
    	return stream;
    }
    
    struct coordinate {
    	geodetic_itude latitude;
    	geodetic_itude longitude;
    	float elevation;
    };
    ostream& operator<<(ostream& stream, coordinate const& object) {
    	return stream << object.latitude << ';' << object.longitude << ';' << object.elevation;
    }
    istream& operator>>(istream& stream, coordinate& object) {
    	// Code zum Einlesen hier
    	return stream;
    }
    
    int main()
    {
    	ifstream in;
    	in.open("Route.csv");
    	in.ignore(numeric_limits<streamsize>::max(), '\n'); // erste Zeile überspringen
    
    	std::vector<coordinate> coordinates;
    	for (coordinate c; std::cin >> c; coordinates.push_back(c))
    		std::cout << c << '\n';
    }
    

    LG



  • @DirkB Danke für die Tipps. Mir sind die Punkte zwischen den Zahlen nicht aufgefallen.
    Als ich mir die CSV-Datei runtergeladen habe und im Editor angeschaut habe waren die Punkte noch nicht vorhanden. Erst als ich die Datei in Excel geöffnet habe sind die Punkte nach dem speichern eingefügt worden.

    Jetzt würde mich interessieren ob in C++ eine Zahl mit einem Punkt als Gleitkommazahl erkannt wird?

    @Fytch vielen Dank, dass du dir so viel Mühe gemacht hast und ein Stück Code geschrieben hast. Ich hätte noch ein paar Fragen. Ich kenne mich mit den Vektor Funktionen nicht so aus und würde gerne wissen ob ich bei der Vektor Funktion auch nur die Elevation-Werte oder Lat-Werte ausgeben kann? Ich habe nämlich selber nur die Funktion gefunden, dass man z.B. den 6 Wert von meiner CSV-Datei ausgibt, aber nicht das man nur die die Inhalte von einer gewissen Spalte. Ich frage deshalb, weil ich wie du schon richtig vermutet hast, mit den Daten weiter arbeiten möchte. Und zwar wollte ich eine zweite CSV-Datei einlesen und mit der ersten CSV-Datei verschmelzen. Die zweite CSV-Datei hat ebenfalls lon und lat Werte und weitere Ortsangaben, aber leider nicht die ele-Daten.
    Deshalb möchte ich ein Programm schreiben, das mir die lon und lat Werte der beiden Dateien vergleicht und dann die dazugehörigen Daten zusammenfügt.



  • TL27 schrieb:

    Erst als ich die Datei in Excel geöffnet habe sind die Punkte nach dem speichern eingefügt worden.

    Dann solltest du die Datei in einem vernünftigen Format abspeichern (oder das Original belassen)

    TL27 schrieb:

    Jetzt würde mich interessieren ob in C++ eine Zahl mit einem Punkt als Gleitkommazahl erkannt wird?

    Der Punkt ist in der IT i.A das Dezimaltrennzeichen (also zwischen Vor- und Nachkommastellen). Daher kennzeichnet er auch eine Fließkommazahl.

    Bei deinem Format sieht das aber mehr nach dem Tausendertrennzeichen aus. Damit kann man leichter die Zahl erkennen.

    Möglicherweise hat Excel schon die Darstelllung zerstört, da es in der deutschen Spracheinstellung mit dem Komma als Dezimaltrennzeichen arbeitet. Da kommt es immer wieder zu unschönen Fällen, wenn Zahlen mit Punkt als Trennzeichen eingelesen werden.

    TL27 schrieb:

    Ich hätte noch ein paar Fragen. Ich kenne mich mit den Vektor Funktionen nicht so aus und ...

    Vector ist ein Datencontainer und soll dein Array ersetzen.
    Was du mit den Daten daraus machst, liegt in deinem Ermessen (als Programmierer).

    Ob du die Funktionen von Fytch nutzen kannst, hängt auch davon ab, wie dein Datenformat letztendlich wirklich aussieht.



  • boost::tokenizer zusammen mit boost::lexical_cast ist für diese Aufgabe wie geschaffen und schafft auch Typensicherheit 🙂

    Hier ein kleines, ungetestes, Beispiel:

    std::ifstream iStream("Beispiel.csv");
    while(!iStream.eof())
    {
            std::string line;
            std::vector<std::string> tokens;
    
            std::getline(iStream, line);
            const boost::char_delimiters_separator<char> separator(",");
            boost::tokenizer<> tokenizer(line, separator);
    
            for (auto it = tokenizer.begin(); it != tokenizer.end(); ++it)
            {
                tokens.push_back(*it);
            }
            if (!line.empty())
            { 
                int beispiel = boost::lexical_cast<int>(tokens[0]);
                float beispiel = boost::lexical_cast<float>(tokens[1]);
            }
    }
    


  • @DirkB Danke für deine Antwort. Ich denke ich habe mittlerweile die Vector Funktion soweit verstanden.
    @Scorcher24 Danke für dieses kleine Beispiel.


Log in to reply