sadly I haven't been able to fix my issue, even after long searches online.
C - GNU GCC on Linux (the code works (sometimes) with mingw on Windows 10)
I have some structs, containing coefficients and values for a linear equation system.
I allocate them, work with them, don't change them, and want to free them in the end to allow a new runthrough.
I do however get a "double free or corruption (out)" in the marked code locations.
Does someone know how to fix this?
(I really am thinking about leaving a memory leak, since I wasted so much time on this...)
Thank you very much in advance!
typedef struct
{
int n;
double **data;
} Matrix;
typedef struct
{
int n;
double *data;
} Vector;
typedef enum
{
JACOBI = 0,
GAUSS_SEIDEL = 1
} Method;
typedef struct Listelement Listelement;
struct Listelement //list containing all results
{
int n;
Vector *dat;
Listelement *next;
};
bool load(const char *filename, Matrix *A, Vector *b, Vector *x)
{
...int row;
//row = number of equations
A->n = row;
A->data = malloc(row * sizeof(double *));
for (i = 0; i < row; i++)
{
A->data[i] = malloc(row * sizeof(double));
}
//Vektor b
b->n = row;
b->data = malloc(row * sizeof(double));
//Vektor x
x->n = row;
x->data = malloc(row * sizeof(double));
//structures are then looped over and filled with data
//e.g.: sscanf(tok, "%lf", &out);
// A->data[j][i] = out;
//sscanf(tok, "%lf", &out);
// b->data[j] = out;
}
//data in structures is only used for calculations and, except for vector x, never changed
int main(){
...Matrix *A;
Vector *b;
Vector *x;
...
A = malloc(sizeof(Matrix));
b = malloc(sizeof(Vector));
x = malloc(sizeof(Vector));
if (load(filename, A, b, x)){
......
//after successful calculation: ask for user intentions on restarting and or stopping the application
for (int k = 0; k < A->n; k++)
{
free(A->data[k]); //ERROR on any other value than k=0!
}
free(A->data);
A->n = 0;
free(A);
//free List
Listelement *l1 = malloc(sizeof(Listelement));
Listelement *l2 = malloc(sizeof(Listelement));
l1 = result; //start with head
while (l1 != l1->next) //iterate entire list
{
l2 = l1->next;
free(l1->dat->data);
l1->dat->n = 0;
free(l1->dat);
l1->n = 0;
free(l1);
l1 = l2;
}
//free Vectors
free(x->data); //ERROR crashed here for a bit, but not reproducable for me now
x->n = 0;
free(x);
free(b->data); //ERROR crashes here
b->n = 0;
free(b);
}
}
EDIT: Since requested, my entire code:
#include <stdio.h>
#include <stdbool.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#define _GNU_SOURCE
//für Umlaute in der Windowskonsole
/*
#define AE (unsigned char)142
#define ae (unsigned char)132
#define OE (unsigned char)153
#define oe (unsigned char)148
#define UE (unsigned char)154
#define ue (unsigned char)129
#define ss (unsigned char)225
*/
typedef struct
{
int n;
double **data;
} Matrix;
typedef struct
{
int n;
double *data;
} Vector;
typedef enum
{
JACOBI = 0,
GAUSS_SEIDEL = 1
} Method;
typedef struct Listelement Listelement;
struct Listelement //verkettete Liste zum Speichern der Ergebnisse
{
int n; //anzahl der gespeicherten Vektoren (nur im Head aktuell)
Vector *dat;
Listelement *next;
};
bool load(const char *filename, Matrix *A, Vector *b, Vector *x) //csv Datei einlesen und Datenstrukturen allokieren und füllen
{
char *str = malloc(sizeof(char) * 10000); //Einlesebuffer - 10000 Zeichen für sehr lange dateien als Grenze
char *tok; //Zeichen zwischen den Kommas (eigentliche Werte)
double out; //ausgelesener Wert
int row = 0, col = -1, i, j; //Anzahl der Zeilen & der Spalten in der Datei, zwei Laufvariablen
bool lnempty; //Laufzeitcheck ob gelesene Zeile leer ist
FILE *fp = fopen(filename, "r");
if (fp == NULL)
{
printf("Die Datei %s konnte nicht gefunden werden\n", filename);
return false;
}
while (fgets(str, 10000, fp) != NULL) //solange noch Zeilen eingelesen werden können
{
i = 0;
lnempty = false;
while (isspace(str[i])) //solange char at i whitespace ist - nächsten char checken
{
i++;
}
if (str[i] == '\0') //wenn alle chars außer das Ende whitespace sind - lnempty
lnempty = true;
if (!lnempty) //counting lines and validating file
{
i = 0;
row++;
tok = strtok(str, ","); //tok ist unterstring von , zu ,
while (tok != NULL)
{
if (sscanf(tok, "%lf", &out) != 1) //überprüfen ob in double konvertiert werden kann
{
printf("Fehler bei [%d][%d]!\n", row + 1, i + 1);
return false;
}
i++;
tok = strtok(NULL, ","); //nächsten Wert zwischen den kommas einlesen
}
if (col == -1) //anfangswert auf aktuelle cols setzen
col = i;
if (i != col) //wenn cols nicht konstant - Fehler
{
printf("i:%d col:%d Das eingegebene GLS hat unterschiedlich viele Angaben pro Zeile!\n", i, col);
return false;
}
}
}
if (!(col == row + 1 || col == row + 2) || row <= 0 || col <= 0) //berechenbare Form überprüfen
{
printf("Das eingegebene GLS ist nicht in der gewünschten Form!\n");
return false;
}
//Matrix und Vektoren allocieren
//Matrix
A->n = row;
A->data = malloc(row * sizeof(double *));
for (i = 0; i < row; i++)
{
A->data[i] = malloc(row * sizeof(double));
}
//Vektor b
b->n = row;
b->data = malloc(row * sizeof(double));
//Vektor x
x->n = row;
x->data = malloc(row * sizeof(double));
//füllen
j = 0;
rewind(fp); //Datei wieder auf anfang zurücksetzen
while (fgets(str, 10000, fp) != NULL) //gleiche Funktion wie zum checken, nur diesmal daten bereits in Strukturen schreiben
{
i = 0;
lnempty = false;
while (isspace(str[i]))
{
i++;
}
if (str[i] == '\0')
lnempty = true;
if (!lnempty)
{
tok = strtok(str, ",");
i = 0;
while (tok != NULL)
{
if (i <= row)
{
sscanf(tok, "%lf", &out);
A->data[j][i] = out;
}
if (i == row)
{
sscanf(tok, "%lf", &out);
b->data[j] = out;
}
if (i == row + 1)
{
sscanf(tok, "%lf", &out);
x->data[j] = out;
}
i++;
tok = strtok(NULL, ",");
}
if (col != row + 2)
{
x->data[j] = 0;
}
j++;
}
}
fclose(fp);
return true;
}
bool wantsrestart() //nachfragen ob der Nutzer das Programm neustarten möchte
{
int m;
m = -1;
while (m != 0 && m != 1)
{
printf("Möchten Sie das Programm neu starten? (0=Nein, 1=Ja)\n");
if (scanf("%d", &m) != 1)
{
m = -1;
}
while (getchar() != '\n'); //um scanf buffer zu clearen - bei Falscheingaben notwendig
}
printf("inrest\n");
if (m != 0)
{
printf("inrest\n");
return true;
}
return false;
}
Listelement *createlist(Vector *x) //verkettete Liste mit Vector x als erste Dateneingabe erstellen
{
Listelement *head = malloc(sizeof(Listelement));
Listelement *tail = malloc(sizeof(Listelement));
head->dat = malloc(sizeof(Vector));
head->dat->data = malloc((x->n) * sizeof(double));
head->dat->n = x->n;
for (int i = 0; i < x->n; i++)
{
head->dat->data[i] = x->data[i]; //Daten aus den Vektor in das erste Listenelement kopieren
}
head->next = tail;
head->n = 1; //gibt Anzahl der gespeicherten Vektoren an
tail->n = head->n; //tail.n ist immer 1
tail->dat = 0; //keine Daten im Tail speichern
tail->next = tail; //tail verweist auf sich selbst
return head;
}
Listelement *appendtolist(Listelement *head, Vector *x) //Vector x zur Liste hinzufügen
{
Listelement *temp = malloc(sizeof(Listelement));
temp->next = head;
while (temp->next != temp)
{
temp = temp->next; //temp auf tail zuweisen
}
//Vector in Listelement kopieren
temp->dat = malloc(sizeof(Vector));
temp->dat->data = malloc(sizeof(double) * x->n);
temp->dat->n = x->n;
for (int i = 0; i < x->n; i++)
{
temp->dat->data[i] = x->data[i];
}
//neuen Tail anhängen
Listelement *tail = malloc(sizeof(Listelement));
temp->next = tail;
tail->next = tail;
head->n += 1; //Eintragscounter erhöhen
return head;
}
void printlist(Listelement *head) //gesamte verkettete Liste auf den Bildschirm ausgeben
{
Listelement *x;
x = head;
for (int i = 0; x != x->next; i++)
{
printf("%d:\n", i);
for (int j = 0; j < x->dat->n; j++)
{
printf("x%d: %lf\n", j + 1, x->dat->data[j]);
}
printf("\n");
x = x->next;
}
}
void printlast(Listelement *head) //nur den letzen Eintrag der verketteten Liste auf den Bildschirm ausgeben
{
Listelement *x;
Vector *v;
x = head;
while (x->next != x)
{
v = x->dat;
x = x->next;
}
if (head->n != -2) //Iterationsschritt nur ausgeben, wenn Iterationsgrenze nicht erreicht wurde
printf("Iterationsschritt: %d\n", head->n);
for (int i = 0; i < v->n; i++)
{
printf("x%d: %lf\n", i + 1, v->data[i]);
}
}
bool islimit(Vector *x1, Vector *x2, double e) //überprüfen ob der neuberechnete Vector eine größere Differenz als e zum letzten hat
{
double sum1 = 0, sum2 = 0;
for (int i = 0; i < x1->n; i++)
{
sum1 += x1->data[i] * x1->data[i];
sum2 += x2->data[i] * x2->data[i];
}
sum1 = sqrt(sum1);
sum2 = sqrt(sum2);
if (sum1 > sum2)
return sum1 - sum2 < e;
return sum2 - sum1 < e;
}
Listelement *solve(Method method, Matrix *A, Vector *b, Vector *x, double e) //GLS lösen - Rückgabe ist head der verketteten Liste
{
int currit = 0; //aktuelle Iteration
int maxit = 100; //maximale Iteration
bool isdone = false; //check ob der Algorithmus schon gelöst ist
double sum1; //Zwischenwert für Berechnung
//Zwischenspeicher um letzten Iterationsschritt zu speichern
Vector *oldx = malloc(sizeof(Vector));
oldx->n = x->n;
oldx->data = malloc(sizeof(double) * oldx->n);
Listelement *results = createlist(x); //Liste erstellen
for (int i = 0; i < A->n; i++) //da 1/0 nicht definiert:
{
if (A->data[i][i] == 0) //wenn ... nicht berechenbar
{
results->n = -1; //Fehlercode für UI ausgabe
return results;
}
}
if (method == JACOBI) //Jacobi Algorithmus
{
while (currit < maxit && !isdone) //solange rechnen bis entweder keine Iterationen mehr und noch nicht gelöst
{
for (int i = 0; i < x->n; i++) //oldx füllen
{
oldx->data[i] = x->data[i];
}
for (int i = 0; i < x->n; i++)
{
sum1 = b->data[i];
for (int j = 0; j < x->n; j++)
{
if (j != i)
{
sum1 -= A->data[i][j] * oldx->data[j]; //sum1 = b(i)-(A(i,j)-oldx(j)) => für 0<i,j<x->n
}
}
x->data[i] = sum1 / A->data[i][i]; //neuen Wert berechnen
}
results = appendtolist(results, x); //wenn alle Zeilen berechnet - neuen Vektor hinzufügen
if (islimit(oldx, x, e)) //wenn Limit erreicht - Ergebnis ausgeben
return results;
currit++;
}
results->n = -2;
return results; //keine Iterationen mehr
}
if (method == GAUSS_SEIDEL) //Gauß-Seidel-Algorithmus -- gleiches wie Jacobi, nur neue Werte verwenden wenn verfügbar
{
while (currit < maxit && !isdone)
{
for (int i = 0; i < x->n; i++)
{
oldx->data[i] = x->data[i];
}
for (int i = 0; i < x->n; i++)
{
sum1 = b->data[i];
for (int j = 0; j < x->n; j++)
{
if (j < i)
{
sum1 -= A->data[i][j] * x->data[j]; //wenn bereits berechnet - neue Daten verwenden
}
if (j > i)
{
sum1 -= A->data[i][j] * oldx->data[j];
}
}
x->data[i] = sum1 / A->data[i][i];
}
results = appendtolist(results, x);
if (islimit(oldx, x, e))
return results;
currit++;
}
results->n = -2;
return results;
}
results->n = -1;
return results; //Fehlerstate - bei unbekannten Fehlern behandeln wie unberechenbar
}
int main() //Hauptfunktion => Userinput verarbeiten
{
Method method;
int m;
double e;
bool status = true;
char filename[256];
Matrix *A;
Vector *b;
Vector *x;
Listelement *result;
while (status)
{
A = malloc(sizeof(Matrix));
b = malloc(sizeof(Vector));
x = malloc(sizeof(Vector));
printf("Dateinamen bitte eingeben:\n");
scanf("%s", filename);
if (load(filename, A, b, x))
{
printf("Datei erfolgreich eingelesen!\n");
m = -1;
while (m != JACOBI && m != GAUSS_SEIDEL)
{
printf("Welchen Algorithmus möchten Sie verwenden? (0: Jakobi; 1: Gauß-Seidel)\n");
if (scanf("%d", &m) != 1)
{
m = -1;
}
while (getchar() != '\n')
; //um scanf buffer zu clearen - bei Falscheingaben notwendig
}
method = m;
e = -1;
while (e < 0)
{
printf("Wie groß möchten Sie ihre Fehlerschranke wählen? (double > 0)\n");
if (scanf("%lf", &e) != 1)
{
e = -1;
}
while (getchar() != '\n')
; //um scanf buffer zu clearen - bei Falscheingaben notwendig
}
result = solve(method, A, b, x, e);
switch (result->n)
{
case -1:
printf("Das gewählte LGS enthält 0 in der Hauptdiagonale und kann daher mit den Algorithmen nicht berechnet werden!\n");
break;
case -2:
printf("Der Berechenvorgang erreichte 100 Iterationen und wurde daher abgebrochen!\n");
m = -1;
while (m != 0 && m != 1)
{
printf("Möchten Sie trotzdem alle Werte, oder nur den Vektor x ausgeben?(0=alle Vektoren oder 1=nur der letzte Vektor)\n");
if (scanf("%d", &m) != 1)
{
m = -1;
}
while (getchar() != '\n')
; //um scanf buffer zu clearen - bei Falscheingaben notwendig
}
if (m == 0)
{
printlist(result);
}
else
{
printlast(result);
}
break;
default:
printf("Berechnung erfolgreich!\n");
m = -1;
while (m != 0 && m != 1)
{
printf("Möchten Sie alle Werte, oder nur den Vektor x ausgeben?(0=alle Vektoren oder 1=nur der letzte Vektor)\n");
if (scanf("%d", &m) != 1)
{
m = -1;
}
while (getchar() != '\n')
; //um scanf buffer zu clearen - bei Falscheingaben notwendig
}
if (m == 0)
{
printlist(result);
}
else
{
printlast(result);
}
break;
}
status = wantsrestart(); //Neustartintention abfragen
printf("test0");
//free Matrix
//free(A->data[1]);
/*
for (int k = 0; k < A->n; k++)
{
free(A->data[k]);
}
*/
printf("test");
free(A->data);
printf("test2");
A->n = 0;
free(A);
printf("test3");
//free List
Listelement *l1 = malloc(sizeof(Listelement));
Listelement *l2 = malloc(sizeof(Listelement));
l1 = result; //mit head beginnen
while (l1 != l1->next) //ganze Liste iterieren
{
l2 = l1->next;
free(l1->dat->data);
l1->dat->n = 0;
free(l1->dat);
l1->n = 0;
free(l1);
l1 = l2;
printf("test4");
}
//free Vectors
free(x->data);
x->n = 0;
free(x);
free(b->data);
b->n = 0;
free(b);
}
else
{
free(A);
free(x);
free(b);
printf("Dateifehler!\n");
status = wantsrestart(); //Neustartintentionen abfragen
}
}
return 0; //Programmende
}