It is unclear whether you ever got this solved, so perhaps a short example will help. Regardless whether you create storage for X number of books in array at the beginning or create array as an an array of X pointers to books, you will need some way of insuring you do not add more books than you can store. The obvious way to handle this is to add one additional variable to your stack struct that tracks the storage (or number of pointers available) in array and then realloc array as required. To track the space in array available, you could simply add another counter, say max_books, e.g.
enum { NBOOKS = 10 };
typedef struct {
char *title;
int pages;
} book;
typedef struct {
int num_books,
max_books;
book *array;
} stack;
Since there is no benefit in declaring an array as an array of pointers when you are simply going to create storage for each book, you may as well just declare array as book *array; and allocate storage for some reasonably anticipated number of books to begin with. Your create_stack isn't far off, but I would do add_book a little differently, in order to create the stack if it is currently NULL and realloc as required. Something like the following:
/** 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: the comment on why the stack is passed to the function as stack **)
Those are basically the changes you would need to create your stack of books that would allow you to add as many books as you would like (until you exhaust the memory of your computer). Putting the example together, you can do something like the following (note: the constant NBOOKS must be greater than zero, you can add checks to insure)
#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);
}
Example Use/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)
Memory Use/Error Check
Setting NBOOKS TO 2 to force reallocation and checking with valgrind, you will find:
$ 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)
Which is how it should be. Look things over and let me know if you have any questions.
Book *array[50];creates an array of pointers to book 50 not 50 struct book.typedef struct stack * Stack;is a misleadingtypedef. Usetypedef struct stack Stack;ortypedef struct stack * StackPtr;Book array[50];, then you will access something likes->book[i].title. If you create an array of uninitialized pointers to struct book (e.g.Book *array[50];), you must allocate memory for each pointer before you can assign values to the members, etc. (you can do it this way, you just have to manage the memory allocation for each Book)typedefa pointer!