Stack
Stack

Reputation: 235

C stack using array

This is only a part of the program but I don't understand these codes why did we declare int* array in structure what does it mean? Also we generally use int or void before function type why did we write struct Stack * before create function and also what is the use of unsigned here? Click the link to view the actual program. a link

struct Stack {
    int top;
    unsigned capacity;
    int* array;
};

struct Stack* createStack(unsigned capacity) {
    struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));
    stack->capacity = capacity;
    stack->top = -1;
    stack->array = (int*) malloc(stack->capacity * sizeof(int));
    return stack;
}

int main() {
    struct Stack* stack = createStack(100);
}

Upvotes: 0

Views: 508

Answers (2)

John Bode
John Bode

Reputation: 123488

why did we declare int* array in structure what does it mean?

The array member is used to store the contents of the stack. However, we don't know ahead of time how many elements the stack will need to hold, so we can't declare it as a regular array (whose size must be known at compile time1). Instead, we'll allocate the memory at runtime using the malloc library function, which returns a pointer to the first element of the dynamically allocated block; this pointer will be stored to the array member.

why did we write struct Stack * before create function

Because the createStack function is returning a pointer to a new struct Stack instance:

struct Stack *createStack( ... )  ----------------+
{                                                 | The type of the expression in the 
  struct Stack *stack = ...; -----+               | `return` statement must match the  
  ...                             |               | return type of the function
  return stack; <-----------------+---------------+
}

what is the use of unsigned here

unsigned is short for unsigned int; it guarantees that only non-negative values can be used for the stack size.

Here's what memory looks like after the createStack function has been called:

                   +---+
            stack: |   |----+  // The stack variable points to a struct Stack instance
                   +---+    |
                    ...     |
                   +---+    |
       stack->top: |   |<---+  // The actual struct Stack instance is created on the heap
                   +---+       // The -> operator allows us to refer to the members of the
  stack->capacity: |   |       // instance through the stack pointer variable.
                   +---+       
     stack->array: |   |----+  // The memory for the stack contents is allocated in a 
                   +---+    |  // separate malloc call, and the resulting pointer is
                    ...     |  // stored in the instance's array member.  
                   +---+    |
  stack->array[0]: |   |<---+
                   +---+
  stack->array[1]: |   |
                   +---+
  stack->array[2]: |   |
                   +---+
                    ...
                   +---+
stack->array[N-1]: |   |    // N == stack->capacity
                   +---+

The stack variable in main points to an instance of struct Stack; this instance is created by the line

struct Stack* stack = (struct Stack*) malloc(sizeof(struct Stack));

in the createStack function. The memory for the stack instance is taken from the "heap" (a region of memory reserved for dynamic allocation). Within the stack instance, the array member also points to a region of dynamic memory reserved by another call to malloc:

stack->array = (int*) malloc(stack->capacity * sizeof(int));

This function sets aside enough memory to store as many int objects as specified in the capacity member.

Edit

Note that both malloc calls can be cleaned up as follows:

struct Stack *stack = malloc( sizeof *stack );
...
stack->array = malloc( stack->capacity * sizeof *stack->array );

Unless you're using a C++ compiler or a C compiler that predates the 1989 standard, the cast is unnecessary (and on C89 implementations, dangerous).

The sizeof expressions use the dereferenced target expression, rather than a type name; this cleans up a little of the visual clutter, and it reduces maintenance if you ever decide to change the type of the target variable (from int * to double *, for example). The type of the expression *stack is struct Stack, so it follows that sizeof *stack == sizeof (struct Stack). Similarly, the type of the expression *stack->array is int, so sizeof *stack->array == sizeof (int). Note that parentheses are only required if the operand of sizeof is a type name.


1. C99 introduced variable-length arrays whose size can be specified at runtime, but they won't work in this context for several reasons.

Upvotes: 1

1) int * is used because we dont know before hand how huge the array is going to be, so we declare it as a pointer and do malloc using the capacity of the stack.

If we had used an array, we had to perform additonal checks to see if our initial declared size was overflown and would be a huge overhead across the program.

2) The function create stack is returning the structure ponter of type stack, according to the syntax for functions.

Syntas:

<return type> function_name(<Parameters>){<Statements>}

3) We want the program to give us an error if some one tries to declare a negative capacity. Unsigned ensures that that is satisfied

Hope this helps.

Upvotes: 1

Related Questions