Zweidimensionales Array an Funktion übergeben - Problem bei allen Spalten >1



  • Hallo,
    ich mache seit einigen Wochen meine ersten Schritte in C und habe dabei ein Problem mit der Übergabe von mehrdimensionalen Arrays (ich weiß, dass es vor kurzem eine ähnliche Fragestellung gab, die Lösung dazu habe ich aber aufgrund der Speicherzuweisung etc. nicht verstanden):

    Ich möchte ein mehrdimensionales Array in main() erzeugen und dieses dann in einer anderen Funktion nutzen. Ich bin mit meiner Fehlereingrenzung schon so weit gekommen, dass die Übergabe nicht richtig ist (deshalb habe ich es hier am einfachen Beispiel des Ausdruckens dargestellt, der Fehler ist der Gleiche). Die erste Zeile meines Arrays wird korrekt ausgegeben, bei den folgenden Zeilen erscheinen jedoch unsinnige Zahlen (426, 1310720, o.Ä.).
    Das Problem tritt nicht auf, wenn ich die Spalten des Arrays als Konstante definieren. Es muss also an "[spalten]" im Funktionsaufruf "drucken" liegen. (Leider geht das mit der Konstante nicht, wenn ich die Dimension der Matrix erst noch einlesen möchte, oder??)

    Alternativ habe ich auf galileocomputing gelesen, dass man auch einen Pointer übergeben kann (http://www.galileocomputing.de/openbook/c_von_a_bis_z/c_014_006.htm#RxxobKap014006040028C01F04118C). Dann bekomme ich allerdings beim kompilieren die Fehlermeldung "assignment of pointer to array 4 of int to pointer to int" für Zeile 8 im zweiten Code-Beispiel. Damit kann ich leider wenig anfangen... (Kann es sein, dass ich dem Pointer noch mitteilen muss, wieviele Spaltenelemente jedes Zeilenelement hat? Wenn ja: wie?)

    Ich würde mich freuen, wenn mir jemand helfen kann, das Array korrekt zu übergeben, wenn möglich ohne struct-Anweisung.

    Herzlichen Dank!

    Gesamtes Programm:

    #include <stdio.h>
    #include <stdlib.h>
    
    int spalten;
    
    //Druck-Funktion
    void drucken (int feld[][spalten], int zeilen, int spalten) {
    	for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
    		for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
    			printf ( "%3d", feld[count_zeilen][count_spalten] );
    		}
    		printf ("\n");
    	}
    }
    
    //Main-Funktion
    int main (void) {
    	int zeilen = 2;
    	spalten = 2;
    	int feld [zeilen][spalten];
    
    	for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
    		for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
    			feld[count_zeilen][count_spalten] = count_zeilen + count_spalten;
    		}
    	}
    
    	drucken (feld, zeilen, spalten);
    }
    

    Änderungen für Pointer-Übergabe, Rest wie oben (den habe ich aus Platzgründen weggelassen...):

    void drucken (int *feld[spalten], int zeilen, int spalten) {
    }
    
    int main (void) {
    
    	int *pointer;
    	pointer = feld;
    	drucken (pointer, zeilen, spalten);
    }
    


  • probier's so:

    #include <stdio.h>
    #include <stdlib.h>
    
    //Druck-Funktion
    void drucken (int *feld, int zeilen, int spalten) 
    {
        int count_zeilen;
        int count_spalten;
        for ( count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) 
        {
            for ( count_spalten = 0; count_spalten < spalten; count_spalten++ ) 
            {
                printf ( "%3d", feld[count_zeilen+zeilen*count_spalten] );
            }
            printf ("\n");
        }
    }
    
    //Main-Funktion
    #define ZEILEN 5
    #define SPALTEN 10
    int main (void) 
    {
        int count_zeilen;
        int count_spalten;
        int feld [ZEILEN][SPALTEN];
        int x = 0;
    
        for ( count_zeilen = 0; count_zeilen < ZEILEN; count_zeilen++ ) 
        {
            for ( count_spalten = 0; count_spalten < SPALTEN; count_spalten++ ) 
            {
                feld[count_zeilen][count_spalten] = x++;
            }
        }
    
        drucken ((int*)feld, ZEILEN, SPALTEN);
    }
    

    🙂



  • online codegenerator schrieb:

    probier's so:
    ...

    das ist ein schönes beispiel vie man flexibel mit arrays verschiedener anzahl von zeilen und spalten arbeiten kann.
    wenn man noch den index ändern würde, dann würden die zahlen auch in der richtigen reihenfolge ausgegeben werden, 😮
    z.b. so:

    void drucken_reprogged( int *feld, int zeilen, int spalten )
    {
        int count_zeilen;
        int count_spalten;
        for ( count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ )
        {
            for ( count_spalten = 0; count_spalten < spalten; count_spalten++ )
            {
                printf ( "%3d", feld[count_zeilen*spalten+count_spalten] ); // !!!
            }
            printf ("\n");
        }
    }
    

    🕶

    wenn die größe des arrays aber feststeht und sich nicht ändert, gehts aus so:

    void drucke2Darr( int arr[ZEILEN][SPALTEN] )
    {
    	int z,s;
    
    	for( s=0; s<SPALTEN; s++ )
    	{
    		for ( z=0; z<ZEILEN; z++ )
    		{
    			printf( "%3d", arr[z][s] );
    		}
    		puts("");
    	}
    }
    
    void init2Darr( int arr[ZEILEN][SPALTEN] )
    {
    	int i = 0,z,s;
    	for( s=0; s<SPALTEN; s++ )
    		for ( z=0; z<ZEILEN; z++ )
    	 arr[z][s] = i++;
    }
    // aufruf
    init2Darr(arr);
    drucke2Darr(arr);
    drucken_reprogged( arr, ZEILEN, SPALTEN )
    

    🙂



  • Die Lösung setzt aber voraus, dass ich ZEILEN und SPALTEN vorher per "#define" definiert habe, oder? Sonst funktioniert es nämlich bei mir nicht...
    Kann ich statt des festen Wertes denn auch den Wert für ZEILEN und SPALTEN während des Programmaufrufs festlegen (z.B. durch eine Eingabe)? Das muss ich nämlich: das Array kann für jeden Programmaufruf eine andere Größe haben 😞
    Trotzdem danke...



  • Übrigens ist mir grade aufgefallen, dass ich das Thema falsch benannt habe: ich habe natürlich Schwierigkeiten in allen Zeilen > 1 🙄



  • c-anfaenger schrieb:

    Kann ich statt des festen Wertes denn auch den Wert für ZEILEN und SPALTEN während des Programmaufrufs festlegen (z.B. durch eine Eingabe)? Das muss ich nämlich: das Array kann für jeden Programmaufruf eine andere Größe haben 😞
    Trotzdem danke...

    das kannst du mit 'malloc' machen:

    ...
    int zeilen = ...;
    int spalten = ...;
    int *feld = malloc (zeilen * spalten * sizeof(int));
    ...
    if (feld) // nur benutzen wenn feld != 0
    {
       feld[x+zeilen*y] = ...;  // setzt einen wert an position x/y
       ...
       free (feld);             // 'free' aufrufen wenn feld nicht mehr gebraucht wird 
    }
    

    🙂



  • c-anfaenger schrieb:

    Alternativ habe ich auf galileocomputing gelesen, dass man auch einen Pointer übergeben kann (http://www.galileocomputing.de/openbook/c_von_a_bis_z/c_014_006.htm#RxxobKap014006040028C01F04118C). Dann bekomme ich allerdings beim kompilieren die Fehlermeldung...

    btw: vergiss 'galileo-computing' am besten ganz schnell. das ist voller fehler. frag' lieber uns.
    🙂



  • falls dir die indexschreibweise eher zusagt:

    void init_arr2D( int **arr, int zeilen, int spalten )
    {
    	int i = 0,z,s;
    
    	for( z=0; z<zeilen; z++ )
    		for ( s=0; s<spalten; s++  )
    			 arr[z][s] = i++;
    }
    
    void drucken_arr2D( int **arr, int zeilen, int spalten )
    {
        int z;
        int s;
        for ( z = 0; z < zeilen; z++ )
        {
            for ( s = 0; s < spalten; s++ )
            {
                printf ( "%3d", arr[z][s] );  
            }
            puts("");
        }
    }
    
    int main()
    {
     	int i=0,j=0,z=3,s=5;
    	int** arr2D=NULL;
    
    	arr2D = malloc( z*sizeof(int**) );
    	if ( !arr2D ) 
    	{
    		puts("out of memory"); return 1;
    	}
    
    	for ( i=0; i<z; i++ )
    	{
    		arr2D[i] = malloc( s*sizeof(int));
    		if ( !arr2D[i]) break;
    	}
    
    	if ( i<z )
    	{
    		puts("out of memory");
    		for ( j=0; j<=i; j++ ) free ( arr2D[j] );
    		free( arr2D ); 
    		return 1;
    	}
    
    	init_arr2D(arr2D, z, s);
    	drucken_arr2D(arr2D, z, s );
    
    	// aufräumen
    	for ( i=0; i<z; i++ )
    	{
    		free(arr2D[i]); // spalten freigeben
    	}
    	free(arr2D); // zeilenzeiger freigeben 
    
    	return 0;
    }
    

    🙂



  • Vielen Dank! 👍



  • Das beispiel von easy array II reprogged funktioniert leider nicht. Ich bekomme jede Menge Fehler:

    Fehler 1 error C3861: "printf": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 18
    Fehler 2 error C3861: "puts": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 20
    Fehler 3 error C2065: 'NULL': nichtdeklarierter Bezeichner h:\visual studio 2010\projects\basics\basics\main.cpp 27
    Fehler 4 error C3861: "malloc": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 29
    Fehler 5 error C3861: "puts": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 32
    Fehler 6 error C3861: "malloc": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 37
    Fehler 7 error C3861: "puts": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 43
    Fehler 8 error C3861: "free": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 44
    Fehler 9 error C3861: "free": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 45
    Fehler 10 error C3861: "free": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 58
    Fehler 11 error C3861: "free": Bezeichner wurde nicht gefunden. h:\visual studio 2010\projects\basics\basics\main.cpp 60
    12 IntelliSense: PCH-Warnung: Es wurde keine geeignete Stelle für das Header-Ende gefunden. Es wurde keine Intellisense-PCH-Datei generiert. h:\visual studio 2010\projects\basics\basics\main.cpp 1
    13 IntelliSense: Der Bezeichner ""printf"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 18
    14 IntelliSense: Der Bezeichner ""puts"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 20
    15 IntelliSense: Der Bezeichner ""NULL"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 27
    16 IntelliSense: Der Bezeichner ""malloc"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 29
    17 IntelliSense: Der Bezeichner ""puts"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 32
    18 IntelliSense: Der Bezeichner ""puts"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 43
    19 IntelliSense: Der Bezeichner ""free"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 44
    20 IntelliSense: Der Bezeichner ""free"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 45
    21 IntelliSense: Der Bezeichner ""free"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 58
    22 IntelliSense: Der Bezeichner ""free"" ist nicht definiert. h:\visual studio 2010\projects\basics\basics\main.cpp 60



  • Da fehlen Header:

    #include <stdio.h>
    #include <stdlib.h>

    ganz oben sollte helfen.



  • Leichenfledderer.

    Liebe Kinder, so nicht machen

    #include <stdio.h>
    #include <stdlib.h>
    
    int spalten;
    
    //Druck-Funktion
    void drucken (int feld[][spalten], int zeilen, int spalten) {
        for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
            for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
                printf ( "%3d", feld[count_zeilen][count_spalten] );
            }
            printf ("\n");
        }
    }
    
    //Main-Funktion
    int main (void) {
        int zeilen = 2;
        spalten = 2;
        int feld [zeilen][spalten];
    
        for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
            for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
                feld[count_zeilen][count_spalten] = count_zeilen + count_spalten;
            }
        }
    
        drucken (feld, zeilen, spalten);
    }
    

    Der Onkel zeigt jetzt mal, wie man sowas macht:
    - ohne globale Variablen
    - ohne VLA
    - ohne UB
    - ohne Zeiger-Cast
    - C99 konform (wegen Verwendung von Zeigern auf VLA)
    - im Übrigen kommen in den meisten o.g. "Vorschlägen" überhaupt keine Arrays vor
    - es gibt auch keine zweidimensionalen Arrays sondern nur Arrays von Arrays

    void setzen (void *speicher, int zeilen, int spalten) {
    	int (*f)[spalten] = speicher;
        for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
            for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
                f[count_zeilen][count_spalten] = count_zeilen + count_spalten;
            }
        }
    }
    
    void drucken (void *speicher, int zeilen, int spalten) {
    	int (*f)[spalten] = speicher;
        for ( int count_zeilen = 0; count_zeilen < zeilen; count_zeilen++ ) {
            for ( int count_spalten = 0; count_spalten < spalten; count_spalten++ ) {
                printf ( "%3d", f[count_zeilen][count_spalten] );
            }
            printf ("\n");
        }
    }
    
    int main (void) {
        int zeilen = 2;
        int spalten = 2;
        int *speicher = malloc( zeilen*spalten*sizeof*speicher );
    
    	setzen  (speicher, zeilen, spalten);
        drucken (speicher, zeilen, spalten);
    
        free( speicher );
        return 0;
    }
    

    http://ideone.com/vTPuBH

    Das Ganze arbeitet mit Dimensionen, die erst zur Laufzeit bekannt sind auf einem Speicherbereich, d.h. es wird auch nur 1x malloc/free verwendet (was in der Regel ziemlich teuer ist).
    Weiterhin kann die offensichtlich ja wohl gewünschte Doppelsubskription [zeile][spalte] verwendet werden, die bei den meisten o.g. Beispielen zu der irrigen Annahme führte, es handele sich um Arrays.


Log in to reply