c中链接列表使用的不同类型的结构内存分配方式

问题描述 投票:0回答:1

我正在用'c'写单链列表的程序,有两种方式(它们在结构内存分配方式上有所不同)。

1.

struct SingleLinkedList
{
    int data;
    struct SingleLinkedList* next;
};

typedef struct SingleLinkedList sll;

sll* createNode()
{
    sll* node = (sll*) malloc(sizeof(sll));
    node -> next = NULL;
    return node;
}

2.

struct SingleLinkedList
{
    int data;
    struct SingleLinkedList* next;
};

typedef struct SingleLinkedList sll;

sll createNode()
{
    sll node;
    node.next = NULL;
    return node;
}

我想知道第二种程序的写法是否正确? 如果不正确,为什么会这样? 如果正确,为什么我在网上找不到这样的程序?

c data-structures memory-management linked-list structure
1个回答
2
投票

你的第一个程序返回一个 指针 到(分配的)结构中。的调用者 createNode 现在的责任是 free()在指针超出作用域之前,它的内存就已经存在了,而节点存在的好处是,直到它被删除为止。free()d.

你的第二个程序在没有 "分配 "内存的情况下,按值返回一个结构体。事实上,这个结构体 node 内创建的 createNode 函数返回时,函数不再存在;函数的调用者得到的是一个 拷贝 的(局部)结构。(尽管大多数编译器会将其优化为零。)

你不常看到第二种类型,因为。

1) 它实际上是一个多余的函数调用; 而不是... ...

ssl node = createNode();

...只是调用...

ssl node = { 0, NULL };

2)那个节点又只会存在到当前作用域结束。如果你在函数中建立一个这样的链接列表。initList(),例如,一旦出现了 initList() 返回的所有节点都将离开范围,而你的指针将什么都不指向。好吧,无论如何,不是分配的节点结构。 ;-) 如果你在循环中初始化这些节点,每个节点都会在循环迭代结束时退出作用域......所有这些都很可能不是你想要的。 ;-)


0
投票

首先,这两个函数都应该用一个参数来声明,这个参数的值是用来初始化数据成员的。data 的节点。

例如,可以用以下方式定义函数

sll * createNode( int data )
{
    sll *node = malloc( sizeof( sll ) );

    if ( node != NULL )
    {
        node->next = NULL;
        node->data = data;
    }

    return node;
}

sll createNode( int data )
{
    sll node = { data, NULL };
    return node;
}

这两段代码都是正确的。你的程序是否会不正确,取决于你是否会正确使用这些函数。

例如第二个函数可以在下面的上下文中使用(将一个新节点追加到列表的尾部)。

int append( sll **head, int data )
{
    while ( *head != NULL )
    {
        head = &( *head )->next;
    }

    *head = malloc( sizeof( sll ) );

    if ( *head ) **head = createNode( data );

    return *head != NULL;
}

第二段代码的唯一缺点是,在大多数情况下,最好将节点分配和初始化结合在一个函数中,而不是像第二段代码那样将这两个操作分开。

然而,有时将初始化本身放在一个单独的函数中是有意义的,因为初始化可以是足够复杂的。这将使整个代码更具可读性。

顺便说一下,在C++中,由于使用构造函数,正是这样做的。也就是由构造函数(独立函数)来负责初始化。

所以你可以考虑这个函数

sll createNode( int data )
{
    sll node = { data, NULL };
    return node;
}

类型的对象的构造函数。sll.

所以,从介绍的两个代码片段中,函数的目的是不同的。第一个函数是动态分配一个节点。而第二个函数是用来初始化一个已经存在的节点。

© www.soinside.com 2019 - 2024. All rights reserved.