[C] dynam. 2D-array Problem

Halli Hallo,

ich habe nen kleines Problem mit einem dynamisch allozierten 2D-Array.

Ich möchte ein 2D-Array mit malloc allozieren und dann mit Funktionen bearbeiten.
Im folgenden Code wird das allozierte Array zum einen in
einer Funktion befüllt und dann durch eine andere ausgegeben.
(Das hat erst einmal keinen tieferen Sinn, halt nur für didaktische Zwecke)

Wenn ich das Array "extern" befüllen möchte bekomme ich sofort einen Speicherzugriffsfehler.
Wenn ich das Array innerhalb der main-Funktion befülle bekomme ich
irgendwelche Zahlen ausgegeben... also es wird von irgendwo im Speicher gelesen.

Hat jemand vielleicht eine Idee was mir hier schief gelaufen ist?
In 1D funktioniert es super, und wenn ich das Array in der Variablen Deklaration fest setze funktioniert es auch prima... .

C++:
#include <stdio.h> 
#include <stdlib.h> 
 
void func2D_print();
void func2D_init();

int main(void){
  int i, j, k, m, n;
  int array2d_init, array2d_print;
  int **array2D;

  /* Arraygröße */
  m=5;
  n=5;
  
/* *------------------- SCHALTER ----------------------------* */
/**/  /*0= in main initialisieren , 1= durch Funktion initialisieren*/
/**/  array2d_init=0;		
/**/  /*0= in main ausgeben, 1= durch Funktion ausgeben*/
/**/  array2d_print=0;	
/* *---------------------------------------------------------* */



/* -------------------- ALLOZIEREN -------------------------* */
/**/  /* 2D ARRAY MALLOC */
/**/    array2D = (int **)malloc( m*sizeof(int *) );
/**/    if(NULL==array2D){ printf("Fehler 1\n"); return EXIT_FAILURE;}
/**/    for(i=0;i<n;i++){ 
/**/      array2D[i]= (int *)malloc( n*sizeof(int) );
/**/      if(NULL==array2D[i]){ printf("Fehler 2\n"); return EXIT_FAILURE;}
/**/    }
/* ----------------------------------------------------------* */
  
/* *-------- Initialisierung über main ODER Funktion --------* */
/**/  /* Initialisierung durch main Funktion*/
/**/  if(!array2d_init){
/**/    k=0;
/**/    for(i=0;i<m;i++){
/**/      for(j=0;j<n;j++){
/**/	array2D[i][j]=k;
/**/	k++;
/**/      }
/**/    }
/**/  }
/**/  
/**/  /* Initialisierung über externe Funktion */
/**/  if(array2d_init){
/**/	func2D_init(&m, &n, array2D);}
/* *---------------------------------------------------------* */

/* *----------- Ausgabe über main ODER Funktion -------------* */
/**/  /* Ausgabe durch main Funktion */  
/**/  if(!array2d_print){
/**/    for(i=0;i<m;i++){
/**/      for(j=0;j<n;j++){
/**/	printf("array2D[%d][%d]: %d\n",i,j,array2D[i][j]);}}
/**/  }
/**/
/**/	/* Ausgabe über externe Funktion*/
/**/  if(array2d_print){
/**/  	func2D_print(&m, &n, array2D);}
/*-----------------------------------------------------------* */

return 0;
}


/* *-------------------- Funktionen -------------------------* */
/**/	/*Ausgabe*/
/**/void func2D_print(int *m, int *n, int array2D[][*n])
/**/{
/**/  int i,j;
/**/  for(i=0;i<*m;i++){
/**/    for(j=0;j<*n;j++){
/**/      printf("array2D[%d][%d]: %d\n",i,j,array2D[i][j]);}}
/**/}
/**/
/**/	/*Array befüllen*/
/**/void func2D_init(int *m, int *n, int array2D[][*n])
/**/{
/**/  int i,j,k;
/**/  
/**/  k=0;
/**/  for(i=0;i<*m;i++){
/**/    for(j=0;j<*n;j++){
/**/      array2D[i][j]=k;
/**/      k++;}}
/**/}
/* *---------------------------------------------------------* */

Wie bekommt man den Code so schön farb-codiert?

Gruß
LM
 
Zuletzt bearbeitet von einem Moderator:
Hi

Zuerst zur Farbcodierung:
[code=cpp]....[/code] statt [code]....[/code] nehmen.
Habs geändert.

