2015-02-22 14 views
7

Come si assegna e si dichiara un array 3D di strutture in C? Assegnate prima la matrice o la dichiarate? Mi sento come se dovessi allocarlo prima in modo da poterlo dichiarare così è nell'heap, ma come allocare qualcosa che non è stato ancora creato? Inoltre, dovresti allocarlo tutto in una volta o elemento per elemento? Inoltre sto inserendo correttamente le strutture nell'array? mia ipotesi su come farlo sarebbe:Come allocare e dichiarare un 3D di matrice di strutture in C?

header.h

struct myStruct{ 
    int a; 
    int b; 
}; 
typedef struct myStruct myStruct_t; 

main.c

#include "header.h" 
#include <stdio.h> 
#include <stdlib.h> 
int main(void){ 

    int length=2; 
    int height=3; 
    int width =4; 
    myStruct_t *elements; 
    struct myStruct arr = (*myStruct_t) calloc(length*height*width, sizeof(myStruct); 
    //zero based array 
    arr[length-1][height-1][width-1]; 

    int x=0; 
    while(x<length){ 
     int y=0; 
     while(y<height){ 
      int z=0; 
      while(z<depth){ 
       arr[x][y][z].a=rand(); 
       arr[x][y][z].b=rand(); 
       z++; 
      } 
      y++; 
     } 
     x++; 
    } 
    return 0; 
}  
+0

Off-topic di consigliare sull'utilizzo di file '.h' e' .c': http://stackoverflow.com/q/3482948/2186301 – yulian

risposta

1

Ci sono un paio di modi diversi per fare questo, dipende da cosa vuoi In primo luogo, è possibile allocare la matrice sullo stack (in C99 e alcuni compilatori) come questo:

myStruct_t arr[length][height][depth]; 

Se lo vuoi allocato sul mucchio, allora si può fare una dotazione unica di dimensioni adeguate. È quindi possibile fare il calcolo dell'indice da soli o fare un puntatore fare il lavoro per voi (in C99 e alcuni compilatori):

void *buf = malloc(length * height * width * sizeof(myStruct_t)); 
myStruct_t *arr = buf; 
myStruct_t (*arr2)[height][width] = buf; 

/* TODO: check return of malloc */ 
... 

arr[x * height * width + y * width + z].a = rand(); /* indexing the C89 way */ 
arr2[x][y][z].b = rand();       /* indexing the C99 way */ 

Oppure è possibile assegnare manualmente le molteplici dimensioni.

#include <stddef.h> 
#include <stdlib.h> 

typedef struct myStruct 
{ 
    int a, b; 

} myStruct_t; 

int main() 
{ 
    myStruct_t ***arr; 
    int length = 5000, height = 1000, depth = 20; 
    int x, y, z; 
    int ret = 1; 

    if (NULL == (arr = malloc(length * sizeof(myStruct_t**)))) 
    goto FAIL; 

    for (x = 0; x < length; ++x) 
    { 
    if (NULL == (arr[x] = malloc(height * sizeof(myStruct_t*)))) 
     goto FAIL_X; 

    for (y = 0; y < height; ++y) 
    { 
     if (NULL == (arr[x][y] = malloc(depth * sizeof(myStruct_t)))) 
     goto FAIL_Y; 

     for (z = 0; z < depth; ++z) 
     { 
     arr[x][y][z].a = rand(); 
     arr[x][y][z].b = rand(); 
     } 
    } 
    } 

    /* TODO: rest of program logic */ 

    /* program successfully completed */ 

    ret = 0; 

    /* reclaim arr */ 

FAIL_CLEANUP: /* label used by TODO code that fails */ 

    for (x = length - 1; x >= 0; --x) 
    { 
    for (y = height - 1; y >= 0; --y) 
    { 
     free(arr[x][y]); 
    FAIL_Y: 
     ; 
    } 

    free(arr[x]); 
    FAIL_X: 
    ; 
    } 

    free(arr); 

FAIL:  
    return ret; 
} 

Quest'ultima versione utilizza molta più memoria per tutti i puntatori espliciti che contiene, la sua località memoria è peggio ed è molto più complessa di allocare correttamente e recuperare. Tuttavia, consente dimensioni diverse lungo le tue dimensioni. Ad esempio, l'array arr[0][4] può avere una dimensione diversa da arr[0][7] se è necessario.

Se si desidera allocarlo nell'heap, è probabile che si desideri la seconda versione con un puntatore a allocazione singola e multidimensionale (se disponibile) oppure eseguire manualmente l'indicizzazione utilizzando la matematica appropriata.

+0

Perché myStruct **? Perché due * invece di 3? Se volessi allocare con la dimensione di arr, la riga dovrebbe leggere arr = calloc (length, sizeof (struct *** arr)); ? – wolfclique

+1

arr è dichiarato come struct myStruct ***. Usa i 3 *. Quando chiami calloc/malloc il valore di ritorno ha un valore più indiretto rispetto al tipo che hai assegnato. Quindi, ad esempio, il calloc di primo livello restituisce una struct myStruct ***, perché abbiamo assegnato un array di struct myStruct **. Quando si usa sizeof su un'espressione di arr, non si aggiunge la struct. Si direbbe semplicemente sizeof (*** arr), che sarebbe equivalente a sizeof (struct myStruct). – jschultz410

+0

@ jschultz410 Pensi che 'malloc()' funzioni sempre magicamente e non fallisce mai? Il tuo codice ha un potenziale comportamento indefinito, scrive codice sicuro e insegna questo. Se all'OP piace più il tuo codice, allora uno di questi giorni userà una delle sue applicazioni, e all'improvviso si bloccherà o qualcosa del genere. –

1

Il modo più semplice è:

myStruct_t (*arr2)[height][width] = calloc(length * sizeof *arr); 

Poi il ciclo può accedere arr2[x][y][z].a = rand(); e così via. Se non hai familiarità con questo modo di chiamare calloc, see here. Come al solito con malloc, controllare arr2 contro NULL prima di procedere.

L'approccio a triplo puntatore non è una soluzione pratica. Se il compilatore non supporta i tipi modificati in modo variabile, l'array deve essere appiattito su 1-D.

+1

Come notato da @Forss, le matrici di lunghezza variabile (e i puntatori a tali) sono state rese purtroppo una caratteristica opzionale in C11. – jschultz410

+0

@ jschultz410 che non significa che non dovrebbero essere usati dove disponibili. Un bel codice può funzionare su tutti i buoni compilatori, e se deve essere eseguito su C89 o Lazy-vendor-C11, allora puoi usare un'opzione brutta (dove consiglio l'appiattimento e non il triplo puntatore) –

+0

Sì, sono completamente d'accordo. Trovo solo un peccato che lo standard C11 abbia reso una parte precedentemente obbligatoria (VLAs in C99) ora opzionale. Visual Studio * è abbastanza diffuso su Windows e questo codice non verrà compilato su di esso AFAIK. – jschultz410

Problemi correlati