Programmzugriff auf Textdatei
-
Hallo! Das ist meine erste Frage hier und ich hoffe,
dass mir Jemand weiterhelfen kann. Ich stelle diese Frage, weil ich mit meinem Programm nicht "falsch" anfangen möchte und mir noch Informationen für die Umsetzung fehlen.Mit meinem Programm möchte ich Matrizen aus einer Datei einlesen (beliebig viele) und sie später nach bestimmten Kriterien raussuchen und sortieren und ggf. in einer anderen Datei abspeichern. Die Matrizen liegen z.B. in dieser Form vor und können maximal 100x100 groß sein:
1 1 (größe der Matrix 1x1) (int-Werte)
2 (Element der Matrix) (double-Werte)2 2
3 1
1 3
. . .1. Problem: Da ist nicht weiß wieviel Speicher ich benötigen werde, muss ich diesen wohl dynamisch für ein Array der Größe, der Matrix reservieren lassen.
1. Frage: Wie sage ich meinem Programm am Besten, wieviel Speicher reserviert werden muss? Reicht die Auskunft über Zeile * Spalte, um den zu benötigenden Speicher auszurechnen und anschließend freizugeben oder gibt es bereits Funktionen, die mir das beim Einlesen abnehmen?
Und Somit komme ich auch zum
2. Problem: Wie lasse ich zwischen Größenangabe der Matrix und der Matrixelemente unterscheiden? Meine Idee war, dass die erste Zeile in der Datei immer eine Größenangabe ist (m * n) und ich dann m+1 Zeilen, in der Datei nach unten gehe um zur nächsten Größenangabe zu kommen. Wenn es eine bessere Methode dafür gibt, benutze ich die auch gerne, ansonsten müsste ich noch wissen wie ich in eine Datei überhaupt Zeile für Zeile einlesen kann bzw. wie die Funktion in C++ dafür heißt.Über Beispiele, ähnliche Fragen oder Hinweise zu bereits vorhandenen Funktionen würd' ich mich sehr freuen
Grüße

