Quando si ha un puntatore a un puntatore in C, è necessario sapere come i dati verranno utilizzati e disposti nella memoria. Ora, il primo punto è ovvio e vero per qualsiasi variabile in generale: se non sai come verrà usata una variabile in un programma, perché farlo? :-). Il secondo punto è più interessante.
Al livello più elementare, un puntatore a tipo T
punti uno oggetto di tipo T
. Per esempio:
int i = 42;
int *pi = &i;
Ora, pi
punti per una int
. Se si desidera, è possibile fare un punto puntatore al primo di molti di questi oggetti:
int arr[10];
int *pa = arr;
int *pb = malloc(10 * sizeof *pb);
pa
ora punta alla prima di una sequenza di 10 (contigui) int
valori, e supponendo che malloc()
riesce, pb
punti al primo di un altro set di 10 (di nuovo contigui) int
s.
Lo stesso vale se si dispone di un puntatore a un puntatore:
int **ppa = malloc(10 * sizeof *ppa);
Supponendo che malloc()
riesce, ora avete ppa
che punta al primo di una serie di 10 contigui int *
valori.
Così, quando si esegue:
char **tmp = malloc(sizeof(char *)*CR_MULTIBULK_SIZE);
tmp
punti al primo char *
oggetto in una sequenza di CR_MULTIBULK_SIZE
tali oggetti. Ciascuno dei puntatori di cui sopra non è inizializzato, quindi tmp[0]
a tmp[CR_MULTIBULK_SIZE-1]
contengono tutti elementi inutili. Un modo per inizializzare loro sarebbe di malloc()
loro:
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i)
tmp[i] = malloc(...);
Il ...
sopra è la dimensione dei dati i
° vogliamo. Potrebbe essere una costante, o potrebbe essere una variabile, a seconda di i
, o della fase della luna, o un numero casuale, o qualsiasi altra cosa. Il punto principale da notare è che nel ciclo sono presenti le chiamate malloc()
a malloc()
e che mentre ogni malloc()
restituisce un blocco contiguo di memoria, l'contiguità non è garantita per le chiamate malloc()
. In altre parole, la seconda chiamata malloc()
non è garantita per restituire un puntatore che inizia esattamente dove sono finiti i dati precedenti di malloc()
.
per rendere le cose più concreto, supponiamo CR_MULTIBULK_SIZE
è 3. In foto, i tuoi dati potrebbero apparire così:
+------+ +---+---+
tmp: | |--------+ +----->| a | 0 |
+------+ | | +---+---+
| |
| |
| +------+------+------+
+-------->| 0 | 1 | 2 |
+------+------+------+
| |
| | +---+---+---+---+---+
| +--->| t | e | s | t | 0 |
+------+ +---+---+---+---+---+
|
|
| +---+---+---+
+--->| h | i | 0 |
+---+---+---+
tmp
punti ad un blocco contiguo di 3 char *
valori. Il primo dei puntatori, tmp[0]
, punta a un blocco contiguo di 3 valori char
.Allo stesso modo, tmp[1]
e tmp[2]
punto a 5 e 2 char
s rispettivamente. Ma la memoria puntata da tmp[0]
a tmp[2]
non è contigua nel suo insieme.
Dato che memcpy()
copia memoria contigua, ciò che si desidera fare non può essere eseguito da uno memcpy()
. Inoltre, è necessario sapere come è stato assegnato ciascun tmp[i]
. Quindi, in generale, ciò che si vuole fare ha bisogno di un ciclo:
char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
/* assume malloc succeeded */
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i) {
realDest[i] = malloc(size * sizeof *realDest[i]);
/* again, no error checking */
memcpy(realDest[i], tmp[i], size);
}
Come sopra, è possibile chiamare memcpy()
all'interno del ciclo, in modo da non avete bisogno di ciclo nidificato nel codice. (Molto probabilmente memcpy()
è implementata con un ciclo, quindi l'effetto è come se si fosse annidato loop.)
Ora, se si ha un codice simile:
char *s = malloc(size * CR_MULTIBULK_SIZE * sizeof *s);
size_t i;
for (i=0; i < CR_MULTIBULK_SIZE; ++i)
tmp[i] = s + i*CR_MULTIBULK_SIZE;
Vale a dire, si assegnato spazio contiguo per tutta la puntatori in una malloc()
chiamata, è possibile copiare tutti i dati senza un ciclo nel codice:
size_t i;
char **realDest = malloc(CR_MULTIBULK_SIZE * sizeof *realDest);
*realDest = malloc(size * CR_MULTIBULK_SIZE * sizeof **realDest);
memcpy(*realDest, tmp[0], size*CR_MULTIBULK_SIZE);
/* Now set realDest[1]...realDest[CR_MULTIBULK_SIZE-1] to "proper" values */
for (i=1; i < CR_MULTIBULK_SIZE; ++i)
realDest[i] = realDest[0] + i * CR_MULTIBULK_SIZE;
da quanto sopra, la risposta più semplice è, se si ha più di un malloc()
allocare memoria per tmp[i]
, quindi sarà necessario un ciclo per copiare tutti i dati.
Dipende interamente da come viene costruito il "vostro array multidimensionale". Mostra il codice che lo crea. – caf
se non si dispone delle dimensioni dell'array, non è possibile copiarlo neanche con un loop. –
@ John Knoeller: Grazie. Ho aggiornato la descrizione. – dan