c - 在链表中插入 -



我在读Skeina的书。我无法理解这段代码。基本上双指针有什么用。*l = p有什么用?任何人都可以用图表解释一下。

void insert_list(list **l, item_type x) {
    list *p; /* temporary pointer */
    p = malloc(sizeof(list));
    p->item = x;
    p->next = *l;
    *l = p;
}

您不应该称其为"双指针",因为那将是指向double的指针。 它是指向指针的指针,用于允许函数更改恰好是指针的参数的值。 如果你熟悉 C#,它就像一个out论点。 在这种情况下,l参数用于获取 IN 和 OUT 行为,但您可能经常看到它仅用于输出。

由于此函数返回类型void因此可以在不使用指向指针的情况下很好地编写它,如下所示:

list * insert_list(list *l, item_type x) {
{
    list *p; /* temporary pointer */
    p = malloc(sizeof(list));
    p->item = x;
    p->next = l; // note that this is not *l here
    return p;
}

此更改需要调用函数的代码更新其自己的列表句柄,因为列表的头部是要更改的内容。

此函数执行一个非常简单的任务:list它在它接收指针的位置。 什么都没有关于双指针的特别之处,它们只是指向指针的指针。 它们保存指针的地址,指针包含对象的地址。 void **l包含list *指针的地址。 *l检索此地址和*l = p存储它。

malloc用于分配 list结构中,p接收已分配结构的地址。代码有些草率,因为之前没有检查p NULL取消引用它。 如果malloc由于内存不足而失败,则程序将调用未定义的行为,希望以分段错误或可能更糟的情况。

节点初始化,其next指针设置为指向的节点通过l参数,最后存储新节点的地址在作为l参数传递的地址。 效果很简单:节点插入 *l .

这种方法很聪明,它允许相同的功能在列表的任何地方插入新节点。例如:

list *head = NULL;
...
/* Insert a LIST_A node at the beginning of the list */
insert_list(&head, LIST_A);
...
/* insert a LIST_B element as the second node in the list */
insert_list(&head->next, LIST_B);
...
/* find the end of the list */
list *node;
for (node = head; node->next; node = node->next)
    continue;
/* insert a LIST_Z node at the end of the list */
insert_list(&node->next, LIST_Z);

上面唯一棘手的是指针本身的概念,这里有一个简单的概述:

  • 内存可以概念化为(大型)字节数组,地址是该数组中的偏移量。
  • 根据定义,char变量是单个字节,
  • int变量占用特定于系统体系结构的字节数,在当前硬件中通常为 4 或 8 个字节。
  • 将指针视为在另一个变量的内存中保存地址的变量。它们需要足够大以容纳系统中的任何有效地址,在当前具有超过 4 GB 物理和可寻址内存的系统中,它们长 64 位,占用 8 个字节。
  • 有一个特殊的地址值NULL它不表示任何对象,用于指定给定指针不指向任何实际对象。地址0用于此目的。 malloc将返回NULL如果它无法分配请求的内存,则应测试返回值,因为禁止在此地址存储值,并且通常被捕获为无效访问(分段错误)。

此摘要故意过于简单。 我使用术语变量而不是对象来避免与 OOP 概念混淆。

相关内容

  • 没有找到相关文章

最新更新