2010-01-06 82 views
0

以下代碼在第二個Pop()調用中崩潰。我是C的新手,我一直在盯着這個代碼一個多小時,我看不到錯誤。任何想法來幫助我解釋爲什麼這段代碼崩潰?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; 
} 
+1

你有沒有在調試器中完成它?停在每一行,檢查s和索引是否爲空值。 – 2010-01-06 23:02:27

回答

11

在第二個Pop中,堆棧爲空,如果堆棧爲空,Pop將返回NULL。

所以在第二行:

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

你提領NULL爲一個指向int

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

「index」成員是簽名還是未簽名?如果它的無符號,則表達式「s-> index--」將導致一個非常大的數字。

+0

我想你會同意,通過檢查,它已簽署。 – 2010-01-06 23:59:18

1

您試圖取消您在空白情況下返回的NULL的引用。

6

第二次彈出嘗試從空棧中彈出,而Pop()函數返回NULL。然後主函數嘗試取消引用這個NULL指針並打印它指向的值。

由於NULL指針不指向任何有效的東西,所以會出現分段錯誤。

3

第二次調用Pop回報NULL,然後您可以轉換爲int *並嘗試取消引用。取消引用NULL會導致段錯誤。

2

要回顯以前的所有答案,問題是第二次調用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}}; 

這樣0不成爲一個特例。

0

雖然我看你的代碼,我看到另一個問題,這也將導致崩潰:我想你已經上了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。這也會給你一個分段錯誤。