2015-02-22 5 views
7

Wie ordnen und deklarieren Sie ein 3D-Array von Strukturen in C? Ordnen Sie das Array zuerst zu oder deklarieren Sie es? Ich habe das Gefühl, dass Sie es zuerst zuweisen müssen, damit Sie es so deklarieren können, dass es auf dem Heap ist, aber wie ordnen Sie dann etwas zu, das noch nicht gemacht wurde? Auch sollten Sie es alle auf einmal oder Element für Element zuweisen? Auch ich die Strukturen in das Array richtig setzen? Meine Vermutung auf, wie es zu tun wäre:Wie ein 3D von Array von Strukturen in C zuweisen und deklarieren?

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 Beratung über die Verwendung von '.h' und' .c' Dateien: http://Stackoverflow.com/q/3482948/2186301 – yulian

Antwort

1

Es gibt ein paar verschiedene Möglichkeiten, dies zu tun, je nachdem, was Sie wollen. Erstens können Sie Ihr Array auf dem Stapel (in C99 und einige Compiler) wie folgt vergeben:

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

Wenn Sie es auf dem Heap zugewiesen wollen, dann können Sie eine einzelne Zuordnung der entsprechenden Größe tun. Sie können dann entweder tun die Indexberechnung selbst oder einen Zeiger für Sie tun die Arbeit machen (in C99 und einige Compiler):

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 */ 

Oder Sie können die verschiedenen Dimensionen manuell zuordnen.

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

Diese letzte Version verwendet für alle expliziten Zeiger viel mehr Speicher enthält, ist seine Speicherlokalizität schlechter und es ist wesentlich komplexer, um richtig zuzuordnen und zurückzufordern. Es erlaubt jedoch verschiedene Größen entlang Ihrer Dimensionen. Zum Beispiel kann das Array arr[0][4] eine andere Größe alshaben, wenn Sie das jemals brauchen.

Wenn Sie es auf dem Heap zuordnen möchten, dann möchten Sie wahrscheinlich die zweite Version mit einer einzigen Zuordnung und Multi-Dimensionszeiger (falls verfügbar) oder die Indexierung manuell mit entsprechenden Mathe tun.

+0

Warum myStruct **? Warum zwei * statt drei? Wenn ich mit der Größe von arr zuweisen wollte, würde die Zeile lesen arr = calloc (length, sizeof (struct *** arr)); ? – wolfclique

+1

arr wird als Struktur myStruct *** deklariert. Es benutzt 3 * s. Wenn Sie Calloc/Malloc aufrufen, weist der Rückgabewert eine weitere Indirektion gegenüber dem Typ auf, den Sie zugewiesen haben. So gibt zum Beispiel das Calloc der obersten Ebene eine Struktur myStruct *** zurück, weil wir ein Array von struct myStruct ** zugeordnet haben. Wenn Sie sizeof für einen Ausdruck von arr verwenden, fügen Sie die Struktur nicht wieder hinzu. Sie würden einfach sizeof (*** arr) sagen, was äquivalent zu sizeof (struct myStruct) wäre. – jschultz410

+0

@ jschultz410 Du denkst, dass 'malloc()' immer magisch funktioniert und niemals fehlschlägt? Ihr Code hat ein potentielles undefiniertes Verhalten, schreibt einen sicheren Code und lehrt das. Wenn der OP Ihren Code mehr mag, dann werden Sie eines dieser Tage eine seiner Anwendungen verwenden, und plötzlich wird es abstürzen oder so etwas. –

1

Der einfache Weg ist:

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

Dann ist Ihre Schleife arr2[x][y][z].a = rand(); und auf so zugreifen können. Wenn Sie mit dieser Art des Anrufens nicht vertraut sind: calloc, see here. Wie bei malloc üblich, überprüfen Sie arr2 gegen NULL, bevor Sie fortfahren.

Der Triple-Pointer-Ansatz ist keine wirklich praktische Lösung. Wenn Ihr Compiler nicht variabel modifizierte Typen unterstützt, sollte das Array auf 1-D reduziert werden.

+1

Wie @Forss angemerkt hat, wurden Arrays variabler Länge (und Zeiger auf solche) in C11 leider zu einem optionalen Feature gemacht. – jschultz410

+0

@ jschultz410 das bedeutet nicht, dass sie nicht verwendet werden sollten, wo verfügbar. Guter Code kann auf allen guten Compilern funktionieren, und wenn er auf C89 oder Lazy-Vendor-C11 ausgeführt werden muss, können Sie eine hässliche Option verwenden (wo ich Flattern und nicht Triple Pointering empfehle) –

+0

Ja, da stimme ich vollkommen zu. Ich finde es nur schade, dass der C11-Standard einen zuvor obligatorischen Teil (VLAs in C99) jetzt optional gemacht hat. Visual Studio * ist ziemlich weit verbreitet unter Windows und dieser Code wird nicht auf AFAIK kompiliert. – jschultz410