1

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?

Andreas Grech
  • 98,643
  • 98
  • 284
  • 354
  • 1
    @01, leave my title the way it was. I need to specify that my question is regards C – Andreas Grech Aug 07 '09 at 10:34
  • Duplicate: http://stackoverflow.com/questions/674722/struggling-with-c-coming-from-object-oriented-land – S.Lott Aug 07 '09 at 10:50
  • @Dreas Grech: The question has tags that do not **have** to be repeated in the title. – S.Lott Aug 07 '09 at 10:51
  • @S.Lott, ah yes you are right there...but still, when skimming through the questions in the main page, people tend to look more at the question titles rather than at the tags...primarily because the titles have a bigger font size heh – Andreas Grech Aug 07 '09 at 11:03
  • @Dreas: that is what tags are for. – JesperE Aug 07 '09 at 11:05
  • 1
    Actually, I see tags more as a way to group and categorize questions – Andreas Grech Aug 07 '09 at 11:06
  • 1
    I'm with Dreas on this one - I like to see the language in the title. –  Aug 07 '09 at 12:54
  • Then formulate it into the title: "how do I do X in C?" – JesperE Aug 07 '09 at 14:04
  • Well it's just my way of asking questions...i put the language first, as to make clear the context of the question, and then I put the the question. As I said earlier on, I think this helps in when skimming through the questions wondering which questions one can answer or not. – Andreas Grech Aug 07 '09 at 14:07
  • @Dreas: you're welcome to do that, but that typically not how things are done on SO. – JesperE Aug 07 '09 at 19:33

7 Answers7

10

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.

JesperE
  • 59,843
  • 19
  • 133
  • 192
7

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);
}
Falaina
  • 6,435
  • 26
  • 31
  • You can skip _stack in your typedef: `typedef struct { ... } stack;` – JesperE Aug 07 '09 at 11:04
  • Ah, true. Force of habit cause I"m used to defining self-referntial structs. It'd probably be a bit cleaner to omit it in this cause, though. – Falaina Aug 07 '09 at 11:35
3

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.)

Meredith L. Patterson
  • 4,513
  • 25
  • 29
1

Simply make your 'this' pointer explicit:

struct stack* create_stack();
void push(struct stack* mystack, int n);
void pop(struct stack* mystack, int* n);
Kristof Provost
  • 24,574
  • 2
  • 22
  • 27
1

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

Sixteen Ways to Stack a Cat

AraK
  • 87,541
  • 35
  • 171
  • 230
0

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

Community
  • 1
  • 1
Lawrence Dol
  • 59,198
  • 25
  • 134
  • 183
0

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.

WillW
  • 771
  • 4
  • 17