当节点是结构的成员时,它的行为会改变吗?

Does a node's behaviour change when it is a member of a struct?

我正在尝试学习如何使用链表,所以我自己编写了一个函数来递归地遍历链表并打印存储在每个节点中的单词,但它只打印倒数第二项,然后无限期地重复。我已经调试了这个,我可以看到它是因为最后一个节点将满足 n.next != NULL,所以我想将条件更改为 n != NULL 以避免这种情况,但我收到错误消息:error: invalid operands to binary expression ('node' (aka 'struct node') and 'void *').我试图在 Google 和 SO 上搜索错误消息,但我无法解释为什么 n.next != NULL 可以很好地编译而 n != NULL 不能。对我来说,我会说 nn.next 都是 node 类型,但我的直觉可能以某种方式欺骗了我。是因为 n.nextstruct member 它的行为发生了变化,还是我走错了路?

我包含下面的代码(有问题的函数在底部):

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

typedef struct node
{
    char word[20];
    struct node *next;
}
node;

void print (node n);

node *table[1];

int main(void)
{
    // TODO
    char word[20];

    FILE *file = fopen("list", "r");
    node *first = malloc(sizeof(node));
    table[0] = first;

    if (file != NULL)
    {
        while (fscanf(file, "%s", word) != EOF)
        {
            node *entry = malloc(sizeof(node));
            if (entry != NULL)
            {
                strcpy (entry->word, word);
                entry->next = first->next;
                first->next = entry;
            }
        }
    }
    
    print(*first);
}

void print (node n)
{
    while(n != NULL)
    {
        printf("%s\n", n.word);
        print(*n.next);
    }
}

To me, I'd say n and n.next are both type node

不是这样; nnode,但 n.next 是类型 node *,即指向 node 的指针。指针可以为空,但结构不能。

因此传递给 print 的对象保证有效。 (如果 first 是空指针,那么 print(*first) 在您输入 print 之前就已经崩溃,或者“导致未定义的行为”。)

也没有必要在 print 中有一个循环,因为递归处理列表遍历。事实上,如果你试图保持循环原样,它就是一个无限循环,因为循环体中没有任何内容会修改 n.

的值

我会写:

void print (node n)
{
    printf("%s\n", n.word);
    if (n.next != NULL)
        print(*n.next);
}

然而,这种方法并不是真正的惯用方法,而且效率也不是很高,因为按值传递 struct 往往会涉及不必要的复制和堆栈使用。正如 dbush 所建议的那样,拥有一个采用指针的版本会更常见:

void print(const node *np)
{
    if (np)
    {
        printf("%s\n", np->word);
        print(np->next);
    }
}

然后您将其称为 print(first);

下一个很好的练习是尝试编写不使用递归的 print 版本,因为这将允许您处理可能超过堆栈大小的非常长的列表。

主要有以下问题:

  1. 不要忘记在malloc之后初始化值,或者它们可以是任何东西,尤其是下一个不会像你期望的那样是NULL。
    node *first = (node*)malloc(sizeof(node));
    first->word[0] = '[=10=]';     
    first->next    = NULL;
    node *entry = (node*) malloc(sizeof(node));
    entry->word[0] = '[=10=]';
    entry->next    = NULL;

我更喜欢使用 calloc 而不是 malloc

node* first = (node*)calloc(1, sizeof(node));
assert(first);

node* entry = (node*)calloc(1, sizeof(node));
assert(entry);
  1. 在打印函数中
    void print (node* n)
    {
            if(n != NULL)
            {
                    printf("%s\n", n->word);
                    print(n->next);
            }
            
    }

因为你递归调用 print,所以应该使用 if 而不是 while