Fehler 1: Es gibt keine free zu deinen malloc.

Warum sind bei dir so viel Kommentar-etwas vor jeder Zeile?
Ich mach mir mal eine lokale Version ohne, geht meiner Meinung nach besser zum Lesen.

Derweil zum vermutlichen Hauptproblem:
Du mischt die zwei möglichen Arten, ein mehrdimensionales Array zu machen.
Ich erklärs der Einfachkeit halber mal mit char statt int,
weil die 4 Byte vom int überall noch Multiplikationen mit 4 bedeuten würden.

Die Variante:
C++:
char array[3][4];
wird im eindimensionalen Speicher. als eindim. Array, Größe 3*4=12, umgesetzt.
Die Adresse des Startelements kommt dann für den späteren Zugriff in den Pointer array.
Code:
   0  1  2  3
0  a  b  c  d
1  e  f  g  h
2  i  j  k  l
in der Vorstellung wird im Speicher also zu
Code:
0  1  2  3  4  5  6  7  8  9 10 11
a  b  c  d  e  f  g  h  i  j  k  l
Bei jedem Zugriff wie array[2][1] werden die "Koordinaten" auf die Indizierung des eindim. Arrays umgerechnet.
(Zeilenindex * Gesamspaltenanzahl) + Spaltenindex
array[2][1] vom char array[3][4] ist k
2*4 + 1 = 9
9 im eindim. ist wieder k


Die andere Arrayart:
C++:
char **array;
und dann malloc auf array und malloc in einer Schleife für alle array[ I].
Also für sowas wie array[3][4] beim ersten malloc 3 Elemente, dann beim Schleifenmalloc jeweils 4.
Das Ergebnis: array selbst ist kein 12 char (oder bei dir int) großes Array,
sondern ein Array aus genau 3 Pointern.

Jeder Pointer zeigt dann auf ein abgetrenntes, eigenes Array aus jeweils 4 char/int/wasauchimmer.
Da, wo bei der oberen Variante also schon die ersten Werte sind sind hier nur irgendwelche Speicheradressen.
Und die eigentlichen Werte müssen auch nicht sofort dahinter kommen, sondern können beliebig irgendwo im Speicher sein.
Jedes der Wertarrays allein irgendwo, abgetrennt von allen anderen.

Bei einem Zugriff auf array[2][1] wird zuerst vom eindim.Pointerarray [2] genommen,
das ist dann wieder die Ausgangsadresse für ein eindim. char/int-Array, von dem dann [1] genommen wird.


Du erzeugst die zweite Variante und behandelst das Ergebnis aber wie die Erste.
array[2][1] bedeutet bei deinen Zugriffen "9 Elemente nach der Startadresse, fertig".
Dabei sind an der Startadresse nur paar Pointer und kein einziger Wert.
 
Zuletzt bearbeitet:
Hi sheel,

danke für deine ausführliche Antwort!

Mit den vielen Kommentaren wollte ich eine graphische Übersichtlichkeit
Simulieren was ich das nächste mal lieber lasse... .

Mit dem Array aus Pointern die dann wieder auf einzelne Arrays zeigen hatte ich auch so verstanden.
Ich war nur konfus bei der Ansprache des 2D Arrays weil ich mich an die Logik des 1D-Falls gehalten hatte,
und andere Quellen mit sagten das ich dann noch die länge der 2.Dim mit angeben muss.
Dabei hab ich dann nich tmehr durchgeblickt... initialisiert wird das Array in einer Funktion dann mit " **Array "
Ich stell mir das wie der "Anfang vom Anfang" vor, Anfang Zeile( was ja ein Feld von Pointern ist) vom Anfang der Spalte.
Danke nochmal für den Hinweis das ich die Initialisierungen vermischt hatte.

Hier der funktionierende Code: (diesmal in bunt und farbe!)
C++:
#include <stdio.h> 
#include <stdlib.h> 
 
void func2D_print();
void func2D_init();
 
