Utilizzo di realloc su un array 2D c

Sono un po ‘nuovo per C dispiace se le mie domande sono un po’ vaghe;

Ho bisogno di usare realloc su un array 2D senza perdere i dati precedenti, ho questa funzione nel mio programma per farlo:

void modifyMatrix(int **iMat, int iRow, int iRow2, int iCol) { int i; iMat = (int**)realloc(iMat, (iRow2)*sizeof(int*)); for(i=iRow; i<iRow2; i++) { iMat[i]=NULL; } for(i=0; i<iRow2; i++) { iMat[i]=(int*)realloc(iMat[i], (iCol)*sizeof(int)); } } 

Dove iRow è la dimensione originale e iRow 2 e iCol sono le nuove dimensioni e vengono tutti catturati altrove nel programma.

Ogni volta che provo a stampare la matrice continuo a ricevere dati spazzatura o valori di memoria sulle righe e sulle colonne che vengono aggiunte, cosa sto facendo male?

Fatemi sapere se avete bisogno del codice completo o di altre domande per chiarire, grazie in anticipo!

Modifica: qui sotto puoi vedere il codice che uso per creare la matrice

Il mio male, penso che avrei dovuto aggiungere che Matrix è già stato creato altrove nel programma, con questa funzione sto solo cercando di modificare le dimensioni, grazie per la risposta rapida btw !, qui sotto puoi trovare la funzione con cui Sto creando l’array

 void createMatrix(int ***iMat, int iRow, int iCol) { int **iRow2 = (int**)calloc(iRow, sizeof(int*)); int i; for (i=0; i<iRow; i++) { iRow2[i] = (int*)calloc(iCol, sizeof(int)); } *iMat=iRow2; } 

Inoltre, posso usare solo l’array che ho già creato per fare questo, non posso creare uno temporaneo (che so sarebbe il modo più semplice per farlo)

In c le variabili vengono passate per valore, per questo l’ iMat all’interno di modifyMatrix() non modifica quello nella funzione del chiamante.

Devi invece passare l’indirizzo di iMat

 void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol) { int i; int **safe; safe = realloc(*iMat, iRow2 * sizeof(int *)); if (safe == NULL) return; *iMat = safe; for (i = 0 ; i < iRow ; i++) { int *keep_old_pointer; keep_old_pointer = realloc(safe[i], iCol * sizeof(int)); if (keep_old_pointer == NULL) do_something_allocation_failed(); safe[i] = keep_old_pointer; } for (int i = iRow ; i < iRow2 ; ++i) safe[i] = malloc(iCol * sizeof(int)); } 

Inoltre, non assegnare NULL a ogni elemento e quindi provare a realloc() perché se realloc() ha senso in questa situazione, si stanno sovrascrivendo i puntatori con NULL senza liberarli.

E non sovrascrivere il puntatore realloc() prima di controllare se l'allocazione è riuscita, perché se fallisce non riuscirai a liberare il puntatore precedente perché avresti perso il riferimento ad esso, causando una perdita di memoria.

Quando si passa una serie di puntatori a una funzione per realloc , in pratica si hanno 2 scelte; (1) passare l’indirizzo dell’array alla funzione (es. &array ) come parametro, il che significa che la definizione della propria funzione sarà reallocfoo (int ***array, size_t* size) o (2) assegnare il ritorno della funzione nel chiamare la routine. (es. array = reallocfoo (array, &size); )

Dato che ti sono già state date risposte per (1), vediamo come implementeresti e userai (2). Nota: non è necessario rendere la funzione del type dell’array, è sufficiente restituire un indirizzo di memoria, quindi fare uso di un puntatore void generico va bene. Per esempio:

 void *xrealloc2 (void **memptr, size_t *n) { void *tmp = realloc (memptr, *n * 2 * sizeof tmp); if (!tmp) { fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); return NULL; } memptr = tmp; memset (memptr + *n, 0, *n * sizeof tmp); *n *= 2; return memptr; } 

Inoltre , poiché si sta riallocando una serie di puntatori, non è necessario passare la dimensione del tipo (un puntatore è un puntatore è un puntatore, in tutti i casi che ci interessano). Mettendo questo a funzionare, dal momento che non si sta passando l’indirizzo della matrice, sarà necessario assegnare il ritorno per completare la riallocazione. (come hai fatto nel tuo codice sopra) ad esempio:

 if (ridx == rmax) /* if realloc is needed */ ia = xrealloc2 ((void **)ia, &rmax); 

