Dynamische, "zwei-dimensionale" Arrays und SegFault bei free-Aufruf



  • Hallo zusammen,
    ich habe einfach zum Üben ein C-Programm zur Matrix-Multiplikation geschrieben(bzw. es versucht) und bekomme nun allerdings einen SegFault beim Aufruf von free(). Hier der Quelltext der Datei matrix.c:

    #include <stdio.h>
    #include <malloc.h>
    #include <stdlib.h>
    #include "matrix.h"
    
    void init(matrix *m,int z, int s) {
    	if(z<=0 || s<=0) {
    		printf("Ungueltige Zeilen- oder Spaltenzahl!");
    		return;
    	}
    	m->zeilen=z;
    	m->spalten=s;
    }
    /*!
    * Multipliziert zwei Matrizen miteinander.
    * \param Two matrix pointer that point to matrix structs that supposed to be multiplied.
    * \return Pointer to a matrix struct that stores the result of \n
    *        the multiplication of the matrices.
    *
    */
    matrix *mult(matrix *m1,matrix *m2) {
    	if(m1->zeilen!=m2->spalten) {
    		printf("Dimensionen ungueltig!");
    		return NULL;
    	}
    	int i,z,s,k, **result;
    	/* Initialize new array to store the result matrix. */
    	result=malloc(m1->zeilen*sizeof(int));
    	for(i=0;i<m1->zeilen;i++) {
    		result[i]=malloc(m2->spalten*sizeof(int));
    	}
    	/* the actual calculation. TODO: Parallelization?*/
    	for(z=0; z< m1->zeilen;z++) {
    		for(s=0;s<m2->spalten;s++) {
    			result[z][s]=0;
    			for(k=0;k<m1->spalten;k++) {
    				result[z][s]+=(*(m1->values+z))[k]*(*(m2->values+k))[s];
    			}
    		}
    	}
    	/* Gebe Inhalt des Ergebnisses aus. */
    	for(z=0;z<m1->zeilen;z++) {
    		for(s=0;s<m2->spalten;s++) {
    			printf("%d\n",result[z][s]);
    		}
    	}
    	matrix *res=malloc(sizeof(matrix));
    	init(res,m1->zeilen,m2->spalten);
    	res->values=result;
    	return res;
    }
    

    matrix.h:

    /* matrix.h */
    #ifndef MATRIX_H
    #define MATRIX_H
    typedef struct matrix {
    	int **values, zeilen, spalten;
    } matrix;
    matrix *mult(matrix *m1, matrix *m2);
    void init(matrix *m, int z, int s);
    #endif
    

    und hier die main:

    int main(int argc, char **argv)
    {
        matrix *m1=malloc(sizeof(matrix));
    	matrix *m2=malloc(sizeof(matrix));
    	int **werte, i, eingabe_korrekt=0;
            //Lese Dimensionen ein, die gueltig sind:
    	while(!eingabe_korrekt) {
    		printf("Please enter dimension:\n");
    		scanf("%d",&m1->zeilen);
    		scanf("%d",&m1->spalten);
    		printf("Enter dimension of matrix 2:\n");
    		scanf("%d",&m2->zeilen);
    		scanf("%d",&m2->spalten);
    		if(m1->spalten==m2->zeilen)
    			eingabe_korrekt=1;
    	}
            //Allokiere Speicher fuer die "2-dim." Arrays, werden in C nur simuliert
    	werte=malloc(sizeof(int)*m1->zeilen);
    	if(werte==NULL) {
    		printf("malloc caused error!\n");
    		return -1;
    	}
    	for(i=0; i<m1->zeilen;i++) { //an der Stelle m[i] ist jetzt ein Array, d.h. *(m+i) liefert Anfangsadresse des i.ten Arrays
    		werte[i]=malloc(m1->spalten*sizeof(int));
    		printf("success!\n");
    		if(werte[i]==NULL) {
    			printf("malloc caused error!\n");
    			return -1;
    		}
    	}
    	m1->values=werte;
            //Mache das gleiche fuer das Array von m2:
    	int **andere_werte;
    	andere_werte=malloc(m2->zeilen*sizeof(int));
    	for(i=0; i<m2->zeilen;i++) {
    		andere_werte[i]=malloc(m2->spalten*sizeof(int));
    		printf("Success!\n");
    		if(andere_werte[i]==NULL) {
    			printf("malloc caused error!\n");
    			return -1;
    		}
    	}
    	int j;
    	for(i=0;i<m1->zeilen; i++) {
    		printf("Outer forloop!\n");
    		for(j=0;j<m1->spalten;j++) { //werte im Intervall [1,30]
    			printf("Inner for loop\n");
    			werte[i][j]=rand()%30+1;
    			andere_werte[i][j]=rand()%40+1;
    		}
    	}
    	m2->values=andere_werte;
    	printf("Nach vollst. Initialization:\n");
    	/*matrix *res=mult(m1,m2);
    	for(;i<res->zeilen;i++) {
    		for(j=0;j<res->spalten;j++) {
    			printf("Werte zeilenweise:     %d\n",*res->values+i*res->spalten)[j]);
    		}
    	}*/
    	/*Hier freigabe der allokierten Speicherbereiche */
    	for(i=0;i<m2->zeilen;i++) {
    		printf("free columns of m2\n");
    		free(m2->values[i]); //TODO Hier passiert nach zweimaligem, erfolgreichen Freigeben ein SegFault!
    	//Sollte aber insgesamt 4 Mal durchlaufen!
    	}
    	free(m2->values);
    	free(m2);
    	for(i=0;i<m1->zeilen;i++) {
    		free(m1->values[i]);
    	}
    	free(m1->values);
    	free(m1);/*
    	for(i=0;i<res->zeilen;i++) {
    		free(res->values[i]);
    	}
    	free(res->values);
    	free(res);*/
    	return 0;
    }
    

    Und zwar konnte ich den verursachten SegFault bis zur mit TODO gekennzeichneten Stelle eingrenzen, als Testeingaben hatte ich folgende Dimensionen verwendet:
    m1: 3x4, m2:4x3.
    Nur wird mir leider nicht klar, warum gerade das Freigeben des Speichers einen SegFault verursacht. Ich kann mir vorstellen, dass dies der Fall sein kann, wenn ich einen Speicher freigeben will, der mir gar nicht gehört, aber den Speicherplatz fuer die Matrix m2 habe ich doch richtig allokiert. Im Buch "Grundkurs C" von Jürgen Wolf wird genau diese Art von Freigeben des allokierten Speichers bei genau demselben Beispiel (Matrizen) verwendet, deshalb verstehe ich nicht, weshalb es hier nicht funktioniert.
    Ich hoffe ihr könnt mir helfen.
    LG Unix1



  • Zeile 18 im main Programm müssten Pointer sein, da du ja eine Liste von Pointern mit **value Ansprechen möchtest. Probier mal anstelle von int ein int * aus.



  • Bei der ersten Dimension bekommst du int* und kein int.
    sizeof(int) und sizeof(int*) müssen nicht gleich sein.

    Warum gibt es keine Funktion, die dir eine Matrix richtig anlegt und auch wieder freigibt?



  • Vielen Dank erstmal fuer die sehr schnellen Antworten! Dass dort sizeof(int*) stehen muss, habe ich völlig übersehen, allerdings gilt auf meinem System dass beide 4 Bytes groß sind, also kein Unterschied besteht, aber im generellen natürlich ist das sehr wichtig, danke. Ich habe einfach mal Programmteile vernünftig ausgelagert und jetzt funktioniert es. Allerdings ist mir aufgefallen, dass die for-Loop, mit der die Matrizen initialisiert werden (mit //werte im Intervall[1,30] gekennzeichnet), auf jeden Fall ungueltige Arrayzugriffe verursachen kann je nach Dimensionen der einzelnen Matrizen.
    Wieso das Programm aber immer bis genau vor den Aufruf von free() durchgelaufen ist, ist mir noch immer ein Rätsel. Denn läge es an dieser for-loop, dann würde das Programm ja früher abbrechen. Auf jeden Fall funktioniert es jetzt und ich habe alles verstanden, was ich programmiert habe. Nochmals vielen Dank,
    Lg Unix1


Anmelden zum Antworten