2016-09-20 10 views
0

Ich habe die folgenden zwei Strukturen:Wie kann ich auf ein Array von Strukturen innerhalb einer Struktur zugreifen?

typedef struct stack * StackPtr; 
typedef struct book * BookPtr; 

struct book { 
    char *title; 
    int pages; 
}; 

struct stack { 
    int num_books; 
    Book array[50] // changed from Book *array[50] 
}; 

Hier ist, wie ich Initialisierung jede Struktur:

StackPtr create_stack(void) { 
    StackPtr s = malloc(sizeof(struct stack)); 
    s->num_books = 0; 
    return s; 
} 

BookPtr create_book(char *title, int pages) { 
    BookPtr b = malloc(sizeof(struct book)); 
    b->title = strdup(title); 
    b->pages = pages; 
    return b; 
} 

Ich versuche, den Titel und die Seiten des Buches innerhalb des Array zuzugreifen die Stapelstruktur Dies ist, wie ich es tue:

Zum Beispiel, wenn ich den Titel und den Seiten des letzten Buches in der Struktur zugreifen möchten, und ändern, ich bin dong dies:

(s->array[s->num_books-1])->title = strdup(new_title); 
(s->array[s->num_books-1])->pages = new_pages; 

Aber ich bin immer diese Fehlermeldung:

error: member reference base type 'Book' (aka 'struct book *') is not a structure or union 
     (s->array[s->num_books-1])->title = strdup(new_title); 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~^ ~~~~~ 

Edit: nachdem ich den Zeiger von Book *array[50]; ich immer diese Fehlermeldung bin jetzt entfernt:

error: incomplete definition of type 'struct book' 
     (s->array[s->num_books-1])->title = strdup(new_title); 
     ~~~~~~~~~~~~~~~~~~~~~~~~~~^ 

Ich dachte, dies sei ein Problem, da main die Buchstruktur nicht sehen konnte, also habe ich keine Headerdateien mehr verwendet und alles in eine Datei geschrieben, aber das half nicht.

Ich denke auch, dass ich den Stapel nicht richtig initialisieren.

Wenn ich versuche, das Array in der create_stack Funktion wie folgt zu initialisieren:

s->array = malloc(sizeof(BookPtr) * 50); //inside create_array function 

Dies ist der Fehler, den ich bekommen:

array type 'BookPtr *[50]' is not assignable 
+1

'Buch * Array [50];' erstellt ein * Array von Zeigern zu Buch 50 * nicht * 50 struct Buch *. –

+2

'typedef struct stack * Stack;' ist ein irreführender 'typedef'. Verwenden Sie 'typedef struct stack Stack;' oder 'typedef struct stack * StackPtr;' –

+0

@David Können Sie das bitte näher ausführen? – user6005857

Antwort

1

Es ist unklar, ob Sie das jemals gelöst haben, vielleicht hilft ein kurzes Beispiel. Unabhängig davon, ob Sie Speicher für X Anzahl der Bücher in array am Anfang erstellen oder array als ein Array von X-Zeiger auf Bücher erstellen, müssen Sie sicherstellen, dass Sie nicht mehr Bücher hinzufügen, als Sie speichern können. Die offensichtliche Möglichkeit, dies zu umgehen, ist das Hinzufügen einer zusätzlichen Variablen zu Ihrer stack-Struktur, die den Speicher (oder die Anzahl der verfügbaren Zeiger) in array und dann reallocarray nach Bedarf verfolgt. Um den Raum in array verfügbar zu verfolgen, könnten Sie einfach einen weiteren Zähler hinzufügen, sagen wir max_books, z.B.

enum { NBOOKS = 10 }; 

typedef struct { 
    char *title; 
    int pages; 
} book; 

typedef struct { 
    int num_books, 
     max_books; 
    book *array; 
} stack; 

Da es in Deklaration einer array als Array von Zeigern kein Vorteil ist, wenn man einfach Speicher für jedes Buch erstellen werden, können Sie auch erklären, nur Array als book *array; und Speicher zuordnen für einige einigermaßen voraussichtliche Anzahl der Bücher, um damit zu beginnen. Dein create_stack ist nicht weit weg, aber ich würde add_book ein wenig anders machen, um den Stack zu erstellen, wenn es momentan NULL und realloc wie benötigt ist. So etwas wie die folgenden:

