简体   繁体   中英

Conflicting types for function in C

I have written a pop function that pops a linked list stack of character operators (+, *, - , /) and returns the value popped. The problem is I am getting a "conflicting types error". And I can't seem to figure out whats wrong. My linkedCharStack struct is declared as:

typedef struct linkedcharStack
{
char elem;
struct linkedcharStack* next;
};

The head of the stack is declared in another function outside of pop(not global but pointer) as:

struct linkedcharStack * opstack = malloc(sizeof(struct linkedStack));

And my actual pop function is:

char poptheop(struct linkedcharStack* s1){
struct linkedcharStack* temp;
if(s1==NULL){
    printf("NULL TOP ON POP VALUE STACK!");

}
char returnvalue = s1->elem;
temp = s1;
s1 = s1->next;
free(temp);
return returnvalue;
}

In addition to the compile error, i can see a problem in your code: You are not correctly implementing poptheop, because the change you are doing to the s1 pointer will not be reported to the caller. What you shoould do is pass a pointer to that pointer:

char poptheop(struct linkedcharStack** s1){
    struct linkedcharStack* temp;
    if(s1==NULL){
        printf("NULL TOP ON POP VALUE STACK!");
    }
    char returnvalue = (*s1)->elem;
    temp = *s1;
    *s1 = temp->next;
    free(temp);
    return returnvalue;
}

You need to do it this way, otherwise your top of stack will not be modified after you pop.

It's more general and may be easier to understand/use if we split into two structs: one for stack control and another for elements in that stack:

// stack element
struct _stackelem;
typedef struct _stackelem elem_t;
struct _stackelem {
    elem_t *prev;
    elem_t *next;

    char elem;
    int precedence;
};

// stack control
struct _stack;
typedef struct _stack stack_t;
struct _stack {
    elem_t *head;
    elem_t *tail;
    long maxcnt;
    long curcnt;
};

stack_t opStack;

other_func()
{

    opStack.tail = malloc(sizeof(elem_t));
}

Note that I've added a "head" to the stack control and "prev" to elem_t. This allows the stack_t to be a doubly linked list and can implement a queue in addition to a stack, etc. if desired. Also, I've added a "precendence" to elem_t--more on that below.

Here's your original function [with corrections similar to ASH's]:

// RETURNS: -1=empty stack
char
poptheop_original(stack_t *stk)
{
    elem_t *tmp;
    char retval;

    tmp = stk->tail;

    // stack is empty
    if (tmp == NULL)
        retval = -1;

    // pop last element
    else {
        retval = tmp->elem;
        stk->tail = tmp->next;
        free(tmp);
    }

    return retval;
}

Now, "(*s1)" has been replaced with "stk->tail". We've avoided passing "**" and the code will execute just as fast.

But, if all you're ever going to need is "elem", I'd consider reimplementing your op stack as just a reallocable array (eg "char *opstack").

Using the linked list approach is more suitable for returning more complex stuff. That's why I added "precedence". Here's your original function tweaked so you can get at both "elem" and "precedence":

// RETURNS: elem is -1 on empty stack
elem_t
poptheop_struct(stack_t *stk)
{
    elem_t *tmp;
    elem_t retval;

    tmp = stk->tail;

    // stack is empty
    if (tmp == NULL) {
        retval.elem = -1;
        retval.precedence = -1;
    }

    // pop last element
    else {
        retval = *tmp;
        stk->tail = tmp->next;
        free(tmp);
    }

    return retval;
}

Note that this function still does the "free" internally. But, it's passing the struct back by value . Almost never a good thing.

Here's the final version where it returns a pointer to the popped elem_t:

// RETURNS: NULL is empty
elem_t *
poptheop_pointer(stack_t *stk)
{
    elem_t *retval;

    retval = stk->tail;

    // pop stack
    if (retval != NULL)
        stk->tail = retval->next;

    return retval;
}

You now have to free the pointer on your own--that's the downside. But the upside is that elem_t can have many data elements, not just elem and precedence and will execute quickly with no needless extra data copying.

A further benefit of splitting out stack_t is that you can hide the details of how the stack is implemented. It could be a singly linked list [as you've done], a doubly linked list, or the realloc array I spoke of earlier.

If you so desire, as an exercise, reimplement stack_t as a reallocable array. That's why I added "maxcnt" and "curcnt". If the array approach turns out to be more suitable, then "prev" and "next" can be eliminated from elem_t altogether.

As a further hint: you only need to realloc during a push and only if curcnt is about to overflow maxcnt. Do the the realloc as maxcnt + slop_factor to prevent doing too many realloc's. This will make it "smart".

This might be the best implementation for you--YMMV

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM