2010-05-15 11 views
6

ieri avevo postato una domanda: How should I pass a pointer to a function and allocate memory for the passed pointer from inside the called function?programmazione C: malloc() per una matrice 2D (con puntatore a puntatore)

Dalle risposte che ho ricevuto, sono stato in grado di capire che cosa errore che stavo facendo.

Sto affrontando un nuovo problema ora, qualcuno può aiutare con questo?

voglio allocare dinamicamente una matrice 2D, quindi sto passando un puntatore a puntatore dal mio main() ad un'altra funzione chiamata alloc_2D_pixels(...), dove io uso malloc(...) e for(...) ciclo per allocare memoria per la matrice 2D.

Ebbene, dopo il ritorno dalla funzione alloc_2D_pixels(...), il puntatore puntatore a NULL rimane ancora, così naturalmente, quando provo l'accesso o cercare di free(...) il puntatore-a-Pointer, il programma si blocca.

Qualcuno può suggerirmi quali errori sto facendo qui?

Aiuto !!!

Vikram


FONTE:

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); 
} 

risposta

3

Un errore sta postando codice che non verrà compilato :). Qui di seguito viene corretto il codice con i miei commenti in
/* questo stile * /:

/* 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 !!! :) Sì, hai ragione, avrei dovuto pubblicare un codice funzionante. Grazie per la tua risposta dettagliata, lo apprezzo. – HaggarTheHorrible

2

Nella funzione alloc_2D_pixels, è necessario un altro livello di indirezione quando si accede memory. Come è ora, si modifica solo il parametro, non il puntatore puntato dal parametro. Ad esempio,

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)); 

(in pratica, ovunque si sta utilizzando memory, è necessario utilizzare (*memory); le parentesi sono necessarie solo quando si utilizza indici per garantire che gli operatori vengono applicati nell'ordine corretto)

+1

Dovrebbe essere sizeof (unsigned char *) not unsigned char ** anche. –

+0

IMHO, è veramente 'memoria = malloc (righe * sizeof ** memoria)' e '(* memoria) [i] = malloc (cols * sizeof * (* memoria) [i])', cioè sempre uno extra '*' sotto 'sizeof'. Molto più a prova di errore. – AnT

1

Sembra anche che tu stia usando le variabili non inizializzate rows e cols

1

Usando gli array multidimensionali in questo modo in C è "ottimale" per le prestazioni.

In parole non chiare: Si prega di non utilizzare - e sicuramente non inizializzare - gli array multidimensionali nel modo in cui hai illustrato. Più chiamate a malloc() creeranno un lotto di posizioni di memoria disgiunte che non si adattano bene al modo in cui i grafici reali (come contigui, singoli buffer) vengono memorizzati ovunque. Inoltre, se devi farlo centinaia o migliaia di volte, lo malloc() può essere orribilmente costoso.

Inoltre, a causa del fatto che stai usando malloc() molto spesso, è anche un incubo (e bug per morderti alla fine) per la pulizia. Ne hai persino parlato nei commenti nel tuo codice, eppure ... perché?

Se è assolutamente necessario disporre di questo ptr[rows][cols] cosa, crearlo meglio così:

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; 
} 

in questo modo si sta assegnando solo un singolo blocco di memoria e il tutto può essere liberato in un colpo solo - fosso free_2D_pixels().

+0

Ah, sarei stato sorpreso se nessun altro avesse risposto a questo in passato. Credito in cui il credito è dovuto: http://stackoverflow.com/questions/3144132/malloc-in-c-but-use-multi-dimensional-array-syntax/3144577#3144577 vedere lì. –

Problemi correlati