/** since add_book may create the stack, you must pass the address 
* of the stack to add_book so that any changes to s are available 
* back in the calling funciton. 
*/ 
book *add_book (stack **s, char *title, int pages) 
{ 
    if (!title) return NULL;  /* validate title */ 
    if (!*s) *s = create_stack(); /* if stack NULL, create */ 

    /* check num_books against max_books and realloc as required */ 
    if ((*s)->num_books == (*s)->max_books) { 
     void *tmp = realloc ((*s)->array, ((*s)->max_books + NBOOKS) * 
          sizeof *((*s)->array)); 
     if (!tmp) { 
      fprintf (stderr, "error: memory exhausted - realloc array.\n"); 
      return NULL; 
     } 
     (*s)->array = tmp; 
     (*s)->max_books += NBOOKS; 
    } 

    /* allocate/copy title, assign pages, increment num_books */ 
    (*s)->array[(*s)->num_books].title = strdup (title); 
    (*s)->array[(*s)->num_books].pages = pages; 
    ((*s)->num_books)++; 

    /* change return as desired, I just return the address of the book 
    * to indicate success and provide a way to validate the add. 
    */ 
    return &((*s)->array[(*s)->num_books - 1]); 
} 

(note: der Kommentar, warum der Stapel der Funktion als stack ** übergeben wird)

Das sind im Grunde die Änderungen, die Sie benötigen würde Ihre Stapel Bücher erstellen das würde Ihnen erlauben, so viele Bücher hinzuzufügen, wie Sie möchten (bis Sie den Speicher Ihres Computers erschöpfen). das Beispiel zusammen setzen, können Sie so etwas wie die folgenden tun (Anmerkung: die Konstante NBOOKS als Null größer sein müssen, können Sie Prüfungen hinzufügen, um sicherzustellen)

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

enum { NBOOKS = 10 }; 

typedef struct { 
    char *title; 
    int pages; 
} book; 

typedef struct { 
    int num_books, 
     max_books; 
    book *array; 
} stack; 

stack *create_stack(); 
book *add_book (stack **s, char *title, int pages); 
void prn_stack (stack *s); 
void free_stack (stack *s); 

int main (void) { 

    stack *s1 = NULL; /* always initialize your pointers */ 

    add_book (&s1, "Huck Finn", 631); 
    add_book (&s1, "Tom Sawyer", 582); 
    add_book (&s1, "The Quick Brown Fox", 1); 

    prn_stack (s1); 
    free_stack (s1); 

    return 0; 
} 

/** allocate stack and allocate storage for NBOOKS books */ 
stack *create_stack() 
{ 
    stack *s = calloc (1, sizeof *s); 
    if (!s) { 
     fprintf (stderr, "error: virtual memory exhausted - stack.\n"); 
     exit (EXIT_FAILURE); 
    } 

    s->array = calloc (NBOOKS, sizeof *(s->array)); 
    if (!s->array) { 
     fprintf (stderr, "error: virtual memory exhausted - array.\n"); 
     exit (EXIT_FAILURE); 
    } 

    s->num_books = 0; 
    s->max_books = NBOOKS; 

    return s; 
} 

/** since add_book may create the stack, you must pass the address 
* of the stack to add_book so that any changes to s are available 
* back in the calling funciton. 
*/ 
book *add_book (stack **s, char *title, int pages) 
{ 
    if (!title) return NULL;  /* validate title */ 
    if (!*s) *s = create_stack(); /* if stack NULL, create */ 

    /* check num_books against max_books and realloc as required */ 
    if ((*s)->num_books == (*s)->max_books) { 
     void *tmp = realloc ((*s)->array, ((*s)->max_books + NBOOKS) * 
          sizeof *((*s)->array)); 
     if (!tmp) { 
      fprintf (stderr, "error: memory exhausted - realloc array.\n"); 
      return NULL; 
     } 
     (*s)->array = tmp; 
     (*s)->max_books += NBOOKS; 
    } 

    /* allocate/copy title, assign pages, increment num_books */ 
    (*s)->array[(*s)->num_books].title = strdup (title); 
    (*s)->array[(*s)->num_books].pages = pages; 
    ((*s)->num_books)++; 

    /* change return as desired, I just return the address of the book 
    * to indicate success and provide a way to validate the add. 
    */ 
    return &((*s)->array[(*s)->num_books - 1]); 
} 

