2010-05-15 4 views
6

gestern habe ich eine Frage gestellt hatte: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?C-Programmierung: malloc() für ein 2D-Array (mit Pointer-to-Zeiger)

Aus den Antworten, die ich bekam, konnte ich verstehen, welche Fehler ich tat.

Ich stehe jetzt vor einem neuen Problem, kann mir jemand dabei helfen?

Ich möchte ein 2D-Array dynamisch zuzuweisen, so bin ich vorbei einen Pointer-to-Pointer von meinem main() auf eine andere Funktion alloc_2D_pixels(...) genannt, wo ich malloc(...) und for(...) Schleife verwenden, um Speicher für das 2D-Array zuzuordnen.

Nun, nach der Rückkehr von der -Funktion bleibt der Zeiger-Zeiger immer noch NULL, so natürlich, wenn ich versuche, auf den Zeiger-zu-Zeiger zuzugreifen oder versuchen, free(...), hängt das Programm.

Kann mir jemand vorschlagen, welche Fehler ich hier mache?

Hilfe !!!

Vikram


QUELLE:

main() 
{ 


unsigned char **ptr; 
unsigned int rows, cols; 

if(alloc_2D_pixels(&ptr, rows, cols)==ERROR)  // Satisfies this condition 
    printf("Memory for the 2D array not allocated"); // NO ERROR is returned 

if(ptr == NULL)     // ptr is NULL so no memory was allocated 
    printf("Yes its NULL!");   

// Because ptr is NULL, with any of these 3 statements below the program HANGS 
ptr[0][0] = 10;      
printf("Element: %d",ptr[0][0]); 

free_2D_alloc(&ptr); 

} 


signed char alloc_2D_pixels(unsigned char ***memory, unsigned int rows, unsigned int cols) 
{ 
     signed char status = NO_ERROR; 

     memory = malloc(rows * sizeof(unsigned char**)); 

     if(memory == NULL) 
     { 
      status = ERROR; 
      printf("ERROR: Memory allocation failed!"); 

     } 
     else 
     { 
      int i; 

      for(i = 0; i< cols; i++) 
      { 
       memory[i] = malloc(cols * sizeof(unsigned char)); 

       if(memory[i]==NULL) 
       { 
        status = ERROR; 
        printf("ERROR: Memory allocation failed!"); 
       } 
      } 

     } 

    // Inserted the statements below for debug purpose only 
     memory[0][0] = (unsigned char)10;  // I'm able to access the array from 
     printf("\nElement %d",memory[0][0]); // here with no problems 


     return status; 
} 


void free_2D_pixels(unsigned char ***ptr, unsigned int rows) 
{ 
    int i; 

    for(i = 0; i < rows; i++) 
    { 
      free(ptr[i]); 
    } 

    free(ptr); 
} 

Antwort

3

Ein Fehler ist Buchung Code, der nicht kompilieren wird :). Unten korrigiert Code mit meinen Kommentaren in
/* dieser Art * /:

/* Next four lines get your code to compile */ 
#include <stdio.h> 
#include <stdlib.h> 
#define NO_ERROR 0 
#define ERROR 1 

/* prototypes for functions used by main but declared after main 
    (or move main to the end of the file */ 
signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols); 
void free_2D_pixels(unsigned char** ptr, unsigned int rows); 

/* main should return int */ 
int main() 
{ 
    unsigned char** ptr; 
    /* need to define rows and cols with an actual value */ 
    unsigned int rows = 5, cols = 5; 

    if(alloc_2D_pixels(&ptr, rows, cols) == ERROR) // Satisfies this condition 
     printf("Memory for the 2D array not allocated"); // ERROR is returned 

    if(ptr == NULL)     // ptr is NULL so no memory was allocated 
     printf("Yes its NULL!"); 
    else 
    { 
     /* Added else clause so below code only runs if allocation worked. */ 
     /* Added code to write to every element as a test. */ 
     unsigned int row,col; 
     for(row = 0; row < rows; row++) 
      for(col = 0; col < cols; col++) 
       ptr[0][0] = (unsigned char)(row + col); 

      /* no need for &ptr here, not returning anything so no need to pass 
       by reference */ 
      free_2D_pixels(ptr, rows); 
    } 

    return 0; 
} 

