Implementing a stack as two discrete variables (the data array and a stack pointer) has two significant disadvantages. First, a programmer can inadvertently alter one of the variables. For example, if the value stored in the stack pointer (sp) is changed, the next push or pop operation will occur at the wrong location in the stack array. Second, discrete variables limit the number of stacks that we can create within a given scope. For example, it's impossible to have two variables named "sp" defined in the same scope. While we can give the variables unique names like "sp1" and "sp2," doing so makes it difficult to create reusable library code. Structures solve the second problem, but we won't see a good solution for the first problem until we study classes in chapter 9.
Using a structure to implement a stack has one significant drawback: needing to pass a pointer to the stack in the stack functions. We also eliminate this clumsy requirement when studying classes in chapter 9. (We can also use pass-by-reference, but using pointers will better set the stage for our study of classes.)
//#define SIZE 100 // 3 ways of making a constant //enum { SIZE = 100; } const int SIZE = 100; struct stack { char st[SIZE]; int sp; }; stack make_stack(); void init_stack(stack* s); void push(stack* s, char data); char pop(stack* s); int size(stack* s); char peek(stack* s);
The stack example includes two functions for creating a new stack: make_stack and init_stack. Although only one function is needed, the example includes the first to provide continuity with previous examples and the second to segue to the constructor functions in Chapter 9.
Construction | Typical Operations | Optional Operations |
---|---|---|
stack make_stack() { stack temp; temp.sp = 0; return temp; } void init_stack(stack* s) { s->sp = 0; } |
void push(stack* s, char data) { if (s->sp < SIZE) s->st[s->sp++] = data; else throw "Stack Overflow"; } char pop(stack* s) { if (s->sp > 0) return s->st[--(s->sp)]; else throw "Stack Underflow"; } |
int size(stack* s) { return s->sp; } char peek(stack* s) { return s->st[s->sp - 1]; } |
throw
keyword throws or launches an exception, relaying an error condition to the calling function. A subsequent chapter explains how to handle the exceptions.
stack s = make_stack(); |
stack s;
init_stack(&s);
|
(a) | (b) |
#include <iostream> #include "stack.h" using namespace std; int main() { //stack s = make_stack(); // choose one stack s; init_stack(&s); push(&s, 'x'); push(&s, 'y'); push(&s, 'z'); char c = peek(&s); cout << c << endl; c = pop(&s); cout << c << endl; while (size(&s) > 0) cout << pop(&s) << endl; return 0; } |
|
(c) |
Formatted with tab stops set at 8 spaces.
View | Download |
---|---|
stack.h | stack.h |
stack.cpp | stack.cpp |
test.cpp | test.cpp |