【问题标题】:How can I access an array of structs within a struct?如何访问结构中的结构数组?
【发布时间】:2017-01-28 19:35:45
【问题描述】:

我有以下两种结构:

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

这是我初始化每个结构的方式:

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

我正在尝试使用堆栈结构内的数组来访问书的标题和页面。我就是这样做的:

例如,如果我想访问和修改结构中最后一本书的标题和页面,我就是这样:

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

但是,我收到此错误:

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);
        ~~~~~~~~~~~~~~~~~~~~~~~~~~^ ~~~~~

编辑:从Book *array[50]; 删除指针后,我现在收到此错误:

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

我认为这是 main 无法看到书本结构的问题,所以我停止使用头文件并将所有内容放在一个文件中,但这没有帮助。

我也认为我没有正确初始化堆栈。

当我尝试像这样在 create_stack 函数中初始化数组时:

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

这是我得到的错误:

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

【问题讨论】:

  • Book *array[50]; 创建一个 指向 book 50 的指针数组 而不是 50 struct book
  • typedef struct stack * Stack; 是一个误导typedef。使用typedef struct stack Stack;typedef struct stack * StackPtr;
  • @David 你能详细说明一下吗?
  • 当然,如果你想创建一个包含 50 个结构书的数组,请使用Book array[50];,然后你将访问类似s->book[i].title 的内容。如果您创建一个指向 struct book 的未初始化指针数组(例如 Book *array[50];),则必须为每个指针分配内存,然后才能为成员分配值等(您可以这样做,您只需要管理每本书的内存分配)
  • 从不 typedef指针!

标签: c arrays struct stack


【解决方案1】:

您已将Book 定义为指向struct book指针,然后您定义了一个Book 类型的指针数组,这意味着它是一个指针数组 struct book

要么将Book 定义为struct book,要么从数组定义中Book 之后删除指针。通常是前者,因为您没有将其明确命名为 BookPtr 例如。

【讨论】:

    【解决方案2】:

    目前还不清楚你是否解决了这个问题,所以也许一个简短的例子会有所帮助。无论您是在开始时在 array 中为 X 本书创建存储空间,还是将 array 创建为指向书籍的 X 指针数组,您都需要某种方法来确保不会添加超过您可以存储的书籍。处理此问题的明显方法是在 stack 结构中添加一个额外的变量,该变量跟踪 arrayrealloc array 中的存储(或可用指针的数量)。要跟踪array 中的可用空间,您可以简单地添加另一个计数器,例如max_books,例如

    enum { NBOOKS = 10 };
    
    typedef struct {
        char *title;
        int pages;
    } book;
    
    typedef struct {
        int num_books,
            max_books;
        book *array;
    } stack;
    

    因为当您只是要为每本书创建存储空间时,将 array 声明为 指针数组 没有任何好处,因此您不妨将数组声明为 book *array; 和为一些合理预期的书籍分配存储空间。你的create_stack 离我不远了,但我会做add_book 有点不同,以便根据需要创建堆栈,如果它当前是NULLrealloc。类似于以下内容:

    /** 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:关于为什么堆栈以stack **传递给函数的注释)

    这些基本上是您创建书籍堆栈所需的更改,这将允许您添加任意数量的书籍(直到您耗尽计算机的内存)。将示例放在一起,您可以执行以下操作(注意:常量NBOOKS 必须大于零,您可以添加检查以确保)

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

    使用/输出示例

    $ ./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)
    

    内存使用/错误检查

    设置NBOOKS TO 2 强制重新分配并检查valgrind,你会发现:

    $ 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)
    

    应该是这样的。如果您有任何问题,请查看并告诉我。

    【讨论】:

      【解决方案3】:

      我无法发表评论,所以我将阐述 David C. Rankin 的评论。您对数组的定义将不起作用。

      您可能应该使用以下其中一种...

      这将为您提供最多可容纳 50 本书的 Book 数组:

      Book array[50];
      

      这为您提供了一个指向 Book 数组的指针,该数组没有大小限制,但需要更多开销。

      Book *array;
      

      如果您使用后者,则必须创建数组,跟踪其当前长度,并在填充后使其变大(请参阅https://linux.die.net/man/3/realloc)。

      【讨论】:

      • 我这样做了,但我在此行收到此错误incomplete definition of type 'struct book'(s-&gt;array[s-&gt;num_books - 1])-&gt;title = strdup(title);
      • 我不明白。您能否在不删除原始代码的情况下编辑原始帖子以添加新代码?
      猜你喜欢
      • 2018-06-08
      • 1970-01-01
      • 2021-09-20
      • 1970-01-01
      • 2012-01-30
      • 1970-01-01
      • 1970-01-01
      • 2023-03-26
      • 2012-10-16
      相关资源
      最近更新 更多