signed char alloc_2D_pixels(unsigned char*** memory, unsigned int rows, unsigned int cols) 
{ 
    signed char status = NO_ERROR; 

    /* In case we fail the returned memory ptr will be initialized */ 
    *memory = NULL; 

    /* defining a temp ptr, otherwise would have to use (*memory) everywhere 
     ptr is used (yuck) */ 
    unsigned char** ptr; 

    /* Each row should only contain an unsigned char*, not an unsigned 
     char**, because each row will be an array of unsigned char */ 
    ptr = malloc(rows * sizeof(unsigned char*)); 

    if(ptr == NULL) 
    { 
     status = ERROR; 
     printf("ERROR: Memory allocation failed!"); 
    } 
    else 
    { 
     /* rows/cols are unsigned, so this should be too */ 
     unsigned int i; 

     /* had an error here. alloced rows above so iterate through rows 
      not cols here */ 
     for(i = 0; i < rows; i++) 
     { 
      ptr[i] = malloc(cols * sizeof(unsigned char)); 

      if(ptr[i] == NULL) 
      { 
       status = ERROR; 
       printf("ERROR: Memory allocation failed!"); 
       /* still a problem here, if exiting with error, 
        should free any column mallocs that were 
        successful. */ 
      } 
     } 
    } 

    /* it worked so return ptr */ 
    *memory = ptr; 
    return status; 
} 


/* no need for *** here. Not modifying and returning ptr */ 
/* it also was a bug...would've needed (*ptr) everywhere below */ 
void free_2D_pixels(unsigned char** ptr, unsigned int rows) 
{ 
    /* should be unsigned like rows */ 
    unsigned int i; 

    for(i = 0; i < rows; i++) 
    { 
     free(ptr[i]); 
    } 

    free(ptr); 
} 
+0

Hey Mark !!! :) Ja, du hast recht, ich hätte einen funktionierenden Code schreiben sollen. Danke für Ihre ausführliche Antwort, ich weiß es zu schätzen. – HaggarTheHorrible

2

In Ihrer alloc_2D_pixels Funktion benötigen Sie eine andere Dereferenzierungsebene wenn memory erreichbar. Wie es jetzt ist, ändern Sie nur den Parameter, nicht den Zeiger, auf den der Parameter zeigt. Zum Beispiel

memory = malloc(rows * sizeof(unsigned char**)); 
// becomes 
*memory = malloc(rows * sizeof(unsigned char**)); 

// and later... 
memory[i] = malloc(cols * sizeof(unsigned char)); 
// becomes 
(*memory)[i] = malloc(cols * sizeof(unsigned char)); 

(im Grunde genommen überall Sie verwenden memory, müssen Sie (*memory) verwenden, die Klammern werden nur benötigt, wenn Sie Indizes zu gewährleisten, verwenden, dass die Betreiber in der richtigen Reihenfolge angewendet werden)

+1

Sollte sizeof (unsigned char *) nicht vorzeichenlosen char ** auch sein. –

+0

IMHO, es sollte wirklich sein '* memory = malloc (rows * sizeof ** Speicher)' und '(* Speicher) [i] = malloc (cols * sizeof * (* Speicher) [i])', dh immer eine extra '*' unter der 'sizeof'. Viel fehlerfreier. – AnT

1

Es sieht auch so aus, Sie verwenden nicht initialisiert rows und cols Variablen

1

in C auf diese Weise mehrdimensionale Arrays zu verwenden ist "suboptimal" für die Leistung.

In keinen unklaren Worten: Bitte verwenden Sie nicht - und definitiv nicht initialisieren - multidimensionale Arrays in der Art, wie Sie dargestellt haben. Mehrere Aufrufe an malloc() erstellen Ihnen einen Stapel von nicht zusammenhängenden Speicherorten, die nicht gut darauf abbilden, wie tatsächliche Grafiken (als zusammenhängende einzelne Puffer) überall gespeichert werden. Auch, wenn Sie es Hunderte oder Tausende Male tun müssen, malloc() kann schrecklich teuer sein.

Aufgrund der Tatsache, dass Sie malloc() sehr oft verwenden, ist es auch ein Albtraum (und Bug, um Sie schließlich zu beißen) zum Aufräumen. Sie haben das sogar in den Kommentaren in Ihrem Code erwähnt, und doch ... warum?

Wenn Sie unbedingt diese ptr[rows][cols] Sache haben muss, schaffen es besser so:

signed char alloc_2D_pixels(unsigned char*** memory, 
          unsigned int rows, 
          unsigned int cols) 
{ 
    int colspan = cols * sizeof(char); 
    int rowspan = rows * sizeof(char*); 
    unsigned char **rowptrs = *memory = malloc(rowspan + rows * colspan)); 

    /* malloc failure handling left to the reader */ 

    unsigned char *payload = ((unsigned char *)rowptrs) + rowspan; 
    int i; 
    for (i = 0; i < rows; payload += colspan, i++) 
     rowptrs[i] = payload; 
} 

auf diese Weise nur einen einzigen Speicherblock und das Ganze sind Zuteilung können in einem Rutsch befreit werden - Graben free_2D_pixels().

+0

Ah, wäre überrascht gewesen, wenn niemand anderes in der Vergangenheit geantwortet hätte. Kredit, wo Kredit fällig ist: http://stackoverflow.com/questions/3144132/malloc-in-c-but-use-multi-dimensional-array-syntax/3144577#3144577 siehe dort. –