Nota: il numero corrente di puntatori ( rmax ) viene passato come puntatore, pertanto il suo valore può essere aggiornato al doppio della funzione di riallocazione. (quindi, quando si esaurirà la volta successiva, è ansible effettuare il riallocamento in base al numero corrente aggiornato corretto). Mettendo insieme tutti i pezzi, si ottiene un breve esempio che costringe la riallocazione due volte. Inoltre, l’allocazione originale viene inserita in una funzione per mantenere in ordine il corpo principale del codice e i controlli di restituzione per l’allocazione nella funzione. (puoi decidere come gestire l’esaurimento della memoria – NULL return o exit , esempi di entrambi sono mostrati nelle due funzioni)

 #include  #include  #include  #include  #define RMAX 2 #define COLS 5 void *xcalloc (size_t n, size_t s); void *xrealloc2 (void **memptr, size_t *n); int main (void) { int **ia = NULL; size_t rmax = RMAX; size_t rows = 0; size_t ridx = 0, cidx = 0; srand (2275311); /* arbitrary repeatable seed */ ia = xcalloc (RMAX, sizeof *ia); /* intentionally force reallocation */ while (ridx < 3 * RMAX) { ia[ridx] = xcalloc (COLS, sizeof **ia); for (cidx = 0; cidx < COLS; cidx++) ia[ridx][cidx] = rand () % 1000 + 1; ridx++; if (ridx == rmax) ia = xrealloc2 ((void **)ia, &rmax); } rows = ridx; printf ("\n the reallocated 2D array elements are:\n\n"); for (ridx = 0; ridx < rows; ridx++) { for (cidx = 0; cidx < COLS; cidx++) printf (" %4d", ia[ridx][cidx]); putchar ('\n'); } putchar ('\n'); for (ridx = 0; ridx < rows; ridx++) free (ia[ridx]); free (ia); return 0; } /** xcalloc allocates memory using calloc and validates the return. * xcalloc allocates memory and reports an error if the value is * null, returning a memory address only if the value is nonzero * freeing the caller of validating within the body of code. */ void *xcalloc (size_t n, size_t s) { register void *memptr = calloc (n, s); if (memptr == 0) { fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); exit (EXIT_FAILURE); } return memptr; } /* realloc array of pointers ('memptr') to twice current * number of pointer ('*nptrs'). Note: 'nptrs' is a pointer * to the current number so that its updated value is preserved. * no pointer size is required as it is known (simply the size * of a pointer */ void *xrealloc2 (void **memptr, size_t *n) { void *tmp = realloc (memptr, *n * 2 * sizeof tmp); #ifdef DEBUG printf ("\n reallocating %zu to %zu\n", *n, *n * 2); #endif if (!tmp) { fprintf (stderr, "%s() error: virtual memory exhausted.\n", __func__); return NULL; } memptr = tmp; memset (memptr + *n, 0, *n * sizeof tmp); *n *= 2; return memptr; } 

Dopo aver compilato il codice ed eseguito, confermerà che invece delle sole 2 righe (puntatori) originariamente allocate, la riallocazione si verifica due volte aumentando tale numero a 8 (es. 2->4->8 ) quindi tutte le 6 righe di interi assegnati sono assegnati correttamente:

  the reallocated 2D array elements are: 155 573 760 410 956 553 271 624 625 934 259 291 811 161 185 756 211 16 6 449 124 869 353 210 317 310 181 897 866 831 

Se avete domande fatemi sapere. Non dimenticare, esegui sempre qualsiasi codice che assegni o ridistribuisca tramite valgrind (o un analizzatore di memoria simile) per assicurare che l'uso della memoria sia corretto e che la tua memoria libera sia allocata.

 ==29608== Memcheck, a memory error detector ==29608== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al. ==29608== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info ==29608== Command: ./bin/realloc2d ==29608== the reallocated 2D array elements are:  ==29608== ==29608== HEAP SUMMARY: ==29608== in use at exit: 0 bytes in 0 blocks ==29608== total heap usage: 9 allocs, 9 frees, 232 bytes allocated ==29608== ==29608== All heap blocks were freed -- no leaks are possible ==29608== ==29608== For counts of detected and suppressed errors, rerun with: -v ==29608== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0) 

È ansible compilare il codice sopra con il flag -DDEBUG per farlo stampare su stdout ogni volta che si rialloca e fornire il conteggio corrente dei puntatori allocati. In bocca al lupo.

In caso di successo, realloc libera il puntatore che si passa e restituisce un puntatore alla memoria appena assegnata. Stai ricevendo “valori spazzatura” perché il dereferenziamento di un puntatore alla memoria liberata è un comportamento indefinito.

Non è bello, ma il modo per sistemarlo (come ha sottolineato un’altra risposta) è passare un puntatore triplo ( int*** ). In questo modo la funzione può modificare il valore originale del puntatore. Questo è il modo in cui simula la semantica di riferimento in C, che è un linguaggio strettamente “passa per valore”.

 void modifyMatrix(int ***iMat, int iRow, int iRow2, int iCol) { int i; int **newMatrix = realloc(*iMat, iRow2 * sizeof(int*)); if (newMatrix == NULL) { /* handle realloc error here */ } else { *iMat = newMatrix; /* assign pointer to the new memory */ } for(i=iRow; i 

Devi anche aggiungere un controllo degli errori. Se realloc fallisce e restituisce un puntatore NULL, hai appena creato una perdita di memoria: non hai più il valore precedente del puntatore.

Nota che ho rimosso tutti i tuoi cast. È una ctriggers pratica lanciare il malloc e gli amici in C.