【问题标题】:Conflicting types for function in CC中函数的冲突类型
【发布时间】:2015-10-04 19:02:11
【问题描述】:

我编写了一个弹出函数,它弹出一个字符运算符(+、*、-、/)的链表堆栈并返回弹出的值。问题是我收到“冲突类型错误”。而且我似乎无法弄清楚出了什么问题。我的linkedCharStack 结构声明为:

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

栈头在pop(不是全局而是指针)之外的另一个函数中声明为:

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

而我实际的pop函数是:

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;
}

【问题讨论】:

  • 你在哪一行得到错误?
  • char poptheop(struct linkedcharStack* s1){
  • 如果s1 == NULL,也许你应该退出函数
  • 你在某处还有另一个 poptheop 声明吗?
  • 寻求调试帮助的问题(“为什么这段代码不起作用?”)必须包括所需的行为、特定的问题或错误以及在问题本身中重现它所需的最短代码。没有明确问题陈述的问题对其他读者没有用处。请参阅:如何创建minimal reproducible example

标签: c compiler-errors stack


【解决方案1】:

除了编译错误之外,我还可以在您的代码中看到一个问题: 您没有正确实现 poptheop,因为您对 s1 指针所做的更改不会报告给调用者。你应该做的是传递一个指向该指针的指针:

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;
}

你需要这样做,否则你的栈顶在你弹出后不会被修改。

【讨论】:

  • 谢谢。这正是我调用此函数时有人告诉我的,但我忘记了!我只是有一个问题。为什么参数需要是指向指针的指针,而例如*s1在实际函数中只是指向struct的指针。
  • 在调用者中,你持有一个指向栈顶的指针。您的弹出操作应该 1)提供顶部元素(返回值)并且 2)删除该元素,这意味着推进堆栈顶部。为了使函数能够修改栈顶参数,您需要传递一个指向它的指针,而不是其值的副本
  • 记住:要让一个函数改变一个变量,你将一个指向变量的指针作为参数传递给它。要让它改变一个指针,你需要传递一个指向指针的指针;)
【解决方案2】:

如果我们分成两个结构,它会更通用,可能更容易理解/使用:一个用于堆栈控制,另一个用于堆栈中的元素:

// 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));
}

请注意,我已将“head”添加到堆栈控件,并将“prev”添加到 elem_t。这允许 stack_t 是一个双向链表,并且可以在需要时实现除了堆栈之外的队列等。另外,我在 elem_t 中添加了一个“优先级”——更多内容如下。

这是您的原始函数 [修正类似于 A.S.H 的]:

// 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;
}

现在,“(*s1)”已替换为“stk->tail”。我们避免了传递“**”,代码执行速度也一样快。

但是,如果您只需要“elem”,我会考虑将您的操作堆栈重新实现为一个可重新分配的数组(例如“char *opstack”)。

使用链表方式更适合返回更复杂的东西。这就是我添加“优先级”的原因。这是您的原始函数经过调整,因此您可以同时使用“elem”和“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;
}

请注意,这个函数在内部仍然是“免费的”。但是,它通过 value 将结构传回。几乎从来都不是一件好事。

这是最终版本,它返回指向弹出的 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;
}

你现在必须自己释放指针——这是缺点。但好处是 elem_t 可以有许多数据元素,而不仅仅是 elem 和优先级,并且可以快速执行而无需进行不必要的额外数据复制。

拆分 stack_t 的另一个好处是您可以隐藏堆栈如何实现的细节。它可以是一个单链表 [正如你所做的那样]、一个双链表或我之前提到的 realloc 数组。

如果您愿意,作为练习,将 stack_t 重新实现为可重新分配的数组。这就是我添加“maxcnt”和“curcnt”的原因。如果结果证明数组方法更合适,则可以从 elem_t 中完全消除“prev”和“next”。

作为进一步的提示:您只需要在推送期间重新分配并且仅当 curcnt 即将溢出 maxcnt 时。将 realloc 设置为 maxcnt + slop_factor 以防止执行过多的 realloc。这将使它“聪明”。

这可能是最适合你的实现——YMMV

【讨论】:

    猜你喜欢
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-06-16
    • 2016-01-03
    相关资源
    最近更新 更多