Sie sind auf Seite 1von 11

Understanding

the Stack

Table of Contents
Introduction

Stack definition and basics

Implementation in C

Defining what we need

2.1

Memory management

2.2

Understanding the Stack

Understanding the stack


I'm glad you've reached those pages ! This book will guide you through the basic
understanding of stacks. You will be able to implement one in either C or C++ . Let's get
started !
NOTE: Source code is available in my repository.
NOTE 2: I recommend you read this bunch of text here, on gitbook.

Introduction

Understanding the Stack

Stack definition and basics


In computer science, a stack is an abstract data type that serves as a
collection of elements, with two principal operations: push, which adds
an element to the collection, and pop, which removes the last element
that was added. - **Wikipedia**

Let's have a simple representation of what this mean. Here is an empty stack

At this point, the stack is empty and stores no data. Indeed, to have our stack store some
bunch of data, we need to use the elementary action push .
When we push , let's say, 10 , here is what we get

As you can see, we've added a value onto the stack. But what happens if we push 8 ?

Once again we've pushed a value onto the stack. How can we get 10 now ? Well, a stack is
to be understood as a pile of books. When you push a book onto another book, you create a
stack ! And to get any book in the stack, you have to remove every book above it, that is to
say pop every book that is above the one we want to get.
How can we get 10 back ?
To retrieve 10, we have to pop the stack twice. The first pop() will return 8 and the second
one will return 10, which is what we want !

Stack definition and basics

Understanding the Stack

Implementation in C
This section is dedicated to a minimalist implementation of a stack in C .

Implementation in C

Understanding the Stack

Defining what we need


As of C doesn't handle objects, we will have to use standard-C struct and primitive types,
nothing more. Of course, a more advanced Stack implementation would maybe use some
more advanced types and things, but let's stick to the minimum.

1 - Stack struct
I will neither discuss how structs are implemented in C, nor tell you how to use them. But
let's see how we can declare a convenient structure for our stack.
First of, let's create a stack.h header file to store our functions prototypes.
// stack.h
#ifndef _STACK_H_
#define _STACK_H_
#endif /* _STACK_H_ */

This basic header-guard prevents recursive inclusion of the header. Now let's list what we
need to know about our stack.
In the first place, we need to have a variable to keep track of the maximum stack's size.
// stack.h
typedef struct {
int size;
} Stack;

We also need a variable to keep track of the current size of the stack, that is to say how
many elements are stored in the stack. Let us call it sp . (this name stands for stack
pointer, which is a sort of convention).
// stack.h
typedef struct {
int sp;
int size;
} Stack;

Defining what we need

Understanding the Stack

Finally, I've chosen to make an array-based implementation of a stack so we'll need to


store an array of int s. Let's name it items , since it will simply store the items contained in
our stack.
Here is how our struct should look like
// stack.h
typedef struct {
int sp;
int size;
int *items;
} Stack;
typedef Stack* stack;

2 - Memory management
2.a - Memory allocation
I've already told you that C doesn't support Object-Oriented programming. Thus, we have to
manage ourselves how memory is allocated / freed for our structs. Of course, you remember
our Stack is implemented as a struct . This is why we'll need a function to initialize a new
stack for us. Let's call it new_stack()
// stack.h
/* function to allocate a new stack */
stack new_stack ();

2.b - Memory de-allocation


Every thing you use every day should be placed back where it was, to whom it belongs right
? So it is. Memory works all the same ! This is why we should always de-allocate memory
we've allocated, when we're done with it. Let's add another function named free_satck() .
This function will be in charge of freeing memory allocated to our stack and thus requires a
stack parameter.

// stack.h
/* function to deallocate memory used by a stack */
void free_stack (stack);

3 - I/O
Defining what we need

Understanding the Stack

Well, there's not much to do with input, but output needs to be implemented. This might look
gadget-ish but, it's not if we want to keep track of our stacks state. So let us have a print()
function !
// stack.h
/* this function will print our stack onto the screen */
void print (stack);

That's it with I/O management !

4 - Stack state informations


We will need to keep track of our stacks state. That is to say, to know whether it's empty or
not, full or not. Let's get two more functions ! First, is_empty() to know if yes or no our
stack is empty. And is_full() for similar purposes.
// stack.h
/* returns whether the given stack is empty or not */
int is_empty (stack);
/* returns whether the given stack is full or not */
int is_full (stack);

Those are pretty self explanatory right ?

5 - Elementary stack operations


This is it. We've almost described every thing we'll need to implement our stack in C but our
beloved functions push() and pop() . Let's add those as well ...
// stack.h
/* pushes a value onto the given stack */
void push (stack, int);
/* returns and removes the topmost value of/from the stack */
int pop (stack);

6 - Putting it altogether
Now we need to assemble all those function prototypes into our stack.h file.

Defining what we need

Understanding the Stack

#ifndef _STACK_H_
#define _STACK_H_
#include <stdlib.h>
#include <stdio.h>
#define STACK_CHUNK_SIZE 16
typedef struct {
int sp;
int size;
int *items;
} Stack;
typedef Stack* stack;
stack new_stack ();
void free_stack (stack);
int is_empty (stack);
int is_full (stack);
void push (stack, int);
int pop (stack);
void print(stack);
#endif /* _STACK_H_ */

You're now ready to implement all those functions and get yourself a working stack !

Defining what we need

Understanding the Stack

Memory management
In this part, we'll simply implement the memory-wise functions we've defined previously.
Let's create a new file named stack.c . This source file will contain the implementation of
every function defined in the previous part.

- new_stack()
This function's purpose is to allocate just enough memory for a new stack. But how to
define a base size if we don't ask the programmer to specify one ? Using a macro, for sure !
// stack.h
#ifndef _STACK_H_
#define _STACK_H_
/* a macro to specify the base size of our stack */
#define STACK_CHUNK_SIZE 16
// ....

Now we got this, let's head back into our stack.c file, and type in the implementation of the
new_stack() function.

#include "stack.h"
stack new_stack() {
printf ("Stack created\n");
stack s = calloc (1, sizeof(Stack));
s->sp = 0;
s->size = STACK_CHUNK_SIZE;
s->items = malloc (STACK_CHUNK_SIZE * sizeof int);
return s;
}

Let's break down this little piece of code...


First, we allocate just enough memory for a struct of type Stack
Then we initialize the structs variables
And finally allocate an array of integers within the struct
And return

Memory management

10

Understanding the Stack

- free_stack()
Again, this function is meant to free the memory previously allocated to our struct ( stack ).
This is maybe the simplest function to write in this part, look
// stack.c
void free_stack() {
printf ("Stack deleted\n");
free (s->items);
free (s);
}

And once more, let's break down this code


First of, we free the memory used by the array
And then free the whole struct
What else ?

Memory management

11

Das könnte Ihnen auch gefallen