0
typedef struct list
{
    struct list * next;
    int val;
}*list_t;    

list_t add(list_t l,int e)
{
    list_t head;

    if(l == NULL)
    {
        l = malloc(sizeof(list_t));
        l->val = e;
        l->next = NULL;
        return l;
    }       

    head = l;

    while(l != NULL)
        l=l->next;

    l = malloc(sizeof(list_t));

    l->val = e;

    l->next = NULL;

    return head;
}

サンプルドライバー:

int main()
{
    list_t ints=NULL;
    int i;

    for(i=0;i<156;i+=2)
        ints = add(ints,i);

    while(ints->next != NULL)
    {   
        printf("%d\n",ints->val);
        ints=ints->next;
    }

    system("pause");
    return 0;
}

プログラムは動作しますが、「add」関数はリストを巻き戻して、メインのループの本体が達成されないようにします。リストを値として渡していると思っていたので、とても驚きました。この現象を説明してもらえますか?

4

3 に答える 3

2

特殊なケースは避けてください。add() 関数でできることは 1 つだけです。リスト ノードを割り当て、そのポインタ値を、たまたま null になったチェーン内の最初のノードに割り当てます。チェーンの先頭、中間、末尾の NULL ノードに違いはありません。(もちろん、null ノードはリストの途中に存在することはできません。リストの先頭に存在することはできますが、リストは空になります)最初の NULL を見つけて、そこに新しいノードを配置します。

struct list *add(struct list *lp, int e)
{
    struct list **pp;

    for (pp= &lp; *pp; pp = &(*pp)->next) {;}

    *pp = malloc(sizeof **pp);
    (*pp)->val = e;
    (*pp)->next = NULL;

    return lp;
}
于 2013-01-16T18:39:54.223 に答える
2

問題は、追加機能がリストを巻き戻すことではなく、まったく機能しないことです。コードのどこにも、リストの前の最後が新しく追加された要素にリンクする必要があると述べていません。

私はそれを少し修正しました:

typedef struct list
{
    struct list * next;
    int val;
} list_t;    

list_t *add(list_t *l,int e)
{
    list_t *head;

    if(l == NULL)
    {
        l = malloc(sizeof(list_t));
        l->val = e;
        l->next = NULL;
        return l;
    }       

    head = l;

    while(l->next != NULL)
        l=l->next;

    l->next = malloc(sizeof(list_t));

    l=l->next;

    l->val = e;

    l->next = NULL;

    return head;
}

int main()
{
    list_t *ints=NULL;
    int i;

    for(i=0;i<156;i+=2)
        ints = add(ints,i);

    while(ints->next != NULL)
    {   
        printf("%d\n",ints->val);
        ints=ints->next;
    }

    return 0;
}

コードが期待どおりに動作するようになりました。

lこれは関数内のローカル変数であることを忘れないでくださいaddl何らかの方法で関数のスコープを離れることが許可されていない場合 (最初の if 内で関数を返すときのように) に加えられた変更は失われます。または演算子lを使用して変数ポイントに加えられた変更は、その変数にアクセスできるすべてのユーザーに有効になります。*->

デバッグ手法について読み始めることをお勧めします。それらは環境によって異なり、 gdb のような暗号化されたコマンドライン ツールから本格的なグラフィカル オブジェクト ブラウザーなどに至る場合があります。このようにして、何が起こっているかを段階的に確認し、メモリの変更を監視し、変数に実際に格納されているものを確認できます。

EDIT : コメントのようにポインターのトラブルを修正しました。メモリ割り当ては構造体変数全体を提供するようになり、ポインターは暗黙的に使用されなくなりました。

于 2013-01-16T18:34:06.543 に答える
1
l = malloc(sizeof(list_t));

構造体自体ではなく、構造体へのポインターを割り当てます。たとえば、64 ビット マシンでは、malloced サイズは 8 ですが、本来は 16 です。

続いて言うと

l->val = ..
l->next = ..

神だけがあなたがどこに書いているかを知っています..

リンクされたリストのサンプルコードを検索して、デバッガーで読んでください。

于 2013-01-16T18:44:05.387 に答える