views:

146

answers:

6

Hello!

I wanted to write a standard stack in C but I am not sure if my stk_size() function could work on other platforms except for my 32bit pc. I read that its not good to cast a pointer to int. But what could be a better implementation? I dont want to add a "size"-variable because its redundant in my eyes.

Here are some parts of the source:

  #define MAX_STACK_SIZE 100

    typedef struct stk stack;

    struct stk
    {
            /* Stack */
            int * stk;

            /* Pointer to first free element of stack */
            int * sp;
    };

    void stk_init(stack* s)
    {
            /* Allocate memory for stack */
            s->stk          = malloc(sizeof(s->stk) * MAX_STACK_SIZE);

            /* Set stack pointer to first free element of stack -> 0 */
            s->sp           = s->stk;
    }

    int stk_size(stack* s)
    {
            return ((int) s->sp - (int) s->stk) / sizeof(int *);
    }

    int main(int argc, char * argv[])
    {
            stack * s;
            stk_init(s);
    }

Thank you!

+9  A: 

You can just use (s->sp - s->stk). Subtracting pointers yields a ptrdiff_t, which is a signed integral type.

Crashworks
A: 

Don't cast both pointers to an int. Subtract the pointers and cast the result to an int, unsigned int (if you know s->sp is always >= s->stk). This eliminates the need to divide by sizeof(int*) as well.

Evän Vrooksövich
A: 

There is a standards-defined type, intptr_t which is guaranteed to be large enough that it can store either an int or any pointer type. Use that.

For example, if you were on a platform where int is 32-bits but a pointer is 64-bits, intptr_t would be a 64-bit type.

Heath Hunnicutt
+5  A: 

For starters, you have a bug. You've allocated no space for your stack object. You want either

int main(int argc, char * argv[])
{
        stack s;
        stk_init(&s);
}

or

int main(int argc, char * argv[])
{
        stack * s = malloc(sizeof(stack));
        stk_init(s);
}

And as for your question, I see @Crashworks has already answered it while I typed this.

Grumdrig
...or `s = stk_init()`
caf
@caf That wouldn't help unless stk_init were rewritten to allocate a stack and return it. Perhaps that's what you're suggesting.
Grumdrig
Well, yes - just like `stk_init` would need to be changed for your first suggestion.
caf
No, niether of my suggests would require any change to <code>stk_init</code>. The <code>stack</code> object would be allocated on the stack (no relation) or heap in main and <code>stk_init</code> allocates memory for the stack defined by this code.
Grumdrig
"neither", I mean
Grumdrig
+1  A: 

No need to cast, and no need to divide so long as you want your answer in ints

size_t stk_size(stack* s)
{
        return (s->sp - s->stk);
}
JSBangs
+2  A: 

In stk_init You should be using

s->stk = malloc(sizeof(int) * MAX_STACK_SIZE);

because stk is an int *. In other words, your stack is composed of ints.

In stk_size you should do this:

return s->sp - s->stk;

When you subtract pointers in C, C takes into account the size of the object they point to (which in this case is an int).

It's a silly idea, but if you really wanted to, you would do it like this : ((int) s->sp - (int) s->stk) / sizeof(int);

Artelius
Alternatively, `malloc(MAX_STACK_SIZE * sizeof *s->stk)`.
caf
Yep, although I find that harder to read. IMO a typedef would be better.
Artelius