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

从堆栈中检索项时C程序崩溃,c,pointers,stack,C,Pointers,Stack,以下代码在第二次调用时崩溃。我是C语言的新手,我已经盯着这段代码看了一个多小时了,我看不到错误。有什么办法可以帮我解释为什么这个代码会崩溃吗 #include <stdio.h> #define StackDataSize 100 typedef struct Stack { int index; void *data[StackDataSize]; } Stack; void* Pop(Stack *s) { if(s->index >=

以下代码在第二次调用时崩溃。我是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;
}
#包括
#定义StackDataSize 100
typedef结构堆栈
{
整数指数;
void*数据[StackDataSize];
}堆叠;
void*Pop(堆栈*s)
{
如果(s->index>=0)
{
返回s->数据[s->索引--];
}
其他的
{
fprintf(stderr,“错误:堆栈为空\n”);
返回NULL;
}
}
无效推送(堆栈*s,无效*v)
{
如果(s->index数据[++s->索引]=v;
}
其他的
{
fprintf(stderr,“错误:堆栈已满\n”);
}
}
内部主(空)
{
堆栈s={-1},*intstack=&s;
int x=123456;
推送(intstack和x);
printf(“%d\n”,*(int*)Pop(intstack));
printf(“%d\n”,*(int*)Pop(intstack));
返回0;
}

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

您正在尝试取消对空大小写中返回的NULL的引用。

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


由于NULL指针不指向任何有效的对象,因此会出现分段错误。

在第二次弹出时,堆栈为空,如果堆栈为空,则Pop返回NULL

所以在第二行:

printf("%d\n", *(int*)Pop(intstack));
您正在将
NULL
作为指向
int
的指针取消引用

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

Pop
的第二次调用返回
NULL
,然后将其转换为
int*
,并尝试取消引用。取消引用
NULL
会导致segfault。

要回显前面的所有答案,问题是对Pop的第二次调用返回NULL,您在对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}};
void推送(堆栈*s,void*v)
{
如果(s->索引)
s->data[--s->index]=v;
其他的
//溢出
}
void*Pop(堆栈*s)
{
如果(s->indexdata[s->index++];
其他的
{
//底流
返回NULL;
}
}
...
堆栈s={StackDataSize,{NULL}};

这样
0
就不会成为特例

当我查看您的代码时,我发现另一个问题也会导致崩溃:我认为您在
Push()
上也出现了一个“off by one”错误,如下所示:

void Push(Stack *s, void *v)
{
    if(s->index < StackDataSize)
    {
        s->data[++s->index] = v;
    }
    ...
void推送(堆栈*s,void*v)
{
如果(s->index数据[++s->索引]=v;
}
...

检查
s->index
,然后做一个预增量
++s->index
并写入
s->data
,如果
s->index==StackDataSize-1
,则会写入一个数组末尾。这也会导致分段错误。

您在调试器中检查过它了吗?停在每行并检查s和索引为空。我想你会同意的,通过检查,它已经签名了。