1

I have an assignment in C to implement a abstract data type STACK. The nature of the data type requires key structure that needs to have memory allocated. My problem is that my instructor insists, for now, for the initialization function to take in a pointer to the key structure. The init() function will do nothing more than allocate the memory necessary for the structure and set a field to zero, but the pointer that is passed in needs to be assigned that memory location.

I can't think of a way to do this without either having the function return a pointer, or to pass in a 2-star pointer - both of which are not allowed. I know The function prototype must be (where stackT* is a pointer to the key STACK data structure):

    void init(stackT* stack);

I came up with this and it works fine:

    void init(stackT** stack){
        *stack = (stackT*) malloc(sizeof(stack));
        (*stack)->count = 0;
        return;
    }

But it does not abide by the restrictions of the assignment.


tl;dr version:

Basically, how can I pass in the address of my original pointer to the STACK data structure (&stackPtr) into a function that takes one-star pointers as arguments and not get a pointer-type warning? Further, once you change the arguments to (stackT* stack) the below code does not work, even though I am passing the same thing either way - this is where my problem is.

I thought it is REQUIRED to have the argument as a 2-star pointer if you intend to pass in a pointer to a pointer .. the compiler must know what it is dealing with when you dereference a pointer.

At any rate, I am not sure how to do this given the restrictions. In my opinion this is only making it unnecessarily more difficult.

sherrellbc
  • 4,650
  • 9
  • 48
  • 77
  • Ask your instructor about why the solution with a pointer to pointer does not fit. And your `init` (which you should perhaps call `init_stack`) might return a pointer... – Basile Starynkevitch Sep 11 '13 at 12:46
  • Well, the function prototype was provided - only the implementation was left to me. I cannot see how to do it with the supplied version. And I agree with you - returning a pointer from the init function would be quite simple too! But no, I have to provide implementation using the function prototype above - somehow. – sherrellbc Sep 11 '13 at 12:47
  • You might then `typedef struct mystack_st stackT` and have your `struct mystack_st` structure contain a pointer field (and perhaps a length and count fields). – Basile Starynkevitch Sep 11 '13 at 12:50
  • Not sure what you mean with that. What would the pointer field in the structure do? – sherrellbc Sep 11 '13 at 12:54
  • It would point to some `calloc`-ed array containing the elements inside the stack. – Basile Starynkevitch Sep 11 '13 at 12:59

4 Answers4

3

I believe, as pointed out in a comment, that you're missing the intention.

I think the idea is that the "root" stackT instance should be a well-known structure, so that you can declare one locally. Then you call init() to set up the actual stack described by the stackT instance:

int push_four(void)
{
  stackT my_stack;

  init(&my_stack);
  push(&my_stack, 1);
  push(&my_stack, 2);
  push(&my_stack, 3);
  push(&my_stack, 4);
}

The above assumes that the stack stores integers, i.e. the allocation inside init() should be something like:

void init(stackT *stack)
{
  stack->items = malloc(64 * sizeof *items);
  stack->count = 0;
}

And this, in turn, assumes a declaration like:

typedef struct {
  int *items;
  size_t count;
} stackT;

Of course, the default maximum depth (64) should be a parameter to init(), you must check (but not cast!) the return value of malloc(), and so on.

unwind
  • 391,730
  • 64
  • 469
  • 606
  • I actually have a `root` structure shown above as `stackT`. Inside this structure is a integer (count) to keep track of how many items are on the stack, and an array of pointers to other structures that will be what is later `push`-ed onto the stack. The problem I was having was how to initialize the `root` stack by passing in only a pointer of type `stackT` without using the 2-star implementation I proposed above - the solution apparently required 1-star. – sherrellbc Sep 11 '13 at 13:12
  • Also, I know that the casting of malloc()'s return of a void pointer `void *` is not necessary, but I included it for sake of readability. However, is there some other reason for you to say not to cast the return? – sherrellbc Sep 11 '13 at 16:05
2

Typically when you have complex structures then there is a control struct and that one will have a pointer to the real memory.

Example:

struct stack_control_s {
    void * memory;
    size_t memory_size;
    size_t current_size;
};

Then you would pass a pointer to the control structure to your initialiser and make it do the real work;

