Question

Let's say that I have the following code in C that represents a stack :

#define MAX 1000

int arr[MAX];
static int counter = 0;
isstackempty()
{
    return counter <= 0;
}
void push(int n)
{
    if (counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return;
    }
    arr[counter++] = n;
}

int pop(int* n)
{
    if(isstackempty() || n == 0) {
        printf("Stack is empty\n");
        return 0;
    }
    *n = arr[--counter];
    return 1;
}

The above code is in a stack.c file and the function prototypes are in a header.


Now, coming from a C# and OO background, if I would want to separate stacks to use in my application, in an OO language I would create two instances. But in C, how do you handle such a scenario?

Say I want to use two separate stacks in my C code...with the above code, how would I go about it?

Was it helpful?

Solution

Put the array arr inside a struct.

struct stack {
    int arr[MAX];
    ...
}

This struct becomes your instance. You can then declare it on the stack:

struct stack mystack;

or on the heap using malloc:

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

You also need to pass a pointer to the instance as the first parameter to any function manipulating the instance.

OTHER TIPS

The C way to do this is to wrap up all the state for your 'object' into a struct, and then explicitly pass it into all the functions that operate on stacks, so it should be:

typedef struct _stack {
  int arr[MAX];
  int counter;
} stack;

int isstackempty(stack *s)
{
    return s->counter <= 0;
}

int push(stack *s, int n)
{
    if (s->counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return -1;
    }
    arr[s->counter++] = n;
    return 0
}

int pop(stack *s, int *n)
{
    if(isstackempty(s) || n == 0) {
        printf("Stack is empty\n");
        return -1;
    }
    *n = arr[--s->counter];
    return 0;
}

The issue with your example is you're writing the function definitions like we have a class-based object structure, which C doesn't have. The easiest way to think about how it's done in C is that you're writing methods that require you to explicitly pass in the 'this' parameter.

Also you can have the equivalent of constructors and destructors, which can further abstract your 'object'.

stack* newStack() {
    stack* s = malloc(sizeof(stack));
    s->counter = 0;
    return s;
}

void freeStack(stack* s) {
    free(s);
}

One (extremely simplistic) way of going about it is to define a struct that represents a stack:

typedef struct {
    int arr[MAX];
    int counter = 0;
} myStack;

and then rewrite push() and pop() to operate on an instance of myStack:

int push(myStack *s, int n)
{
    if (s->counter >= MAX) {
        printf("Stack is full.  Couldn't push %d", n);
        return -1;
    }
    s->arr[(s->counter)++] = n;
    return s->counter;
}

int pop(myStack *s, int* n)
{
    if(0 == s->counter || 0 == n) {
        printf("Stack is empty\n");
        return -1;
    }
    *n = s->arr[--(s->counter)];
    return 1;
}

(Also added a meaningful return value and error value to push(). YMMV.)

I hope you find this paper useful. It gives more than one answer to your question :)

Sixteen Ways to Stack a Cat

Simply make your 'this' pointer explicit:

struct stack* create_stack();
void push(struct stack* mystack, int n);
void pop(struct stack* mystack, int* n);

My answer to this other question has a complete working example of an OO data buffer structure in C.

A dynamically allocated structre-per-instance is the right way to go. A point of detail - if you are writing a more generally used API it is probably a good idea to engage in data hiding for better abstraction. The simplest way of doing this is keep the definition of the internal structure in the C file (or a private header file), and typedef a void pointer to (e.g.) 'stack_handle_t'. It is this type that is returned from your 'constructor' and is passed back in to each other function. The implementation is aware that the value of the handle is in fact a pointer to a structure and at the beginning of each function simply does:

int pop(stack_handle_t handle, int* n)
{
    stack *p_stack = (stack *)handle;
    ...

Even better than that is to use an internally allocated identifier instead, whether this is an index into an array of these structs or simply an identifier which can be matched against one of a (linked?) list of structs. Obviously all this is irrelevant if its only for use internal to your project, in those circumstances it is just making unnecessary work and over-complication.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top