Matrixerstellung mit Pointern



  • Hallo

    Ich habe folgendermaßen eine Matrix erstellt:

    int ** buffer;
    buffer = (int**) malloc(2);
    
    int k;
    for (k = 0; k < 2; k++) {
       buffer[k] = (int*) malloc(2);
    }
    

    Prinzipiell funktioniert das auch, ich kann dann mit buffer[a][b] auf die Werte zugreifen. Das funktioniert bis buffer[2][2].
    Wieviel Platz muss ich jetzt immer allgemein reservieren um eine bestimmte Größe in einer Dimension zu erlangen? Langen immer "ungefähr" eine Größe von n für n Elemente aus?



  • Hi

    Geminus schrieb:

    Wieviel Platz muss ich jetzt immer allgemein reservieren um eine bestimmte Größe in einer Dimension zu erlangen?

    Geminus schrieb:

    int k;
    for (k = 0; k < 2; k++) {
    buffer[k] = (int*) malloc(2);
    }

    Das reserviert dir jeweils 2 Byte, das ist vermutlich nicht, was du willst.
    Allgemein reserviert man (für T *t) n * sizeof(*t) Speicher, in deinem Fall also vermutlich

    buffer[k] = malloc ( 2 * sizeof(int));
    

    Geminus schrieb:

    Langen immer "ungefähr" eine Größe von n für n Elemente aus?

    😕
    Wenn du n * sizeof(*t) reservierst, hast du exakt n * sizeof(*t) Bytes, nicht
    ungefährt.
    Ob es ausreicht, ist abhängig von der Anwendung.
    Entweder du kennst die Größe vorher, dann brauchst du nicht unbedingt malloc (es sei den der Stackspeicher ist zu klein) und nimmst ein statisches Array. Oder du schätzt eine gewisse Speichermenge ab und erweiterst bei Bedarf dynamisch. Oder du machst
    es von 0 an dynamisch, kommt immer auf den Fall drauf an, was am Besten ist.



  • ⚠ Wenn du dann auch genug Platz für eine 2*2 Matrix hast, ist der maximale Index 1. Also buffer[1][1]



  • Danke schon mal für die Antworten!

    Also wenn ich das richtig verstanden habe, muss ich in der Schleife für jedes Element n * sizeof(int) Platz reservieren, um n Elemente speichern zu können.
    Wieviel Platz muss ich in

    buffer = (int**) malloc( ? );
    

    reservieren? Wenn die erste Dimension die Größe m hat ebenso m * sizeof(int) viel Bytes? Also dass das am Ende zB so ausschaut:

    int width = 5;
    int height = 5;
    
    int ** buffer;
    buffer = (int**) malloc(width * sizeof(int));
    
    int k;
    for (k = 0; k < 2; k++) {
       buffer[k] = (int*) malloc(height * sizeof(int));
    }
    


  • Geminus schrieb:

    reservieren? Wenn die erste Dimension die Größe m hat ebenso m * sizeof(int) viel Bytes? Also dass das am Ende zB so ausschaut:

    int width = 5;
    int height = 5;
    
    int ** buffer;
    buffer = (int**) malloc(width * sizeof(int));
     
    int k;
    for (k = 0; k < 2; k++) {
       buffer[k] = (int*) malloc(height * sizeof(int));
    }
    

    Nicht ganz richtig.

    1. die Typecasts sind in C eher hinderlich. Bitte entfernen. Wenn dein Compiler dann meckert, ist das ein recht eindeutiges Zeichen, dass du einen C++-Compiler verwendest.

    2. Die sizeof-Ausdrücke sind nicht korrekt. Für die erste Dimension benutzt du sizeof(int), wobei du aber sizeof(int*) benutzen sollst, da alle Elemente buffer[k] Zeiger auf int sind. Verstanden?
    Weiterhin bietet es sich meist an sizeof nicht rohe Typen zu geben, sondern Ausdrücke aus denen sich die Typen direkt ableiten lassen. Also z.B. sizeof(*buffer) statt sizeof(int*). Hat den Vorteil, dass du nicht immer mit Typen um die gegen werfen musst.

    1. und 2. angewendet sollte gleich etwas übersichtlicher sein:

    int width = 5;
    int height = 5;
    
    int ** buffer;
    buffer = malloc(width * sizeof(*buffer));
    
    int k;
    for (k = 0; k < 2; k++) {
       buffer[k] = malloc(height * sizeof(*buffer[k]));
    }
    

    Du siehst, dass der Typ der Matrixelemente nur ein einziges Mal genannt wird, nämlich bei der Deklaration von buffer.

    3. das k < 2 macht irgendwie keinen Sinn. Da solltest du selbst drauf kommen was an der 2 albern ist.



  • Geminus schrieb:

    Danke schon mal für die Antworten!

    Also wenn ich das richtig verstanden habe, muss ich in der Schleife für jedes Element n * sizeof(int) Platz reservieren, um n Elemente speichern zu können.
    Wieviel Platz muss ich in

    buffer = (int**) malloc( ? );
    

    reservieren? Wenn die erste Dimension die Größe m hat ebenso m * sizeof(int) viel Bytes? ...

    Wenn dir Tims Version nicht behagt, kannst du auch direkt mit den Datentypen arbeiten,
    du darfst bloß nicht vergessen den(die) Datentyp(en) in den speicherreservierenden Aufrufen zu ändern,
    falls du den Datentyp der Variable änderst.
    Dynamisch erzeugte Arrays beliebiger Dimension lassen sich auch auf einen zusammenhängenden Speicherbereich abbilden
    und mit T* my_array = malloc ( n * sizeof ( *my_array )); schreiben (mit n = xdim * ydim * ... * ndim).
    (Die Erzeugung im Fall 2-D wäre dann T* my_array = malloc ( xdim * ydim * sizeof ( *my_array ));
    Das hat Vorteile wie kürzerer Code (Erzeugung des Arrays und Speicherfreigabe in nur einer Zeile), ressourcensparsamer weil weniger Zeiger gebraucht werden, dafür muss man sich über die etwas weniger intuitive Adressierung der Array-Koordinaten klar werden.
    Aber bilde dir deine eigene Meinung, guckst du:

    #include <stdio.h>
    #include <stdlib.h>
    
    // Variante A
    
    // Initialisierung
    void init_array_a ( int** array_a, int xdim, int ydim )
    {
    	int x, y;
    	if ( NULL != array_a )
    		for ( y = 0; y < ydim; y++ )
    			for ( x = 0; x < xdim; x++ )
    				array_a [ y ] [ x ] = x * y;
    }
    // Freigabe des Speichers
    void free_array_a ( int** array_a, int ny )
    {
    	if ( array_a )
    	{
    		int i;
    		for ( i = 0; i < ny; i++ )
    			free ( array_a [ i ]);
    		free ( array_a );
    	}
    }
    // Dito.
    void free_array_advanced_a ( int*** array_a, int ny )
    {
    	if ( array_a )
    	{
    		int i;
    		int** arr = *array_a;
    		if ( NULL != arr )
    		{
    			for ( i = 0; i < ny; i++ )
    				free ( arr [ i ] );
    			free ( arr );
    			*array_a = NULL; // Entschärfung des Zeigers durch NULL setzen.
    		}
    	}
    }
    
    // Anzeige der Array-Daten
    void view_array_a ( int** array_a, int xdim, int ydim )
    {
    	int x, y;
    	if ( array_a )
    		for ( y = 0; y < ydim; y++ )
    			for ( x = 0; x < xdim; x++ )
    				printf ( "%d ", array_a [ y ] [ x ] ); // Intuitive Adressierung des Arrays mit x-/y-Koordinaten
    }
    
    // Erzeugung
    int** create_array_a ( int xdim, int ydim )
    {
    	int** array_a, x, y;
    	if ( NULL != ( array_a = malloc ( ydim * sizeof ( int* ))))
    		for ( y = 0; array_a && y < ydim; y++ ) 
    			if ( NULL == ( array_a [ y ] = malloc ( xdim * sizeof ( int ))))
    				free_array_advanced_a ( &array_a, y ); 
    	return array_a;
    }
    
    ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////
    
    // Variante B
    
    // Erzeugung des Arrays als zusammenhängenden Speicherbereich. Mein Favorit :p
    int* create_array_b ( int xdim, int ydim )
    {
    	return malloc ( xdim * ydim * sizeof ( int ));
    }
    
    void init_array_b ( int* array_b, int xdim, int ydim )
    {
    	int x, y;
    	for ( y = 0; y < ydim; y++ )
    		for ( x = 0; x < xdim; x++ )
    			array_b [ y * xdim + x ] = x * y; // Addressierung des Arrays mit Koordinaten: y * xdim + x
    }
    
    void free_array_b ( int* array_b )
    {
    	if ( array_b )
    		free ( array_b );
    }
    
    void free_array_advanced_b ( int** array_b )
    {
    	if ( array_b && *array_b )
    		free ( *array_b ), *array_b = NULL; // Entschärfung des Zeigers durch NULL setzen.
    }
    
    void view_array_b ( int* array_b, int xdim, int ydim )
    {
    	int i = 0;
    	if ( array_b )
    		while ( i < xdim * ydim )
    			printf ( "%d ", array_b [ i++ ] );
    }
    
    int main ( void )
    {
    	int xdim = 5, ydim = 3, x, y, z;
    	int** array_a = create_array_a ( xdim, ydim );
    	int* array_b = create_array_b ( xdim, ydim );
    
    	init_array_a ( array_a, xdim, ydim );
    	init_array_b ( array_b, xdim, ydim );
    	// Anzeige der initialisierten Werte
    	view_array_a ( array_a, xdim, ydim ); putchar('\n');
    	view_array_b ( array_b, xdim, ydim );
    	// Freigabe des Speichers
    	free_array_a ( array_a, ydim );
    	free_array_b ( array_b );
    	// Die Zeiger sind nicht NULL und können in manchen Fällen Probleme verursachen.
    	printf ( "\n%p %p\n", array_a, array_b );
    
    	array_a = create_array_a ( xdim, ydim );
    	array_b = create_array_b ( xdim, ydim );
    	free_array_advanced_a ( &array_a, ydim );
    	free_array_advanced_b ( &array_b );
    	// Die Zeiger sind NULL, 'entschäft'.
    	printf ( "%p %p\n", NULL, array_b );
    	return 0;
    }
    


  • Tim schrieb:

    das k < 2 macht irgendwie keinen Sinn. Da solltest du selbst drauf kommen was an der 2 albern ist.

    int width = 5;
    int height = 5;
    
    int ** buffer;
    buffer = malloc(width * sizeof(*buffer));
     
    int k;
    for (k = 0; k < width; k++) {
       buffer[k] = malloc(height * sizeof(*buffer[k]));
    }
    

    OK so müsste es dann passen. Danke für die Erklärung 🙂

    Tim schrieb:

    Wenn dir Tims Version nicht behagt, kannst du auch direkt mit den Datentypen arbeiten,
    du darfst bloß nicht vergessen den(die) Datentyp(en) in den speicherreservierenden Aufrufen zu ändern,
    falls du den Datentyp der Variable änderst.
    Dynamisch erzeugte Arrays beliebiger Dimension lassen sich auch auf einen zusammenhängenden Speicherbereich abbilden
    und mit T* my_array = malloc ( n * sizeof ( *my_array )); schreiben (mit n = xdim * ydim * ... * ndim).
    (Die Erzeugung im Fall 2-D wäre dann T* my_array = malloc ( xdim * ydim * sizeof ( *my_array ));

    Hei cool, das ist wirklich eine ausführliche Antwort 😉 Um ehrlich zu sein versteh ich das im Moment nur ansatzweise, ich muss mich da wohl noch mehr mit Pointern und Speicherallokation beschäftigen...


Anmelden zum Antworten