void prn_stack (stack *s) 
{ 
    if (!s) return; 

    printf ("\nThere are %d books in the stack:\n\n", s->num_books); 
    for (int i = 0; i < s->num_books; i++) 
     printf (" %2d. %-20s (%3d pages)\n", i, s->array[i].title, s->array[i].pages); 
    putchar ('\n'); 
} 

void free_stack (stack *s) 
{ 
    if (!s) return; 

    for (int i = 0; i < s->num_books; i++) 
     free (s->array[i].title); 
    free (s->array); 
    free (s); 
} 

Beispiel Verwendung/Output

$ ./bin/bookstack 

There are 3 books in the stack: 

    0. Huck Finn    (631 pages) 
    1. Tom Sawyer   (582 pages) 
    2. The Quick Brown Fox ( 1 pages) 

Speichernutzung/Error Check

Einstellung NBOOKS TO 2 Neuzuweisung zu zwingen und die Überprüfung mit valgrind, finden Sie:

$ valgrind ./bin/bookstack 
==15521== Memcheck, a memory error detector 
==15521== Copyright (C) 2002-2013, and GNU GPL'd, by Julian Seward et al. 
==15521== Using Valgrind-3.10.1 and LibVEX; rerun with -h for copyright info 
==15521== Command: ./bin/bookstack 
==15521== 

There are 3 books in the stack: 

    0. Huck Finn    (631 pages) 
    1. Tom Sawyer   (582 pages) 
    2. The Quick Brown Fox ( 1 pages) 

==15521== 
==15521== HEAP SUMMARY: 
==15521==  in use at exit: 0 bytes in 0 blocks 
==15521== total heap usage: 6 allocs, 6 frees, 153 bytes allocated 
==15521== 
==15521== All heap blocks were freed -- no leaks are possible 
==15521== 
==15521== For counts of detected and suppressed errors, rerun with: -v 
==15521== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 1 from 1) 

das ist, wie es sein sollte. Schauen Sie sich die Dinge an und lassen Sie es mich wissen, wenn Sie irgendwelche Fragen haben.

2

Sie Book als Zeiger-struct book definiert haben und dann definieren Sie ein Array von Zeigern vom Typ Book, was bedeutet, dass es ein Array von Zeigern zu Zeigern zuist.

Entweder Book als struct book definieren oder den Zeiger nach Book in der Array-Definition entfernen. Normalerweise die erste, da Sie es nicht eindeutig als BookPtr zum Beispiel nennen.

+0

Im Code der Frage gibt es keinen Typ "Buch". – Olaf

0

Ich kann nicht kommentieren, also werde ich auf David C. Rankins Kommentar eingehen. Ihre Definition von Array wird nicht funktionieren.

Sie wahrscheinlich eine der folgenden Optionen verwenden sollten ...

Dies gibt Ihnen eine Reihe von Buch, das höchstens 50 Bücher halten wird: von

Book array[50]; 

Dies gibt Ihnen einen Zeiger auf ein Array Buch, das keine Größenbeschränkung hat, aber mehr Overhead benötigt.

Book *array; 

Wenn Sie letztere verwenden, werden Sie das Array erstellen müssen, halten Sie den Überblick über seine aktuelle Länge und machen es größer, wenn Sie es ausgefüllt haben (siehe https://linux.die.net/man/3/realloc).

+0

Ich habe das gemacht, aber ich bekomme diesen Fehler 'unvollständige Definition des Typs' struct book' 'an dieser Zeile: '(s-> array [s-> num_books - 1]) -> title = strdup (title);' – user6005857

+0

I verstehe nicht. Können Sie den ursprünglichen Post bearbeiten, um Ihren neuen Code hinzuzufügen, ohne den ursprünglichen Code zu entfernen? – Loring

Verwandte Themen