2012-02-22 43 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