#define STACK_MIN_SIZE 0x100
int stack_init(struct stack_control_s * stack) {
    memset(stack, 0, sizeof(*stack));

    stack->memory = calloc(STACK_MIN_SIZE, 1);

    if (!stack->memory)
        return -1; //error

    stack->memory_size = STACK_MIN_SIZE;

    return 0; // all good
}

Here is a slightly modified header for a generic C list that I once made. I have added to macros to make it useable as a stack. Maybe this will give you some inspirations:

list_t.h

Use:

list_t(char) mylist;
list_init(&mylist);

list_push(&mylist, 'A');

printf("%c\n", list_pop(&mylist));
Sergey L.
  • 21,822
  • 5
  • 49
  • 75
  • In my (probably basic for now) implementation I have a `root` structure typedefined as `stackT` in which holds an array of pointers to other structures that will be later `push`-ed onto the stack and a `count` field to keep track of how many items are currently on the stack. – sherrellbc Sep 11 '13 at 13:16
  • Sure, I can do that. I was just wondering how to do this in general but I will. – sherrellbc Sep 11 '13 at 13:19
1

Probably it is not the best solution, but you can define your stack globally.

In this case it will look like a:

stackT G_stack;
....

void init(stackT* stack){
    stack->count = 0;
    return;
}

int main() {
    .....
    init(&G_stack);
    .....
}

In this case you don't need to change prototype.

Alex
  • 9,891
  • 11
  • 53
  • 87
1

This assignes the pointer the address of the definition of STACK and passes the pointer to be initialized (using a single * :)... Will this work for you?

#include <ansi_c.h>  
typedef struct  {
    int count;
} COUNT;

typedef struct  {
    COUNT count;
    int *element1;
    int *element2;
    int address;
} STACK;

STACK stack, *pStack;

void InitStack(STACK *iS);

int main(void)
{    //This is how I think you will meet the 
     //criteria you are talking about (single *)
    pStack = &stack; //assigning address of stack to pointer

    InitStack(pStack);
    //pStack->address == pStack
    return 0;
}

void InitStack(STACK *iS)
{
    iS->count.count = 0;
    iS->address = (int)iS; //assigning address of stack to member of struct
    iS->element1 = calloc(10, sizeof(int));
    iS->element2 = calloc(10, sizeof(int));
}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • This solution would technically work, but the the creation of `stack` in this case is statically allocated, while the components in the stack are dynamically allocated. Also, the stack and pointer is declared globally and I was trying to keep the namespace free of clutter. At any rate, I like this solution: +1 thank you. – sherrellbc Sep 11 '13 at 16:09
  • Hmmm. Thanks for the +1, but I am still trying to understand my disconnect. The init function takes in a pointer, it allocates memory necessary for the structure (i.e. members _element1_ & _element2_), it sets a member _count_ to zero, and assigns member _address_ to contain the address of the struct location. As for dynamically allocating memory for a copy of an entire struct, could you not do something like: S_DEVICE *pI, i; then pI = &i; then pI = malloc(sizeof(S_DEVICE)+(20*sizeof(int)); ? Let me know where I am missing the point. Thanks! – ryyker Sep 11 '13 at 17:36
  • Also, here is a ***[link](http://stackoverflow.com/questions/5837772/gsoap-generated-client-side-structure-initialization-and-use)*** (look at the answer section below) that goes into some detail about creating, allocating and freeing complex structures. I did this when trying to work out how to initialize gSoap structures, but some of it may apply to what you are doing too. – ryyker Sep 11 '13 at 17:43
  • Well, the solution above statically allocates memory for the stack and assigns a pointer to that static memory block. I need to do essentially this, but with dynamic memory allocation inside the function and assign the memory block address to the pointer passed in. With how it is done above, the address is already assigned in the main() when the statically allocated stack address is assigned to the pointer `pStack`. The init() function should only allocate the memory for the stack structure itself, not the elements inside it as you have it - at least in the implementation I have to do for now, – sherrellbc Sep 11 '13 at 18:14
  • Cont. I have another function `push()` that will allocate the required space for the item needing to be `push`-ed to the top of the stack. I am not sure how the stack data type may be used it its more complex forms, but for now this is how I have to do it since by calling calloc() and adding only a single item to the stack is wasted space. – sherrellbc Sep 11 '13 at 18:19
  • However, I think you have the right idea though. It really does not make sense to dynamically allocate the stack structure. There really is no benefit over static or automatic allocation inside main. – sherrellbc Sep 11 '13 at 18:45