2012-02-22 1 views
1

NULLにポインタを設定することにより、Cスタックを初期化:Iは、次のヘッダ(stack.h)に従ってCスタックを実装しようとしている

#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); 

そして、これは私のプログラムがクラッシュwith:

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

これは、本当に*正当な理由がない限り、typedefの後ろにポインタ型を隠さない理由です。 –

+0

@Ed S .:正確に。 'typedef struct {...} mystruct_t;も疑わしい、IMHOです。なぜこの練習は学校でまだ教えられていますか?先生が皆、パスカル主義の終末的な形から苦しんでいるように私には思える。 – wildplasser

+0

@wildplasser:まあ...私がC言語を書いているときは、どこにでも 'struct foo f;'を書くのを避けるためにstructをtypedefします。私はそれが問題のように見えませんが、ポインタ型で...ドラゴンズがあります。 –

答えて

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、あなたのために。 –

+0

+正しいものであることと、ポインタ型を 'typdef'するのは一般的には悪いことだと言及しています。明示的な説明のために+1 –

+0

+1!今はスタックが動作していますが、* sのメモリを解放した後、簡単に "s = NULL"を説明できますか? "s = NULL"と書かなければ、sの値は未定義/無作為なものがシステムの "空き(s)"の後ろにあるでしょうか? – rize

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); 

次にあなたが呼ばれる機能を持っている必要があります動的メモリをfreeNULLへのポインタを設定しますstack_destroy

​​
+0

それは常に 'stack_node_s'です。 'sizeof(** stack)' –

+0

@EdSを使う方が安全かもしれません。あなたが正しい。私の無効なポインタの感覚はうずきがしていましたが、 'sizeof'はコンパイル時に忘れていますので、それは問題ありません。 –

-1

あなたはNULLにスタックを初期化する必要があります - それにNULL値をプッシュするではない:

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

これは私が見た中で最も無駄な' init'関数です。 -1 –

+0

@EdS。私はそれが役に立たないと知っているが、OPは機能を望んでいる...彼は無効なアドレスにNULLをプッシュしようとするが、これを行う理由はない。彼が必要とするのは、彼が持っている 'stack_s'にNULLを割り当てることだけです。 – asaelr

+0

いいえ、彼は 'init'関数を持っており、後でスタックを使うことができると期待しています。あなたの実装は、あなたがそうすることができないことを単に保証します。 OPの問題は、関数への入力がスタックへのポインタへの有効なポインタであると予想されていないことです。彼は(typdefを通して隠された)スタックへのポインタを宣言しましたが、決してそれを初期化しませんでした。あなたが何かをしなければならない場合は、 'malloc'はすぐそこにあるものです。 –

関連する問題