2013-11-25 26 views
0

GDB告訴我52行正在導致分段錯誤。我不明白爲什麼。我正在實現一個簡單的堆棧。它有兩個功能:彈出和推送。它出現流行不工作。 pop的目的是檢索堆棧中最高的值。但是,當它嘗試這樣做時,我會遇到分段錯誤。有誰知道原因?如何解決C中的函數傳遞指針的分段錯誤?

/************************************************************************* 
* stack.c 
* 
* Implements a simple stack structure for char* s. 
************************************************************************/ 

// for strdup() in the testing code 
#define _XOPEN_SOURCE 500 

#include <assert.h> 
#include <stdbool.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

// the capacity of the stack 
#define CAPACITY 10 

//global variable used to keep track of pop and push 


typedef struct 
{ 
    // storage for the elements in the stack 
    char* strings[CAPACITY]; 

    // the number of elements currently in the stack 
    int size; 
}stack; 

// declare a stack (as a global variable) 
stack s; 


/** 
* Puts a new element into the stack onto the "top" of the data structure 
* so that it will be retrived prior to the elements already in the stack. 
*/ 
bool push(char* str) 
{ 
    s.strings[s.size++] = strdup(str); 
    return false; 
} 

/** 
* Retrieves ("pops") the last ("top") element off of the stack, following 
* the "last-in, first-out" (LIFO) ordering of the data structure. Reduces 
* the size of the stack. 
*/ 
char* pop(void) 
{ 
    char *ptr = s.strings[--s.size]; 
    s.strings[s.size] = NULL; 

    return ptr; 
} 

/** 
* Implements some simple test code for our stack 
*/ 
int main(void) 
{ 
    // initialize the stack 
    s.size = 0; 

    printf("Pushing %d strings onto the stack...", CAPACITY); 
    for (int i = 0; i < CAPACITY; i++) 
    { 
     char str[12]; 
     sprintf(str, "%d", i); 
     push(strdup(str)); 
    } 
    printf("done!\n"); 

    printf("Making sure that the stack size is indeed %d...", CAPACITY); 
    assert(s.size == CAPACITY); 
    printf("good!\n"); 

    printf("Making sure that push() now returns false..."); 
    assert(!push("too much!")); 
    printf("good!\n"); 

    printf("Popping everything off of the stack..."); 
    char* str_array[CAPACITY]; 
    for (int i = 0; i < CAPACITY; i++) 
    { 
     str_array[i] = pop(); 
    } 
    printf("done!\n"); 

    printf("Making sure that pop() returned values in LIFO order..."); 
    for (int i = 0; i < CAPACITY; i++) 
    { 
     char str[12]; 
     sprintf(str, "%d", CAPACITY - i - 1); 
     assert(strcmp(str_array[i], str) == 0); 
     free(str_array[i]); 
    } 
    printf("good!\n"); 

    printf("Making sure that the stack is now empty..."); 
    assert(s.size == 0); 
    printf("good!\n"); 

    printf("Making sure that pop() now returns NULL..."); 
    assert(pop() == NULL); 
    printf("good!\n"); 

    printf("\n********\nSuccess!\n********\n"); 

    return 0; 
} 
+2

哪一條是52號線? – Sinkingpoint

+0

char * ptr = s.strings [ - s.size]; – Adam

+0

你應該使用[valgrind](http://valgrind.org/)來了解爲什麼分段錯誤的答案。 –

回答

5

看看這塊:

printf("Making sure that push() now returns false..."); 
assert(!push("too much!")); 
printf("good!\n"); 

這裏你將的Pusing字符串「太多」到你的籌碼,這已經是滿的。你的push()函數實際上並不檢查你是否超出了容量,它只是附加字符串。

bool push(char* str) 
{ 
    s.strings[s.size++] = strdup(str); 
    return false; 
} 

這意味着你會在你的堆棧的界限,搗毀內存,堆棧的大小設置爲11,而出現混亂。

也許推送功能應該做的:

bool push(char* str) 
{ 
    if (s.size >= CAPACITY) 
     return false; 

    s.strings[s.size++] = strdup(str); 
    return true; 
} 

彈出功能需要做類似的檢查,否則你可能會改變,即使它是空棧的大小 結束:

char* pop(void) 
{ 
    if (s.size == 0) 
     return NULL; 

    char *ptr = s.strings[--s.size]; 
    s.strings[s.size] = NULL; 

    return ptr; 
} 
2

在你pushpop functionw,您可以訪問s.strings[--s.size]/s.strings[s.size++]任何檢查s.size是在合理的範圍之內。

因此,在堆棧頂部推入儘可能多的元素之後,行assert(!push("too much!"));會在分配的數組之外添加一個元素。

同樣,彈出主函數內的所有元素後,堆棧將爲空,並且assert(pop() == NULL);會嘗試訪問堆棧數組的第-1個元素,這是未定義行爲和另一個可能的segfault源。

編輯︰順便說一句,即使認爲這可能是你問的錯誤的來源,你的代碼似乎更容易出錯。記住在使用指針算術或數組訪問時總是執行邊界檢查。