代码之家  ›  专栏  ›  技术社区  ›  Gary Willoughby

从堆栈中检索项时C程序崩溃

  •  0
  • Gary Willoughby  · 技术社区  · 15 年前

    以下代码在第二个代码上崩溃 Pop() 打电话。我是C的新手,我已经盯着这个代码看了一个多小时了,我看不到错误。有什么办法能帮我解释一下为什么这个代码会崩溃吗?

    #include <stdio.h>
    
    #define StackDataSize 100
    
    typedef struct Stack
    {
        int index;
        void *data[StackDataSize];
    } Stack;
    
    void* Pop(Stack *s)
    {
        if(s->index >= 0)
        {
            return s->data[s->index--];
        }
        else
        {
            fprintf(stderr, "ERROR: Stack Empty\n");
            return NULL;
        }
    }
    
    void Push(Stack *s, void *v)
    {
        if(s->index < StackDataSize)
        {
            s->data[++s->index] = v;
        }
        else
        {
            fprintf(stderr, "ERROR: Stack Full\n");
        }
    }
    
    int main(void)
    {
        Stack s = {-1}, *intstack = &s;
    
        int x = 123456;
        Push(intstack, &x);
    
        printf("%d\n", *(int*)Pop(intstack));
        printf("%d\n", *(int*)Pop(intstack));
    
        return 0;
    }
    
    7 回复  |  直到 15 年前
        1
  •  11
  •   Pete Kirkham    15 年前

    在第二个pop中,堆栈为空,如果堆栈为空,pop返回空。

    所以在第二行:

    printf("%d\n", *(int*)Pop(intstack));
    

    你正在取消引用 NULL 作为指向 int .

    printf("%d\n", *(int*)NULL );
    
        2
  •  6
  •   sth    15 年前

    第二个pop尝试从空堆栈中弹出, Pop() 函数返回 NULL . 然后主函数试图取消引用 无效的 -指针并打印它指向的值。

    由于空指针没有指向任何有效的内容,所以会出现分段错误。

        3
  •  3
  •   Norman Ramsey    15 年前

    第二次呼叫 Pop 收益率 NULL ,然后投射到 int * 尝试取消引用。取消引用 无效的 导致SegFault。

        4
  •  2
  •   John Bode    15 年前

    为了回显前面所有的答案,问题是对pop的第二个调用返回空值,您试图在对printf()的第二个调用中取消引用该值。

    简单地说,使用基于数组的堆栈,如果您从上到下增长,而不是从另一个方向增长,会更容易一些:

    void Push(Stack *s, void *v)
    {
      if (s->index)
        s->data[--s->index] = v;
      else
        // overflow
    }
    
    void *Pop(Stack *s)
    {
      if (s->index < StackDataSize)
        return s->data[s->index++];
      else
      {
        // underflow
        return NULL;
      }
    }
    ...
    Stack s = {StackDataSize, {NULL}};
    

    这种方式 0 不会变成特殊情况。

        5
  •  1
  •   Benno    15 年前

    您试图取消引用空案例中返回的空值。

        6
  •  0
  •   Steve Emmerson    15 年前

    “索引”成员是签名的还是未签名的?如果它是无符号的,那么表达式“s->index--”将产生一个非常大的数字。

        7
  •  0
  •   Craig McQueen Dr. Watson    15 年前

    当我查看您的代码时,我发现另一个问题也会导致崩溃:我认为您在 Push() 还有,这里:

    void Push(Stack *s, void *v)
    {
        if(s->index < StackDataSize)
        {
            s->data[++s->index] = v;
        }
        ...
    

    检查 s->index < StackDataSize ,然后进行预增量 ++s->index 写信给 s->data 如果 s->index == StackDataSize - 1 . 这也会给你一个分割错误。