【问题标题】:Using pointer to a struct to create linked list and Memory allocation in C使用指向结构的指针在 C 中创建链表和内存分配
【发布时间】:2011-08-03 22:20:43
【问题描述】:

我想我有一个概念问题。当我需要创建一个链表时,我只是得到了一个指向结构的指针(并且该结构包含一些数据类型和指针“next”)。我将如何确保创建其他链接而不仅仅是根节点?我没有使用 malloc ,否则这将是更明显的答案。这个列表本身就是 malloc。

提前致谢!

澄清:

将有一个一维数组,它将充当一个固定大小的内存块。然后,链表将通过删除一个节点并将其放入数组中来“分配”,或者通过将其从数组中删除以添加回链表来“释放”数据。

示例

(由某些数据类型和指针定义的结构) 结构称为节点

node array[10];  //this acts as memory
node* linked_list;  //this gives or removes data to memory (array)

【问题讨论】:

  • 如果像malloc一样只有一个根,可以为根使用一个全局变量,并测试它是否为NULL。问题不清楚……
  • 借口 - 我已经澄清了问题。

标签: c memory-management linked-list structure


【解决方案1】:

这类似于我们在我的数据结构课程中使用 FORTRAN 77(早在白垩纪中期)所做的事情;我们分配了一个固定大小的数组并将其用作我们的内存池。

基本上,您必须维护一个“免费”列表;这些是可供使用的节点。首次启动时,将数组中的每个元素初始化为显式指向下一个元素:

struct node {T data; struct node *next; } pool[N]; // for some type T
...
for (i = 0; i < N-1; i++)
  pool[i].next = &pool[i+1];
pool[i].next = NULL;

您的空闲列表最初指向池中的第一个元素:

struct node *free = &pool[0];

分配节点时,您检索free 指向的元素,更新free 以指向列表中的下一个可用元素(如果存在),然后根据需要初始化该元素:

if (free) // is there a free node available
{
  struct node *newNode = free;
  free = free->next;
  newNode->data = ...;
  newNode->next = NULL;
  ...
}

完成一个节点后,将其添加回free 列表的头部:

node->next = free;
free = node;

自然地,实际代码会比这更有条理,但这应该足以让您知道该怎么做。

【讨论】:

  • +1,这绝对比在节点 struct 中有一个“标志”字段更好。
  • 我进行了这些更改并使用了这个想法 - 如果我在释放多个节点时遇到分段错误,为什么会发生这种情况? (对不起,如果这含糊不清)我正在循环添加新节点,然后循环删除一些。
  • @abitlost:segfault 听起来像是 next 指针未正确初始化,或者您试图取消引用 NULL 指针,或类似的东西。让我更新我的答案,以提出一些更强大的东西。
  • @abitlost:实际上,现在我想起来了,请确保在更新空闲列表之前不要破坏下一个指针。
【解决方案2】:

我不能确定这是否适用于您的特定问题,但我确实想指出一些关于在不使用 malloc 的情况下创建链接列表的内容。

如何分配链表的节点并不重要,无论是动态还是静态。重要的是每个节点都实际存在并且指针是有效的。

例如,我们可以从一个数组构建一个链表。

#include <stdio.h>

typedef struct node_t {
    int value;
    struct node_t *next;
} node;

int main() {

    int i;
    node linked_list[10];

    // build the linked list
    for ( i = 0; i < 10; i++ ) {
        linked_list[i].value = i * i;
        linked_list[i].next = ( i < 9 ) ? &linked_list[i+1] : 0;
    }

    // now traverse it
    node *head = &linked_list[0];
    while ( head ) {
        printf( "%d\n", head->value );
        head = head->next;
    }
}

编辑:为了使用数组作为“分配”或“释放”链表节点的位置,您可以在节点struct 上添加一个标志来指示是否节点是否被使用。

typedef struct node_t {
    char in_use;
    int value;
    struct node_t *next;
} node;

EDIT2:让我们再试一次。下面是从数组中“分配”一个节点的函数(如果没有可用节点,则返回 NULL)。假设 linked_list 是全局的。

node *get_node() {
    int i;
    for ( i = 0; i < 10; i++ )
        if ( !linked_list[i].in_use ) {
            linked_list[i].in_use = true;
            return &linked_list[i];
        }
    return 0;
}

EDIT3:如果要将数组用作内存池,那么 John Bode 的答案就是要走的路。

【讨论】:

  • 是的,我遇到的问题是确保列表中的每个节点都存在。但对于阵列我敢肯定。我用这个 for 循环来做到这一点。指向结构的指针需要有节点,但我不确定它们是否存在。假设我们添加: node* ptr;这应该与您提供的数组具有相同数量的节点。如何为创建链表的指针创建每个节点?
  • 我不确定我是否理解你。节点要么已经分配,​​要么没有。你怎么不确定?
  • 'int i;节点链接列表[10];节点* ptrLinkedList; // 使用 this 创建链表 // 为 ( i = 0; i
  • 好的,那你想要什么,创建另一个与head指向的链表相等的链表,或者别的什么?
  • 头部应该一次只删除一个链接以放入数组中。不是为了穿越。似乎我没有创建多个链接。我怎么知道它是一个完整的链表而不仅仅是根节点?
【解决方案3】:

有几种可能的情况:

  • 链表正在使用 malloc。然后链表负责节点的分配和解除分配。这是标准实现。

  • 链表正在使用静态分配的内存块,即固定大小的静态数组。这样的链表更复杂,因为您必须跟踪数组的哪些部分包含数据。您还需要跟踪链表的大小。

  • 链表是一个“带有索引查找表的节点数组”。然后它不分配任何数据,而是每个节点都包含数组索引。链表需要跟踪列表的大小。

  • 链表未执行任何分配。分配由调用者完成(静态或动态)。在这种情况下,链表只跟踪下一个指针并且不分配任何内容。这个版本是糟糕的面向对象设计,因为它破坏了数据的私有封装。

操作更改后编辑: 似乎您正在使用上面的版本 3。谷歌“使用数组的链表”或类似的。

【讨论】:

  • #2 更像是我的问题 - 链表使用的是固定大小的数组
猜你喜欢
  • 2014-02-23
  • 2013-05-09
  • 1970-01-01
  • 1970-01-01
  • 2021-12-26
  • 2013-05-06
  • 1970-01-01
  • 2018-05-16
  • 2015-07-04
相关资源
最近更新 更多