int main(void){
  int i, j, k, m, n;
  int array2d_init, array2d_print;
  int **array2D;
 
  /* Arraygröße */
  m=5;
  n=5;
  
/* *------------------- SCHALTER ----------------------------* */
/**/  /*0= in main initialisieren , 1= durch Funktion initialisieren*/
/**/  array2d_init=0;       
/**/  /*0= in main ausgeben, 1= durch Funktion ausgeben*/
/**/  array2d_print=1;  
/* *---------------------------------------------------------* */
 
 
 
/* -------------------- ALLOZIEREN -------------------------* */
/**/  /* 2D ARRAY MALLOC */
/**/    array2D = (int **)malloc( m*sizeof(int *) );
/**/    if(NULL==array2D){ printf("Fehler 1\n"); return EXIT_FAILURE;}
/**/    for(i=0;i<n;i++){ 
/**/      array2D[i]= (int *)malloc( n*sizeof(int) );
/**/      if(NULL==array2D[i]){ printf("Fehler 2\n"); return EXIT_FAILURE;}
/**/    }
/* ----------------------------------------------------------* */
  
/* *-------- Initialisierung über main ODER Funktion --------* */
/**/  /* Initialisierung durch main Funktion*/
/**/  if(!array2d_init){
/**/    k=0;
/**/    for(i=0;i<m;i++){
/**/      for(j=0;j<n;j++){
/**/    array2D[i][j]=k;
/**/    k++;
/**/      }
/**/    }
/**/  }
/**/  
/**/  /* Initialisierung über externe Funktion */
/**/  if(array2d_init){
/**/    func2D_init(&m, &n, array2D);}
/* *---------------------------------------------------------* */
 
/* *----------- Ausgabe über main ODER Funktion -------------* */
/**/  /* Ausgabe durch main Funktion */  
/**/  if(!array2d_print){
/**/    for(i=0;i<m;i++){
/**/      for(j=0;j<n;j++){
/**/    printf("array2D[%d][%d]: %d\n",i,j,array2D[i][j]);}}
/**/  }
/**/
/**/    /* Ausgabe über externe Funktion*/
/**/  if(array2d_print){
/**/    func2D_print(&m, &n, array2D);}
/*-----------------------------------------------------------* */
 
/*-----Allozierten Speicher wieder freigeben----*/
  for(i = 0; i < n; i++){
      free(array2D[i]);}
      
  free(array2D);

return 0;
}
 
 
/* *-------------------- Funktionen -------------------------* */
/**/    /*Ausgabe*/
/**/void func2D_print(int *m, int *n, int **array2D)
/**/{
/**/  int i,j;
/**/  for(i=0;i<*m;i++){
/**/    for(j=0;j<*n;j++){
/**/      printf("array2D[%d][%d]: %d\n",i,j,array2D[i][j]);}}
/**/}
/**/
/**/    /*Array befüllen*/
/**/void func2D_init(int *m, int *n, int **array2D)
/**/{
/**/  int i,j,k;
/**/  
/**/  k=0;
/**/  for(i=0;i<*m;i++){
/**/    for(j=0;j<*n;j++){
/**/      array2D[i][j]=k;
/**/      k++;}}
/**/}
/* *---------------------------------------------------------* */

Grüße
LM
 
Zuletzt bearbeitet:
Hi.

Du solltest übrigens bei einer Funktionsdeklaration (Vorwärtsdefinition) besser den vollständigen Prototyp der Funktion angeben.

Da kann dir der Compiler dann auch helfen (warnen) falls die Argumente beim Aufruf nicht zu den Parametertypen passen. Ansonsten wunderst du dich nur zur Laufzeit warum es nicht funktioniert oder warum es abstürzt.

Also nicht so:
C:
void func2D_print();
sondern so:
C:
void func2D_print(int *, int *, int **);
Und warum übergibst du die Dimension als Zeiger? Das ist doch ziemlich unnötig und auch merkwürdig. Da würde man nämlich vermuten, das die Werte von der Funktion manipuliert werden.
 
HI deepthroat,

stimmt, dass mit der korrekten Prototypen Angabe sollte ich mir langsam mal angewöhnen!

Die Übergabe der Dimension hat erst einmal keine Bedeutung, das ist nur noch vom "Experimentieren"
übrig geblieben... .
Bevor ich Code in ein größeres Programm einfüge teste ich die Code-Schnipsel bevor es
richtig unübersichtlich wird.

Ein Beispiel wäre:
Ich habe n Datensätze mit je 1000 Werten.Array[n][1000].
Nun möchte ich nur einen bestimmten Datensatz ändern, dass wäre bspw. eine Spalte.
Und dann speichere ich die Stelle bei der der jeweiligen Datensatz das Maximum besitzt.

Grüße
-LM
 
Zurück