1

I'm having a struct like this:

typedef struct tree_s{
    struct tree_s *a;
    int b;
}tree_t;

Which, at the moment, I am initializing in this way:

tree_t branch_n = {
    .a = NULL,
    .b = 2
};

tree_t root = {
    .a = (tree_t*) &branch_n, 
    .b = 1
};

Now, it annoys me that I have to initialize the lower branches before the root because the complete structure is quite large, with the branches having branches on their own, making my code hard to manage.

What I would like to do is something like this:

tree_t root = {
    .a = 
     //The first branch
     {                 
        .a =
         //Yet another branch 
         { //Since the following is actually an array, I need the 
           // "a" above to point to the first index
             {  
                 .a = NULL,         //Maybe this will have its own branch
                 .b = 3
             },
             {
                 .a = 
                 {
                     .a = NULL,     //And this might even have its own branch
                     .b = 5
                 }
                 .b = 4  
             }
         }
        .b = 2
     }, 
    .b = 1
};

How can I achieve an initialization like this?

The main reason I want to do this is to greatly enhance the overview of my code and immediately visually see the structure of the "Tree".

Note that the structure of the complete "Tree" is know from the start which is why I consider the structure constant. The value b however may be changed at any time.

I am quite new to the C language and this is my first post on SO, so feel free to edit or ask if I havent been able to make myself clear :)

4

2 に答える 2

3

オプション 1a — 配列

あなたの「ツリー」構造はかなり直線的な形状にとどまっているようですが、配列を使用して問題を回避できます。

static const tree_t oak[] =
{
    { .a = &oak[1], .b = 20 },
    { .a = &oak[2], .b = 15 },
    { .a = NULL,    .b = 10 },
};

オプション 1b — 配列から構築されたツリー

または、二分探索木構造が与えられた場合:

#include <stdio.h>

typedef struct bst_t bst_t;
struct bst_t
{
    int          data;
    const bst_t *left;
    const bst_t *right;
};

static const bst_t bst[] =
{
    { .data = 30, .left = &bst[1], .right = &bst[2] },
    { .data = 10, .left = &bst[3], .right = &bst[4] },
    { .data = 50, .left = &bst[5], .right = &bst[6] },
    { .data =  5, .left = &bst[7], .right = &bst[8] },
    { .data = 20, .left =       0, .right = &bst[9] },
    { .data = 40, .left =       0, .right =       0 },
    { .data = 60, .left =       0, .right =       0 },
    { .data =  2, .left =       0, .right =       0 },
    { .data =  8, .left =       0, .right =       0 },
    { .data = 28, .left =       0, .right =       0 },
};

static void print_in_order(const bst_t *bst)
{
    if (bst != 0)
    {
        printf("[");
        print_in_order(bst->left);
        printf("(%d)", bst->data);
        print_in_order(bst->right);
        printf("]");
    }
}

static void print_tree(const bst_t *bst)
{
    print_in_order(bst);
    putchar('\n');
}

int main(void)
{
    print_tree(&bst[0]);
    return 0;
}

これにより、次の出力が生成されます。

[[[[(2)](5)[(8)]](10)[(20)[(28)]]](30)[[(40)](50)[(60)]]]

オプション 2a — C99 複合リテラル

C99 と複合リテラルを使用すると、次のように記述できます。

#include <stddef.h>

typedef struct tree_s{
    struct tree_s *a;
    int b;
}tree_t;

tree_t root2 =
{
    .a = &(tree_t){ .a = NULL, .b = 2 }, .b = 1
};

tree_t root3 =
{
    .a = &(tree_t){ .a = &(tree_t){ .a = NULL, .b = 3 }, .b = 2 }, .b = 1
};

判読できるかどうかはわかりませんが、コンパイルは問題ありません。全体として、私は配列表記を好みます。

これは、OPが望んでいた/使用した主な答えです。


オプション 2b — 配列を初期化しようとして失敗しました

問題の改訂されたデータ構造を適応させようとすると (データ構造で作成できる「ツリー」は単一リンク リストのみであることに注意してください)、これでほぼ (完全ではありません) 実行できます。

tree_t root4 =
{
    .a = &(tree_t)
    {                 
        .a = (tree_t [])
        { 
            (tree_t){  
                .a = NULL,
                .b = 3
            },
            (tree_t){
                .a = &(tree_t)
                {
                    .a = NULL,
                    .b = 5
                },
                .b = 4  
            },
        },  // Line 47
        .b = 2
    }, 
    .b = 1
};

Mac OS X 10.8.4 上の GCC (i686-apple-darwin11-llvm-gcc-4.2 (GCC) 4.2.1 (Apple Inc. ビルド 5658 に基づく) (LLVM ビルド 2336.11.00)) は次のように文句を言います:

tree.c:47: error: initializer element is not constant
tree.c:47: error: (near initialization for ‘(anonymous)’)

行 47 がマークされている場所は、構造体の配列の最後です。明らかな何かが欠けている可能性があります。試してみ&(test_t[]){ ... }[0],ましたが、同じ警告が表示されました。

tree_t違いを示すために別のフィールドを追加しない限り、特定のポインターが単一の要素ではなく配列の先頭へのポインターであったことをどのように判断できるかはわかりません(または、bフィールドがエンコードされているかどうかを示すために何らかの形でエンコードされています)。a単一項目へのポインターまたは配列へのポインター)。

于 2013-07-19T09:16:43.937 に答える
0

私はこのコードを考えていません:

tree_t root = {
    .a = 
     //The first branch
     {                 
        .a = NULL,       //Maybe another branch instead of NULL
        .b = 2
     }, 
    .b = 1
};

tree_t ルートを正常に初期化します。

{} は、ポインタではなく、構造体を初期化するためのものです。しかし、root->a はポインタとして定義されています。これにより、コンパイルエラーが発生する可能性があります。

ブランチは、上記のコードの外で定義および初期化でき、ポインター root->a ポイントをそれに設定できます。

于 2013-07-19T09:46:08.750 に答える