2012-02-22 45 views
1

我試圖根據下面的頭(stack.h)用C來實現堆棧:通過設置指針初始化在C語言的堆疊爲NULL

#ifndef STACK_H 
#define STACK_H 

/* An element from which stack is consisting */ 
typedef struct stack_node_ss { 
    struct stack_node_ss *next; /* pointer to next element in stack */ 
    void *value;     /* value of this element */ 
} stack_node_s; 

/* typedef so that stack user doesn't have to worry about the actual type of 
* parameter stack when using this stack implementation. 
*/ 
typedef stack_node_s* stack_s; 

/* Initializes a stack pointed by parameter stack. User calls this after he 
* has created a stack_t variable but before he uses the stack. 
*/ 
void stack_init(stack_s *stack); 

/* Pushes item to a stack pointed by parameter stack. Returns 0 if succesful, 
* -1 otherwise. 
*/ 
int stack_push(void *p, stack_s *stack); 

/* Pops item from a stack pointed by parameter stack. Returns pointer to 
* element removed from stack if succesful, null if there is an error or 
* the stack is empty. 
*/ 
void *stack_pop(stack_s *stack); 

#endif 

然而,作爲新帶C,我停留在stack_init功能,我已經寫在stack.c:

#include <stdlib.h> 
#include <stdio.h> 
#include "stack.h" 

void stack_init(stack_s *stack) { 
    (*stack)->value = NULL; 
    (*stack)->next = NULL; 
} 

主程序開頭:

int *tmp; 
    stack_s stack; 
    stack_init(&stack); 

而這種崩潰我的程序與:

Program received signal EXC_BAD_ACCESS, Could not access memory. 
Reason: KERN_INVALID_ADDRESS at address: 0x0000000000000008 
0x0000000100000abf in stack_init (stack=0x7fff5fbffb30) at stack.c:6 
6  (*stack)->value = NULL; 

你可以暗示我到正確的軌道嗎?非常感謝。

+2

這就是爲什麼你不會隱藏typedefs後面的指針類型,除非它真的有很好的理由。 – 2012-02-22 23:01:48

+0

@Ed S .:完全。即使'typedef struct {...} mystruct_t;'是有問題的,恕我直言。爲什麼這種做法仍然在學校教授?在我看來,老師們都遭受着帕斯卡主義的終極形式的束縛。 – wildplasser 2012-02-22 23:22:02

+0

@wildplasser:呃......當我寫C時,我會''定義一個結構以避免在任何地方寫'struct foo f;'。我不認爲這是有問題的,但是用指針類型......有龍。 – 2012-02-23 00:09:49

回答

5

你必須爲自己**stack分配內存:

*stack = malloc(sizeof(**stack)); 

但請不要typedef定義指針類型。這真是令人困惑,難以閱讀。更好地按值傳遞指針,它留給調用者來存儲指針,就像這樣:

typedef struct stack_node_t 
{ 
    struct stack_node_t * next; 
    /* ... */ 
} stack_node; 

stack_node * create_stack() 
{ 
    stack_node * res = calloc(1, sizeof(stack_node)); 
    return res; 
} 

void destroy_stack(stack_node * s) 
{ 
    if (!next) return; 

    stack_node * next = s->next; 
    free(s); 
    destroy_stack(next); 
} 

// etc. 

然後,你可以說:

stack_node * s = create_stack(); 

// use s 

destroy_stack(s); 
s = NULL; // some people like this 
+0

嘿!有人閱讀代碼! +1,先生。 – 2012-02-22 23:00:51

+0

+1是正確的*和*提到'typdef'指針類型通常是個壞主意。 – 2012-02-22 23:09:24

+0

+1爲明確的解釋!現在我有堆棧工作,但是能否在釋放* s內存後簡單解釋「s = NULL」?如果我不寫「s = NULL」,s的值是不確定的/隨機的,取決於系統在「free(s)」之後? – rize 2012-02-23 13:20:38

2

您正在訪問一個未初始化的指針,造成不確定行爲。

因爲這個功能是創建一個新的堆棧,您需要分配一些動態內存堆棧,然後將指針指向新分配的內存:

void stack_init(stack_s *stack) { 
    *stack = malloc(sizeof(**stack)); // create memory for the stack 

    (*stack)->value = NULL; 
    (*stack)->next = NULL; 
} 

stack_s stack; 
stack_init(&stack); 

那麼你應該有一個調用的函數stack_destroyfree的動態內存,並設置指針NULL

​​
+0

只要它總是一個'stack_node_s'。使用'sizeof(** stack)' – 2012-02-22 23:08:50

+0

@EdS可能更安全。你是對的。我的無效指針感到刺痛,但我忘了'sizeof'在編譯時,所以沒關係 – 2012-02-22 23:12:20

-1

你應該堆棧初始化爲NULL - 不爲NULL值推到它:

void stack_init(stack_s *stack) { 
    *stack=NULL; 
} 
+1

這是我見過的最沒用的'init'函數......並且它沒有解決問題。 -1 – 2012-02-22 23:06:12

+0

@EdS。我知道這是無用的,但OP需要一個功能......他試圖將NULL推送到無效地址,而沒有理由這麼做。他所需要的只是將NULL分配給他得到的'stack_s'。 (需要分配才能推送內容) – asaelr 2012-02-22 23:10:26

+0

不,他有一個'init'函數,你可以期望你能夠在之後使用堆棧。你的實現只是保證你不能這樣做。 OP的問題是他沒有意識到函數的輸入可能是指向堆棧的有效指針。他聲明瞭一個指向堆棧的指針(通過typdef隱藏),但從未初始化它。如果有什麼你應該做相反的事情; 'malloc'事情就在那裏。 – 2012-02-22 23:18:12