2017-02-04 4 views
0

ここに私を混乱させるコードがあります。Cタイプ*(ブランク)宣言(バイナリツリー、ケースインポイント)

struct tNode { 
    int key;   // search key for this item 
    int data;   // data for this item 
    struct tNode *left, *right; // children 
}; 

typedef struct tNode tree_type; 

/**************** tree_new() ****************/ 
/* Create a new tree */ 
tree_type * 
tree_new(const int key, const int data) 
{ 
    tree_type *node = malloc(sizeof(struct tNode)); 

    ... 
    } 
} 

だから私はかなり右tree_new機能上tree_type *の構文が届きません。ポインタのようには見えません...それが何をしているのかは分かりません。

---------------------後編集 お手数をおかけしていただきありがとうございます。

+0

ポインタです。 'tree_new'は' toree_type'へのポインタを返します。 – jtbandes

+0

これは関数の戻り値の型です。それはポインタです... –

+3

Cで改行は特別なものではありません。あなたが 'tree_type * tree_new(...')を書いたのと同じです。 – user2357112

答えて

3

tree_type * 
tree_new(const int key, const int data) 

は、その戻り値の型を持つ関数の定義を記述するだけで、別の法的な方法です。

tree_type *tree_new(const int key, const int data) 

それがセミコロンで終わっていないので、ステートメントは次の行に続きます。

3

tree_type *は空白の宣言ではありません。 tree_typeは宣言指定子であり、*は、関数tree_newの宣言子の一部です(ニットピックの場合は@Jonathan Lefflerに感謝します)。
つまり、tree_type *は、関数tree_newの戻り値の型を表しています。あなたが一緒に両方の行を読まなければならない

+1

厳密に厳密には、 'tree_type'はa _declaration_specifier_と '*'は関数の_declarator_の一部ですが、これは選択肢の中で最も厄介なものです –

+0

@JonathanLeffler;これは実際には言語文法の通りです。 – haccks

1

あなたのポインタの使用は上手く見えます。 malloc()は、メモリへのポインタを定義されたポインタ型に返します。あなたの小さなコードを見た後、私はあなたのバイナリツリーの例がで使用されるかもしれないことと、コンテキストのための提案を受けることができます思った。

のtypedef nameing大会

構造体の宣言とtypedefのは同じで行うことができます時間。それは好みの問題です。 Cのtypedefの一般的な規則は、型名をsomeType_tの形式で指定し、使用されているどこでもtypedefを一貫して識別できるようにすることです。

私は通常のでmalloc()calloc()ゼロに割り当てられたメモリとは異なり、むしろmalloc()よりも、calloc()を使用

割り当てられたメモリをゼロに。

割り当て関数の名前に(慣例により)、返されたかどうかを示すために単語を追加することができます(呼び出しレイヤーのヌルチェックが不要ななど)。

安全な割り当てと割り当て障害

のための割り当てをチェックし、ヌルのチェックを行い、利用可能な十分なメモリがない場合は、明示的なシンプルメモリ不足のメッセージが表示されます。プログラムのメモリが不足している場合は、通常は致命的とみなされ、プログラムを終了する正当性があると考えられます。十分なメモリがないとどこでも失敗する可能性があるからです。これは非常にまれなプログラムであり、メモリ不足状態をロバストに処理するための洗練された方法です。たとえば、メモリを再び使用できるようになるまで待ってから再試行することができます。安全な割り当て関数を使うと、呼び出しレイヤーに多くのヌルチェックを保存することができます。

設定が解放されたポインタの設定がNULLに

注意をNULLにポインタを解放しました。これが一貫して行われると、NULLチェックによってポインタが常に有効であるかどうかを判断できます。さらに、ほとんどのシステムでNULLを解放するのはNOPなので、ダブルフリー(ポインタを2回以上解放する)のリスクを下げることができます。これは、特に大規模なプログラムでは、悲惨で困難なバグを診断する可能性があります。

単純なバイナリツリーの例
(コンパイル/実行されます)

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

typedef struct Tree { 
    int key;    
    int data;   
    struct Tree *left, *right; 
} tree_t; 

// Dummy data just for example: 

#define KEY 1 
#define VAL 2 
#define KEY2 3 
#define VAL2 4 
#define KEY3 5 
#define VAL3 6 

tree_t *node_create_safe(const int, const int); 
void free_tree(tree_t *); 

int 
main() { 
    tree_t *rootNode = node_create_safe(KEY, VAL); 
    rootNode->left = node_create_safe(KEY2, VAL2);; 
    rootNode->right = node_create_safe(KEY3, VAL3);; 
    free_tree(rootNode); 
    rootNode = NULL;  
} 

/* 
* node_create_safe() - allocates node, always returns pointer. 
* 
*  Side effects: Terminates program on allocation failure. 
*/ 
tree_t * 
node_create_safe(const int key, const int data) { 
    tree_t *node = calloc(sizeof(struct Tree), 1); 
    if (node == NULL) { 
     fprintf(stderr, "out of memory\n"); 
     exit(-1); 
    } 
    node->key = key; 
    node->data = data; 
    return node; 
} 

/* 
* free_tree() - Recursively frees [sub]tree 
*/ 
void 
free_tree(tree_t *node) { 
    if (node->left != NULL) 
     free_tree(node->left); 
    if (node->right != NULL) 
     free_tree(node->right); 
    free(node); 
} 
2
int *foobar(int x) { 
    return 42; 
} 

tree_type(またはstruct tNode)と

int * 
foobar(int x) 
{ 
    return 42; 
} 

同じことと同じです。