2012-04-12 19 views
22

Scrivo codice C e vorrei allocare 512 * 256 byte. Per mia comodità mi piacerebbe poter accedere agli elementi con l'array di sintassi [a] [b]; nessuna aritmetica per trovare l'indice giusto.Heap alloca un array 2D (non un array di puntatori)

Ogni tutorial che vedo online mi dice di creare una serie di puntatori che puntano agli array delle righe che voglio nel mio array. Ciò significa che ogni subarray deve essere malloc'd e free'd individualmente. Mi interessa una soluzione che richiede solo una chiamata a malloc e una chiamata a free. (Quindi tutti gli elementi sono contigui) Penso che questo sia possibile perché non costruirò una matrice seghettata.

Apprezzerei se qualcuno potesse condividere la sintassi per dichiarare un tale array.

+1

C++ è un'opzione? È possibile creare un oggetto C++ semplice che sovraccarichi l'operatore di indicizzazione. –

+4

@ RichardJ.RossIII: È davvero una risposta valida a una domanda di "come faccio questo in C?" (rendendosi conto che * l'hai * lasciato come commento). Prenderò C over C++ ogni giorno grazie. –

+0

@ Eds. anche se preferisci C, C++ è meglio in alcune situazioni, e questo sarebbe uno di questi. L'ho lasciato come commento semplicemente per determinare se sarebbe stata un'opzione. –

risposta

34

Bene, se si desidera allocare un array di tipo, lo si assegna a un puntatore di quel tipo.

Poiché array 2D sono array di array (nel caso, un array di 512 array di 256 caratteri), è necessario assegnare in un puntatore a vettore di 256 caratteri:

char (*arr)[256]=malloc(512*256); 
//Now, you can, for example: 
arr[500][200]=75; 

(Le parentesi attorno *arr devono essere un puntatore all'array e non un array di puntatori)

+0

+1, in qualche modo mi sono perso che l'hai postato mentre stavo scrivendo la mia risposta. :-) –

+0

Questo è esattamente quello che stavo cercando. Grazie. – Paul

+3

Si noti che dal C99 le dimensioni non devono più essere conosciute in fase di compilazione. Puoi avere 'n, m' leggere da stdin e dichiarare un' char arr [n] [m] 'o, in questo caso, un' char (* arr) [n] '. – Kos

14

Se si assegna la matrice in questo modo, richiede due chiamate a free, ma consente la sintassi di stile array[a][b] ed è contigua.

char **array = malloc(512 * sizeof(char *)); 
array[0] = malloc(512*256); 
for (int i = 1; i < 512; i++) 
    array[i] = array[0] + (256 * i); 

Vedi array2 qui per maggiori informazioni: http://c-faq.com/aryptr/dynmuldimary.html

+0

È un bel trucco! +1 –

+3

È possibile combinare le due allocazioni mettendo il blocco dati immediatamente dopo il vettore di droga. Richiede una certa quantità di typecasting, ma non è così difficile. Comunque, il tuo codice come mostrato ha un bug serio: tu alleni uno spazio per 512 'char's, e poi lo tratti come spazio sufficiente per 512' char * 's. Questo è quasi garantito per uscire dalla fine dell'allocazione e crash. – zwol

+0

Oops typo, dovrebbe farlo ... –

5

Dal momento che si conosce la dimensione della matrice prima del tempo, è possibile creare un tipo di struct che contiene una matrice di 521x256, e quindi allocare dinamicamente la struct.

2

Se si conosce la dimensione dell'array, è possibile eseguire typedef e puntare un puntatore. Ecco un breve frammento che illustra questo uso:

#include <stdio.h> 
#include <stdlib.h> 

typedef int array2d[20][20]; 

int main() { 
    int i,j; 
    array2d *a = malloc(sizeof(array2d)); 
    for(i=0;i!=20;i++) 
     for(j=0;j!=20;j++) 
      (*a)[i][j] = i + j; 

    for(i=0;i!=20;i++) 
     for(j=0;j!=20;j++) 
      printf("%d ",(*a)[i][j]); 
    free(a); 
    return 0; 
} 
+0

Soluzione interessante, esiste un modo per capire come farlo con un array dinamico? –

+0

@ RichardJ.RossIII Sfortunatamente, questo non funziona con array di dimensioni dinamiche, perché typedef richiede costanti in fase di compilazione per entrambe le dimensioni. Il meglio che puoi fare è rendere fissa una dimensione e l'altra dinamica, ma non renderla completamente dinamica. – dasblinkenlight

+0

Il typedef non è necessario e in realtà è dannoso mettere entrambe le dimensioni nel typedef dato che sei bloccato usando '(* a)' dappertutto invece che semplicemente 'a'. Se metti solo il numero di colonne, funzionerebbe molto meglio. E ovviamente con C99, puoi rendere il tipo variabilmente modificato; Credo che questo sia valido anche in un typedef purché typedef abbia scope di blocco piuttosto che scope di file. –

2

E è possibile allocare dinamicamente lo stesso tipo di array multidimensionale che

static char x[512][256]; 

ti dà, ma è un wee difficile perché di tipo decadimento. So solo come si fa con un typedef:

typedef char row[512]; 
row *x = malloc(sizeof(row) * 256); 

Questo solo consente di determinare la dimensione della seconda dimensione in fase di esecuzione. Se entrambe le dimensioni possono variare in fase di esecuzione, è necessario un vettore di droga.

+0

Manca anche questo. Nota che, a meno che tu non sia limitato a C89, entrambe le dimensioni possono variare; hai solo bisogno di usare un tipo di puntatore modificato in modo variabile. –

11

Ciò è facile presumendo che non sia necessaria la compatibilità con l'antico standard C89 (tra gli attuali compilatori C, solo MSVC e alcuni target incorporati i compilatori sono così arretrati). Ecco come si fa:

int (*array)[cols] = malloc(rows * sizeof *array); 

Poi array[a][b] è valido per qualsiasi a in [0,rows) e b in [0,cols).

Nella lingua dello standard C, array ha tipo variabile. Se si desidera passare il puntatore ad altre funzioni, è necessario ripetere questo tipo nell'elenco di argomenti della funzione e assicurarsi che almeno il numero di colonne sia passato alla funzione (poiché è necessario come parte della variabile modificata genere).

Modifica: Ho perso il fatto che OP si preoccupa solo di una dimensione fissa, 512x256. In tal caso, C89 sarà sufficiente, e tutto ciò che serve è:

int (*array)[256] = malloc(512 * sizeof *array); 

Lo stesso tipo può essere utilizzato in liste funzione degli argomenti se è necessario passare il puntatore tra le funzioni (e anche come un tipo di funzione di ritorno , ma per questo uso si potrebbe voler digitare typedef ... :-)

+0

Hai ragione nel caso generale, ma l'OP vuole solo un array 512 * 256. – asaelr

+0

Infatti, aggiornerò la risposta. –

+0

In realtà, questa risposta è eccellente. Anche se ora ho solo bisogno di 512 * 256, potrei facilmente vedere questo requisito cambiare in futuro. – Paul