diff --git a/main.c b/main.c index 4bad51f..c84ae08 100644 --- a/main.c +++ b/main.c @@ -5,351 +5,419 @@ #include #include +/** + * Hilfsmakro für {@code STR(X)} + */ #define _STR(X) #X +/** + * Makro das den gegebenen Wert in einen String convertiert + */ #define STR(X) _STR(X) +/** + * Die maximal erlaubte Länge eines Dateipfads + */ #define MAX_FILE_PATH_LENGTH FILENAME_MAX +/** + * Die maximal erlaubte Größe einer Matrix + */ #define MAX_MATRIX_SIZE 500 +/** + * Die maximale Anzahl von verketteten doubles in den Dateien + */ #define MAX_MATRIX_IN_FILE_SIZE (MAX_MATRIX_SIZE + 2) +/** + * Maximale Zahl der Iterationsschritte + */ #define MAX_ITERATION_STEPS 100 +/** + * Die Struktur zur Speicherung von Matrizen. Speicherplatz für die Daten muss dynamisch als Pointer-Array allokiert werden. + */ typedef struct { int n; double** data; } Matrix; +/** + * Erstellt eine neue Matrix-Struktur der Größe 0 mittels dynamischer Speicher-Allokation. + * @return Ein Zeiger auf die neue Struktur. + */ Matrix* createMatrix(void); +/** + * Gibt den Speicherplatz einer dynamisch allokierten Matrix wieder frei. + */ void freeMatrix(Matrix* matrix); +/** + * Füllt eine Matrix mit {@code rows} Zeilen. + */ void createMatrixRows(Matrix* matrix, int rows); +/** + * Schreibt eine Matrix in die Konsole. + */ void printMatrix(Matrix* matrix); +/** + * Die Struktur zur Speicherung von Vektoren. Speicherplatz für die Daten muss dynamisch allokiert werden. + */ typedef struct { int n; double* data; } Vector; +/** + * Erstellt eine neue Vektor-Struktur der Größe 0 mittels dynamischer Speicher-Allokation. + * @see initVector + * @return Ein Zeiger auf die neue Struktur + */ Vector* createVector(void); +/** + * Allokiert den Speicher für einen {@code size} großen Vektor. + * @param vector ein Zeiger auf einen nicht initialisierten Vektor + * @param size die Größe des Vektors + */ void initVector(Vector* vector, int size); +/** + * Gibt den Speicherplatz eines dynamisch allokierten Vektors wieder frei. + * @param vector ein Zeiger auf den freizugebenden Vektor + */ void freeVector(Vector* vector); +/** + * Schreibt einen Vektor in die Konsole. + * @param vector ein Zeiger auf den Vektor + */ void printVector(Vector* vector); +/** + * Die Auflistung aller erlaubten Berechnungs-Algorithmen. + */ typedef enum { JACOBI = 0, GAUSS_SEIDEL = 1 } Method; +/** + * Beseitigt nicht eingelesene Daten aus der Konsoleneingabe. + */ void flushStdin(void); +/** + * Hauptfunktion die eine Matrix und zwei Vektoren aus der gegebenen Datei lädt und in den durch Zeiger gegebenen Strukturen speichert. + * @param filename Dateipfad zu der Datei. Unter Windows immer absolut, unter Linux auch relativ. + * @param A Ein Zeiger auf eine leere Matrix + * @param b Ein Zeiger auf einen leeren Vektor + * @param x Ein Zeiger auf einen leeren Vektor + * @return Gibt an ob die Daten erfolgreich geladen wurden + */ bool load(const char* filename, Matrix* A, Vector* b, Vector* x); +/** + * Hauptfunktion die das durch eine Matrix und einen Vektor gegebene LGS mit einem bestimmten Startwert löst. + * @param mmethod Der Algorithmus, der zur Lösung verwendet werden soll. + * @param A Die Koeffizienten der Unbekannten gegeben als Zeiger auf die Matrix + * @param b Die konstanten Glieder der Gleichungen gegeben als Zeiger auf den Vektor + * @param x Ein Zeiger auf einen Vektor mit Startwerten + * @param e Die Genauigkeit, auf die die Lösung bestimmt werden soll + * @return {@code NULL} bei Fehlern. Ansonsten ein Vektor-Array der Größe {@code MAX_ITERATION_STEPS + 1}. Das Array beginnt mit dem Startwert und endet vorzeitig mit einem Vektor der Größe {@code 0}. + */ Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e); +/** + * Liest ein double-Array aus der gegebenen Datei. + * @param file Ein Zeiger auf die Datei + * @param matrixLine Ein double-Array der Länge {@code maxCols} oder größer + * @param maxCols die maximal zu lesende Anzahl an doubles + * @return Die Anzahl der gelesenen doubles. Negativ wenn ein Fehler aufgetreten ist + */ int readMatrixLine(FILE* file, double* matrixLine, int maxCols); int main(int argc, char* argv[]) { - char filePath[MAX_FILE_PATH_LENGTH]; + char filePath[MAX_FILE_PATH_LENGTH + 1]; // char-Array zum Speichern des Dateipfads (1 char mehr für '\0') - if(argc >= 2) { - strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH); + if(argc >= 2) { // Wenn Argumente übergeben wurden + strncpy(filePath, argv[1], MAX_FILE_PATH_LENGTH); // Das erste Argument wird (auf MAX_FILE_PATH_LENGTH gekürzt) in filePath kopiert } else { puts("Please enter the path of the file you'd like to open"); - int result = scanf("%s" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath); - if(result == EOF || result == 0 || filePath[0] == 0) { + int result = scanf("%" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath); // Liest MAX_FILE_PATH_LENGTH Zeichen aus der Konsole bis zum ersten Zeilenumbruch + if(result == EOF || result == 0 || filePath[0] == 0) { // Wenn Nichts gelesen werden konnte wird das Programm erfolgreich beendet return 0; } - if(result != 1) { + if(result != 1) { // Wenn ein Fehler beim Lesen aufgetreten ist wird das Programm mit Fehlermeldung beendet fputs("Couldn't read file path - stopping\n", stderr); return 1; } - flushStdin(); + flushStdin(); // Die Konsoleneingabe wird bereinigt } + // Speicherallokation für die Matrix und die Vektoren Matrix* matrix = createMatrix(); Vector* b = createVector(); Vector* x = createVector(); - int returnCode = 0; - - while(true) { - if(load(filePath, matrix, b, x)) { - - // Debug outputs - //puts("Data successfully loaded\nMatrix A:"); - //printMatrix(matrix); - //puts("Vector b:"); - //printVector(b); - //puts("Vector x:"); - //printVector(x); + int returnCode = 0; // Variable um den Rückgabewert an das Programmende zu liefern + while(true) { // Endlosschleife, die durch Erfolg oder Fehler beendet wird + if(load(filePath, matrix, b, x)) { // Versucht die Daten zu laden puts("Please enter the algorithm to use:\n\t0: Jacobi (default)\n\t1: Gauss-Seidel"); - int algorithm; + int algorithm; // int-Variable um Eingabewerte zwischenzuspeichern - while(true) { - algorithm = getchar(); - if(algorithm == EOF) { + while(true) { // Endlosschleife, die durch erfolgreiche Eingabe oder Programmfehler beendet wird + algorithm = getchar(); // Nutzereingabe + if(algorithm == EOF) { // Bei der Eingabe ist ein Fehler aufgetreten + returnCode = 20; goto end; } - if(algorithm == '\n' || algorithm == 0) { + if(algorithm == '\n' || algorithm == 0) { // Wenn der Nutzer nichts eingegeben hat puts("Defaulting to Jacobi"); - algorithm = 0; - break; + algorithm = JACOBI; // Standardalgoritmus: JACOBI + break; // Verlassen der Schleife } - flushStdin(); - if(algorithm == '0' || algorithm == '1') { - algorithm -= '0'; - break; + flushStdin(); // Konsoleneingabe bereinigen + if(algorithm == '0' || algorithm == '1') { // Wenn die Eingabe gültig ist + algorithm -= '0'; // Algorithmusnummer wird bestimmt + break; // Verlassen der Schleife } - fputs("Please enter 0, 1 or leave empty to exit!\n", stderr); + fputs("Please enter 0, 1 or leave empty to exit!\n", stderr); // Fehlermeldung } puts("Please enter the precision to use:"); - double e; - int scan; + double e; // Variable für die Algorithmusgenauigkeit + int scan; // Variable zum Speichern des scanf Rückgabewerts while(true) { - scan = scanf("%lf", &e); - if(scan == EOF) { + scan = scanf("%lf", &e); // Eingabe eines doubles + if(scan == EOF) { // Fehler bei der Eingabe + returnCode = 20; goto end; } - flushStdin(); - if(scan == 1) { + flushStdin(); // Konsoleneingabe bereinigen + if(scan == 1) { // Bei erfolgreicher Eingabe die Schleife verlassen break; } - fputs("Invalid input - please enter a valid floating point number!\n", stderr); + fputs("Invalid input - please enter a valid floating point number!\n", stderr); // Fehlermeldung } - Vector* result = solve(algorithm, matrix, b, x, e); + Vector* result = solve(algorithm, matrix, b, x, e); // Ausführung des Algorithmus - if(result == NULL) { - puts("Given equation system doesn't converge!\nEnter 0 to repeat the program (default) or 1 to exit"); - algorithm = getchar(); + if(result == NULL) { // Beim Auftritt eines Fehlers + puts("Given equation system doesn't converge!\nEnter 0 to repeat the program (default) or 1 to exit"); // Fehlermeldung und Auswahlmöglichkeiten + algorithm = getchar(); // Benutzereingabe - if(algorithm != '\n' && algorithm != 0) { - flushStdin(); - if(algorithm == '1') { - returnCode = 10; + if(algorithm != '\n' && algorithm != 0) { // Wenn Eingabe nicht leer war + flushStdin(); // Konsoleneingabe bereinigen + if(algorithm == '1') { // Bei Auswahl der Beendigung Programm erfolgreich beenden goto end; } } } else { - puts("Solution found!\nEnter 0 to just print the solution (default) or 1 to print the whole sequence of iteration steps!"); - algorithm = getchar(); - if(algorithm != '\n' && algorithm != 0) - flushStdin(); - if(algorithm == '1') { - int i = 0; - do { - printVector(&result[i]); - free(result[i].data); + puts("Solution found!\nEnter 0 to just print the solution (default) or 1 to print the whole sequence of iteration steps!"); // Auswahlmöglichkeiten + algorithm = getchar(); // Benutzereingabe + if(algorithm != '\n' && algorithm != 0) // Wenn Eingabe nicht leer + flushStdin(); // Konsoleneingabe bereinigen + if(algorithm == '1') { // Alle Schritte ausgeben + int i = 0; // Zählervariable + do { // Solange wie der aktuelle Vektor nicht leer ist und das Array nicht zu Ende ist + printVector(&result[i]); // Vektor ausgeben + free(result[i].data); // Speicher freigeben } while(result[++i].n != 0 && i <= MAX_ITERATION_STEPS); - free(result); + free(result); // Schließlich den Speicher des Arrays freigeben } else { - int i = 0; - while(result[++i].n != 0 && i < MAX_ITERATION_STEPS) { - free(result[i - 1].data); + int i = 0; // Zählervariable (erstes Element wird durch kopfgesteurte Schleife nicht überprüft) + while(result[++i].n != 0 && i < MAX_ITERATION_STEPS) { // Solange wie der aktuelle Vektor nicht leer ist und das Array nicht zu Ende ist + free(result[i - 1].data); // Speicher des vorherigen Vektors } - printVector(&result[i-1]); - free(result); + printVector(&result[i-1]); // Ausgabe des letzten existierenden Vektors + free(result[i-1].data); // Speicher der letzten existierenden Vektordaten wird freigegeben + free(result); // Vektoren werden freigegeben } - break; + break; // Hauptschleife verlassen } - } else { + } else { // Datei konnte nicht geladen werden fputs("Failed to load data from file.\n", stderr); } puts("Enter file path or leave empty to exit"); - int result = scanf("%" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath); - if(result == EOF || result == 0 || filePath[0] == 0) { + int result = scanf("%" STR(MAX_FILE_PATH_LENGTH) "[^\n]", filePath); // Erneute Abfrage des Dateipfads + if(result == EOF || result == 0 || filePath[0] == 0) { // Wenn Eingabe leer ist goto end; } - if(result != 1) { + if(result != 1) { // Wenn Fehler bei der Eingabe aufgetreten ist fputs("Couldn't read file path - stopping\n", stderr); returnCode = 1; goto end; } - flushStdin(); + flushStdin(); // Konsoleneingabe bereinigen } end: + // Matrix- und Vektorspeicher freigeben freeMatrix(matrix); freeVector(b); freeVector(x); - printf("\nReturning with code %i\n", returnCode); + printf("\nReturning with code %i\n", returnCode); // Den Rückgabewert anzeigen return returnCode; } bool load(const char* filename, Matrix* matrix, Vector* b, Vector* x) { - FILE* file = fopen(filename, "r"); - if(file == NULL) { + FILE* file = fopen(filename, "r"); // Die gegebene Datei zum Lesen öffnen + if(file == NULL) { // Beim Auftritt eines Fehlers -> Laden ist fehlgeschlagen fprintf(stderr, "Failed to open file \"%s\"\n", filename); return false; } else { + // Erste Zeile der Datei wird mit Maximalgröße gelesen double* firstLineBuffer = malloc(sizeof(double) * (MAX_MATRIX_IN_FILE_SIZE)); + int colsInFile = readMatrixLine(file, firstLineBuffer, MAX_MATRIX_IN_FILE_SIZE); // Zeile lesen und Anzahl der gelesenen Werte speichern - int colsInFile = readMatrixLine(file, firstLineBuffer, MAX_MATRIX_IN_FILE_SIZE); - - if(colsInFile == -1) { + if(colsInFile == -1) { // Es konnte kein double gelesen werden fputs("Unexpected input on line 0", stderr); - - free(firstLineBuffer); - goto failure; - } else if(colsInFile == -2) { + free(firstLineBuffer); // Speicher freigeben + goto failure; // Zum Fehlerlabel springen + } else if(colsInFile == -2) { // Die Zeile war länger als die Maximalgröße erlaubt fprintf(stderr, "Exceeded maximum matrix size of %i\n", MAX_MATRIX_SIZE); - free(firstLineBuffer); - goto failure; - } else { - // success - int cols = colsInFile - 1; - initVector(b, cols); + goto failure; // Zum Fehlerlabel springen + } else { // Erfolgreich gelesen + int cols = colsInFile - 1; // Tatsächliche Größe der Matrix/Vektoren ist um eins kleiner, da zumindest b mit eingelesen wurde + initVector(b, cols); // Vektoren werden initialisiert initVector(x, cols); - b->data[0] = firstLineBuffer[cols]; - createMatrixRows(matrix, cols); - matrix->data[0] = firstLineBuffer; + b->data[0] = firstLineBuffer[cols]; // b0 enthält den letzten Eintrag der ersten Zeile + createMatrixRows(matrix, cols); // Matrix wird mit cols Zeilen angelegt (nur das Haupt-Array - die Einträge sind nicht initialisiert) + matrix->data[0] = firstLineBuffer; // Erste Matrix-Zeile entspricht erster eingelesener Zeile. b-Wert ist irrelevant da durch Matrix-Größe die erste Zeile vorher endet - int colsInLine; - for(int i = 1; i < cols; i++) { - matrix->data[i] = malloc(sizeof(double) * (colsInFile)); - colsInLine = readMatrixLine(file, matrix->data[i], colsInFile); - if(colsInLine < 0) { - if(i == cols - 1) { + int colsInLine; // Variable zum Speichern der pro Zeile eingelesenen Einträge + for(int i = 1; i < cols; i++) { // Einlesen von cols Zeilen + matrix->data[i] = malloc(sizeof(double) * (colsInFile)); // Matrix Zeile wird initialisiert + colsInLine = readMatrixLine(file, matrix->data[i], colsInFile); // Nächste Zeile in Matrix einlesen + if(colsInLine < 0) { // Wenn ein Fehler beim Einlesen aufetreten ist + if(i == cols - 1) { // Wenn die vermeintlich letzte Zeile erreicht ist und ein Fehler auftritt, dann wird davon ausgegangen, dass x-Werte übergeben wurden puts("Optional parameters are being used"); - // Matrix is one smaller than assumed - cols--; - b->n--; + cols--; // Die tatsächliche Matrixgröße ist also eins geringer + b->n--; // Ebenso für die Vektoren x->n--; matrix->n--; - free(matrix->data[i]); + free(matrix->data[i]); // der bereits allokierte Speicher kann wieder freigegeben werden - x->data[0] = 0.4; + // Die letzte Spalte (derzeit b) ist eigentlich x, die Zeiger auf die Daten können also getauscht werden + { + double* temp = x->data; + x->data = b->data; + b->data = temp; + } - // Copy b to x - memcpy(x->data, b->data, b->n * sizeof(double)); - - // extract b + // b wird nun aus der zugehörigen Spalte in der Matrix ausgelesen for(int j = 0; j < cols; j++) { b->data[j] = matrix->data[j][cols]; } - goto success; - } else { - fprintf(stderr, "Line %i contains illegal formatting - please fix!\n", i + 1); - goto failure; + goto success; // Ausführung erfolgreich beendet + } else { // Unerwarteter Fehler ist aufgetreten + fprintf(stderr, "Line %i contains illegal formatting - please fix!\n", i + 1); // Fehlermeldung + goto failure; // Abbruch } - } else if(colsInLine != colsInFile) { - fprintf(stderr, "Illegal line length found in line %i\n", i + 1); - goto failure; - } else { - b->data[i] = matrix->data[i][cols]; + } else if(colsInLine != colsInFile) { // Die Anzahl der gelesenen Spalten stimmt nicht mit der Erwartung überein + fprintf(stderr, "Illegal line length found in line %i\n", i + 1); // Fehlermeldung + goto failure; // Abbruch + } else { // Erfolgreiches Einlesen + b->data[i] = matrix->data[i][cols]; // b-Wert auslesen } - } - // successful but with no optional parameter + } // Ende Schleife - // initialize vector x with zeros + // Da an dieser Stelle keine x-Werte gelesen wurden, wird x mit Nullen initialisiert memset(x->data, 0, cols * sizeof(double)); - } } -success: - fclose(file); +success: // Erfolgslabel + fclose(file); // Die Datei wird geschlossen return true; -failure: - fclose(file); +failure: // Fehlerlabel + fclose(file); // Die Datei wird geschlossen return false; } int readMatrixLine(FILE* file, double* matrixLine, int maxCols) { - char nextChar = 0; - int col = 0; - double buffer; + char nextChar = 0; // Variable für den nächsten zu verarbeitenden char + int col = 0; // Die Anzahl gelesener Werte - while(true) { - if(fscanf(file, "%lf", &buffer) != 1) { - return -1; + do { // Solange wie Kommas als Trennzeichen gelesen werden + if(fscanf(file, "%lf", &matrixLine[col]) != 1) { // In das Array wird ein double-Wert eingelesen + return -1; // Es konnte kein double gelesen werden } - matrixLine[col] = buffer; - - col++; - if(col > maxCols) { - return -2; + col++; // Gelesene Werte erhöhen + if(col > maxCols) { // Wenn zu viele Werte gelesen wurden + return -2; // Fehlerrückgabe } - nextChar = fgetc(file); - if(nextChar == EOF || nextChar == '\n') break; - } - return col; + nextChar = fgetc(file); // nächstes Trennzeichen einlesen + } while (nextChar == ','); + return col; // Anzahl gelesener Werte zurückgeben } void flushStdin(void) { - int c; - while((c = getchar()) != '\n' && c != EOF && c != 0); + int c; // Buffer-Variable + while((c = getchar()) != '\n' && c != EOF && c != 0); // Solange das Konsoleneingabe-Ende noch nicht erreicht ist werden einzelne chars eingelesen } Vector* solve(Method method, Matrix* A, Vector* b, Vector* x, double e) { - Vector* vectors = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); + Vector* vectors = malloc(sizeof(Vector) * (MAX_ITERATION_STEPS + 1)); // Historie der Iterationsschritte/Rückgabe-Array - initVector(&vectors[0], b->n); - memcpy(vectors[0].data, x->data, b->n * sizeof(double)); + initVector(&vectors[0], b->n); // Erster Vektor wird initialisiert... + memcpy(vectors[0].data, x->data, b->n * sizeof(double)); // ...und mit den Werten aus x gefüllt - int vectorCount = 1; - double temp; - double delta = 0.0; + int vectorCount = 1; // Länge existierender Vektoren in vectors + double temp; // Temporäre Variable zur Berechnung + double delta; // Abweichung der Iterationsschritte - zur Genauigkeitsberechnung if (method == JACOBI){ - do { + do { // Solange wie die Abweichung größer als die Genauigkeit ist delta = 0.0; - initVector(&vectors[vectorCount], b->n); - for(int i = 0; i < b->n; i++){ - temp = 0.0; - for(int j = 0; j < b->n; j++){ - if(j != i){ + initVector(&vectors[vectorCount], b->n); // Vektor an aktueller Position initialisieren + + for (int i = 0; i < b->n; i++) { // Iteration über alle Zeilen + temp = 0.0; // temp wird zur Summenbildung verwendet + for (int j = 0; j < b->n; j++) { // für alle Spalten, die nicht auf der Diagonale liegen + if (j != i){ temp = temp + A->data[i][j] * vectors[vectorCount - 1].data[j]; } } - vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; - delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); + vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; // Berechneten Wert in Historie aufnehmen + delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); // Berechnung der maximalen Abweichung durchführen } - vectorCount++; - if (vectorCount >= MAX_ITERATION_STEPS) - goto fail; + vectorCount++; // Größe der Historie erhöhen + if (vectorCount >= MAX_ITERATION_STEPS) // Wenn zu viele Iterationsschritte durchgeführt wurden + goto fail; // Fehlerbehandlung } while (delta > e); - } else { - do { + } else { // GAUSS-SEIDEL + do { // Solange wie die Abweichung größer als die Genauigkeit ist delta = 0.0; - if (vectorCount == 1){ - initVector(&vectors[vectorCount], b->n); - memcpy(vectors[vectorCount].data, x->data, b->n * sizeof(double));} - else { - initVector(&vectors[vectorCount], b->n); - memcpy(vectors[vectorCount].data, vectors[vectorCount - 1].data, b->n * sizeof(double));} + initVector(&vectors[vectorCount], b->n); // Vektor an aktueller Position initialisieren + memcpy(vectors[vectorCount].data, vectors[vectorCount - 1].data, b->n * sizeof(double)); // Werte des vorherigen Schrittes in den neuen Schritt kopieren - for (int i = 0; i < b->n; i++){ - temp = 0.0; - for (int j = 0; j < b->n; j++){ + for (int i = 0; i < b->n; i++) { // Iteration über alle Zeilen + temp = 0.0; // temp wird zur Summenbildung verwendet + for (int j = 0; j < b->n; j++) { // für alle Spalten, die nicht auf der Diagonale liegen if (j != i){ temp = temp + A->data[i][j] * vectors[vectorCount].data[j]; - } } - vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; - delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); + vectors[vectorCount].data[i] = (b->data[i] - temp) / A->data[i][i]; // Berechneten Wert in Historie aufnehmen + delta = fmax(fabs(vectors[vectorCount].data[i] - vectors[vectorCount - 1].data[i]), delta); // Berechnung der maximalen Abweichung durchführen } - vectorCount++; - if (vectorCount >= MAX_ITERATION_STEPS) - goto fail; + vectorCount++; // Größe der Historie erhöhen + if (vectorCount >= MAX_ITERATION_STEPS) // Wenn zu viele Iterationsschritte durchgeführt wurden + goto fail; // Fehlerbehandlung } while(delta > e); } - vectors[vectorCount].n = 0; + vectors[vectorCount].n = 0; // Abschließenden Vektor auf Größe 0 setzen return vectors; -fail: - for (int i = 0; i < vectorCount; i++) { +fail: // Fehlerlabel + for (int i = 0; i < vectorCount; i++) { // Allokierten Daten-Speicher freigeben free(vectors[i].data); } - free(vectors); + free(vectors); // Vektoren-Array freigeben return NULL; } @@ -365,11 +433,11 @@ inline void createMatrixRows(Matrix* matrix, int rows) { } inline void freeMatrix(Matrix* matrix) { - for(int i = 0; i < matrix->n; i++) { + for(int i = 0; i < matrix->n; i++) { // Gibt die Zeilen frei free(matrix->data[i]); } - free(matrix->data); - free(matrix); + free(matrix->data); // Gibt das Zeilen-Array frei + free(matrix); // Gibt das Matrix-Object frei } void printMatrix(Matrix* matrix) { diff --git a/test-data/3.csv b/test-data/3.csv new file mode 100644 index 0000000..0016896 --- /dev/null +++ b/test-data/3.csv @@ -0,0 +1,3 @@ +4,2,1,7,100 +2,4,1,7,200 +1,1,3,5,300