-
Werner wird mich nun vermutlich prügeln, weil ich zeilenweise parse, aber ein einfacher Ansatz wäre sowas:
std::ifstream reader("matrix.txt"); std::vector<std::vector<double> > matrix; for(std::string line; std::getline(reader, line, '\n'); ) { std::istringstream isstr(line); std::vector<double> row; for(double matrix_element; isstr >> matrix_element; ) { row.push_back(matrix_element); } matrix.push_back(row); } std::cout << "Number rows: " << matrix.size() << '\n'; std::cout << "Number cols: " << matrix[0].size() << '\n'; //Achtung: matrix kann leer sein. std::cout << "First element: " << matrix[0][0] << '\n'; //Achtung: matrix kann leer sein.
-
Hallo und Danke für die Antwort!
Habe es gerade mal getestet und versucht zu verstehen.
Also bisher gehe ich bis zur letzten Zeile in der Datei(=Number rows), egal ob nach der ersten Matrix noch eine Matrix kommt oder nicht.
Und ein Space wird immer als neue Spalte angesehen. Dadurch wirkt sich die Größenangabe z.B. " 1 1 " auf die Spalten der Matrix mit aus.
Bsp.: 1 1 (Größenangabe)
3 (Element)=> Spalten = 2
Das First Element ist bei mir dann einfach immer die erste Zahl in der Textdatei.
Mein Ziel ist es ja jetzt erstmal die einzelnen Matrizen inkl. Größenangabe als getrennte Objekte anzusehen mit denen ich später noch arbeiten kann.
Ist das über diesen Weg überhaupt möglich? Wenn ja muss ich es mir wohl nochmal gründlicher anschauen.
Mit dieser Zeile hier habe ich auch Probleme:
std::vector<std::vector<double> > matrix;Gruß
-
Kleiner Vorschlag: Nimm für die Spalten ein
std::array, da die Anzahl der Spalten (also der Eigenschaften einer Entity) ja schon vorher feststehen müssten.std::vector<std::vector<double> > matrix;Wie du sicher wissen solltest, kann man als Template-Parameter jeden Typ übergeben **(**ob es dann kein
static_asserto.ä. gibt, ist eine andere Frage
, und nebenbei sei auch bemerkt dass Container bestimmte Anforderungen an die übergebenen Typen stellen (die auch von den benutzten Funktionen abhängen)), also auch Klassen. In diesem Fall wird einfach ein vector mit vectors gefüllt, die wiederum mit Fließkommazahlen gefüllt werden (ein einfaches Multi-Dimensionales Array).
-
In diesem Fall wird einfach ein vector mit vectors gefüllt, die wiederum mit Fließkommazahlen gefüllt werden (ein einfaches Multi-Dimensionales Array).
Nein, das sollte man eher als Liste von Listen betrachten und nicht als multidimensionales Array. Mag zwar wie Haarspalterei klingen, ist aber ein Unterschied.
-
Ethon schrieb:
In diesem Fall wird einfach ein vector mit vectors gefüllt, die wiederum mit Fließkommazahlen gefüllt werden (ein einfaches Multi-Dimensionales Array).
Nein, das sollte man eher als Liste von Listen betrachten und nicht als multidimensionales Array. Mag zwar wie Haarspalterei klingen, ist aber ein Unterschied.
Ja, du hast recht, ist es weil die Länge der Listen nicht festgelegt ist? Wäre es ein MD-Array, wenn es statt
std::vector std::arrayverwendet hätte?
-
Hacker schrieb:
Ethon schrieb:
In diesem Fall wird einfach ein vector mit vectors gefüllt, die wiederum mit Fließkommazahlen gefüllt werden (ein einfaches Multi-Dimensionales Array).
Nein, das sollte man eher als Liste von Listen betrachten und nicht als multidimensionales Array. Mag zwar wie Haarspalterei klingen, ist aber ein Unterschied.
Ja, du hast recht, ist es weil die Länge der Listen nicht festgelegt ist? Wäre es ein MD-Array, wenn es statt
std::vector std::arrayverwendet hätte?Ich würde es immer als multidimensionales Array bezeichnen, da ich für mich Zeilen und Spalten betrachte.
Wenn du
vector<vector>hast, ist sowohl Anzahl Zeilen als auch die Anzahl Spalten dynamisch:6 3 7 2 4 6 7 3 1 6 2 5 . . . . . . . .Wenn du
vector<array>hast, ist die Zeilenanzahl dynamisch und die Spaltenanzahl statisch:6 3 4 6 7 3 . . . . . .Wenn du
array<array>hast, ist sowohl die Anzahl Zeilen als auch die Anzahl Spalten statisch:6 3 4 6 7 3
-
Gugelmoser schrieb:
Hacker schrieb:
Ethon schrieb:
In diesem Fall wird einfach ein vector mit vectors gefüllt, die wiederum mit Fließkommazahlen gefüllt werden (ein einfaches Multi-Dimensionales Array).
Nein, das sollte man eher als Liste von Listen betrachten und nicht als multidimensionales Array. Mag zwar wie Haarspalterei klingen, ist aber ein Unterschied.
Ja, du hast recht, ist es weil die Länge der Listen nicht festgelegt ist? Wäre es ein MD-Array, wenn es statt
std::vector std::arrayverwendet hätte?Ich würde es immer als multidimensionales Array bezeichnen, da ich für mich Zeilen und Spalten betrachte.
Wenn du
vector<vector>hast, ist sowohl Anzahl Zeilen als auch die Anzahl Spalten dynamisch:6 3 7 2 4 6 7 3 1 6 2 5 . . . . . . . .Wenn du
vector<array>hast, ist die Zeilenanzahl dynamisch und die Spaltenanzahl statisch:6 3 4 6 7 3 . . . . . .Wenn du
array<array>hast, ist sowohl die Anzahl Zeilen als auch die Anzahl Spalten statisch:6 3 4 6 7 3Das ist mir sehr klar. Ich schlug Variante Zwei vor.
Allerdings hat Ethon IMO Recht. Denn eine Liste ist ja nicht auf Länge beschränkt. Also würde ich erst Variante Zwei/Drei als Zweidimensionales Array ansehen.
-
Hi,
Ich bin jetzt etwas verwirrt.
Ich lese die Datei zeilenweise ein. Und wie ich mir zu Beginn schon überlegt habe, erkenne ich die Matrix daran, dass sie einfach nach der Größenangabe kommt. Die Größenangabe steht ganz am Anfang der Datei. Beim ersten mal gehen die Matrixelemente also bei Stelle matrix[1][0] los. Die nächste Größenangabe kommt dann bei Zeile(größenangabe)+2. (Zwischen den Matrizen ist immer eine Zeile frei).
Ich schaffe es nicht den Codeausschnitt so umzuschreiben, dass die Matrizen ersteinmal getrennt sind.
-> Deshalb wollte ich jetzt VisualStudio10 benutzen und Schritt für Schritt durch den Code. Vielleicht habe ich ihn immernoch nicht ganz verstanden.
Da bekomme ich allerdings folgende Meldung beim Ausführen des Programms:"include\vector Line:932 Expression: vector subscript out of range."
Includes sind bei mir #include <iostream> #include <fstream> #include <sstream>
#include <vector> #include <conio.h>
und using namespace std; habe ich auch mal dazu. Und er meckert schon beim unveränderten Code, der zuvor bei Dev-Cpp keine probleme gemacht hat.
-
Hallo Elliot000,
ich habe mal eine Neuauflage gemacht, weil ich befürchte, dass dein Quellcode grausig ist. Falls du Fragen zu folgendem Quellcode hast, schieß los.#include <iostream> #include <iterator> #include <fstream> #include <vector> using namespace std; // Diese Klasse muss dich eigentlich nicht interessieren. // Du kannst sie benutzen wie ein normales zweidimensionales Array, außer dass du statt // dem Zugriffsoperator [zeile][spalte] (zeile,spalte) schreiben musst. template<typename T> class array_2d { private: vector<T> data; unsigned sy; unsigned sx; public: array_2d(unsigned y, unsigned x) : data(y*x), sy(y), sx(x) { } const T& operator()(unsigned y, unsigned x) const { return data[y*size_x() +x]; } T& operator()(unsigned y, unsigned x) { return data[y*size_x() +x]; } unsigned size_y() const { return sy; } unsigned size_x() const { return sx; } }; // Alle Matrizen einlesen. typedef array_2d<double> matrix; ifstream& operator>>(ifstream& file, vector<matrix>& matrizen) { for(unsigned zeilen=0, spalten=0; file>>zeilen>>spalten;) // Anzahl Zeilen und Spalten einer Matrix einlesen. { matrix m(zeilen,spalten); // Leere Matrix erzeugen. // Matrix füllen. for(unsigned z=0; z<zeilen; ++z) { for(unsigned s=0; s<spalten; ++s) { double wert; file >> wert; // Ein Wert der Matrix einlesen. m(z,s) = wert; // Eingelesener Wert entsprechend abspeichern. } } // Gefüllte Matrix abspeichern. matrizen.push_back(m); } return file; } int main() { /* Aufbau der Textdatei: 1 1 2 2 2 3 1 1 3 3 3 1 2 3 4 5 6 7 8 9 */ ifstream file("test.txt"); if( !file.is_open() ) { cerr << "failed to open file"; return -1; } // Alle Matrizen einlesen. vector<matrix> matrizen; file >> matrizen; // Testausgaben for(vector<matrix>::iterator it=matrizen.begin(); it!=matrizen.end(); ++it) { matrix m = *it; for(unsigned zeilen=0; zeilen!=m.size_y(); ++zeilen) { for(unsigned spalten=0; spalten!=m.size_x(); ++spalten) { cout << m(zeilen,spalten) << ' '; } cout << '\n'; } cout << '\n'; } return 0; }