/*
* This program builds a linked stack in plain C much as the C++ example.
* There are many differences, since plain C does not have templates or classes,
* plus there's a couple of details I'm trying to avoid. So, we're putting
* it all in one program. Our stack will be of integers, not generic.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
// Integer stack node.
struct node {
int data;
struct node *next;
};
// Represents a stack.
struct stack {
struct node * head; // Head of the linked list.
int size; // Size of the stack.
};
/*
* Methods on stack.
*/
// Initialize a new stack. Call after declaring a stack.
void stack_init(struct stack *stk)
{
stk->head = NULL;
stk->size = 0;
}
// Clean up a stack. This should be called after using a stack to make
// no garbage remains.
void stack_clear(struct stack *stk)
{
struct node *scan = stk->head;
while(scan != NULL) {
struct node *zombie = scan;
scan = scan->next;
free(zombie);
}
stk->size = 0;
}
// Push the argument item.
void stack_push(struct stack *stk, int itm) {
// Create the node and fill it in.
struct node *newnode = malloc(sizeof (struct node));
newnode->data = itm;
newnode->next = stk->head;
// Add the node to the stack.
stk->head = newnode;
++stk->size;
}
// Pop the argument item, and return it. Return 0 if the stack is empty.
// If zero is a valid data item, you should probably use the empty method
// before you pop.
int stack_pop(struct stack *stk) {
// Bail on empty.
if(stk->head == NULL) return 0;
// Remove the node from the list.
struct node *zombie = stk->head;
stk->head = stk->head->next;
--stk->size;
// Extract the data and free the node.
int itm = zombie->data;
free(zombie);
return itm;
}
// Tell if empty.
int stack_empty(struct stack *stk) {
return stk->head == NULL;
}
// Report the size
int stack_size(struct stack *stk) {
return stk->size;
}
int main()
{
// Stack of integers.
struct stack is;
stack_init(&is);
// Read the input.
char op;
while(scanf(" %c", &op) == 1) {
// See what we got.
if(op == '.') {
// Halt char.
break;
} else if(isdigit(op)) {
// Digit. Unget it, read the number, and push it
// on the stack.
ungetc(op, stdin);
int val;
scanf("%d", &val);
stack_push(&is, val);
continue;
} else if(strchr("+-*/", op) != NULL) {
// Operator, pop the operands.
if(stack_empty(&is)) break;
int b = stack_pop(&is);
if(stack_empty(&is)) break;
int a = stack_pop(&is);
// Push the operation result in place of the operands.
switch(op) {
case '+':
stack_push(&is,a+b);
break;
case '-':
stack_push(&is,a-b);
break;
case '*':
stack_push(&is,a*b);
break;
case '/':
stack_push(&is,a/b);
break;
}
} else {
// Just what it says.
printf("Bad char %c.\n", op);
}
}
// If there's a result, print it. If the stack is empty, just
// whine about it.
if(!stack_empty(&is))
printf("Value: %d\n", stack_pop(&is));
printf("Stack has %d elements at exit.\n", stack_size(&is));
stack_clear(&is);
}
Plain C does not have have the new operator. It has:
- The malloc library call, which takes a size in bytes and returns
a pointer to a block of memory that large.
- The area returned is uninitialized storage. Any initial values it
needs must be provided after malloc returns.
- The sizeof operator returns the amount of storage needed for a
type or variable, often used to make the argument to malloc.
- The memory must be released using a the free library call.
- There is no garbage collector or any type of smart pointer.
- Being no classes, there are no special methods like constructors or
destructors.