【问题标题】:Linked Lists in C, last node point to NULL?C中的链表,最后一个节点指向NULL?
【发布时间】:2015-08-10 06:39:23
【问题描述】:

在 C 中,我必须始终初始化指向 NULL 的最后一个节点吗?我通常会在教程和书籍中看到这种情况。但据我了解,未初始化的指针与 NULL 指针拥有相同的地址。那么为什么要初始化呢?

【问题讨论】:

  • 未初始化保存未指定的值。这与 NULL 不同。
  • "未初始化的指针与 NULL 指针拥有相同的地址" 是这样吗?那么是什么将其初始化为 NULL
  • 顺便说一句:没有必要将最后一个指针设置为 NULL。它必须是指示列表结尾的任何值。这可以是例如列表锚的地址,或者如果您喜欢值为 0xffffffff 的指针。但在大多数情况下,按惯例使用 NULL。这允许像while (p->next) p=p->next 这样的语法。
  • 简短的回答是否定的,但您必须了解链表有 2 种类型(通常)。第一个是传统的 head/tail 列表,其中最后一个节点是NULL,用作列表末尾的标记。第二种类型的链表是循环链表,其中最后一个节点的ptr->next 指针始终保存链表开始的地址。不需要 NULL,因为迭代会一直持续到再次到达第一个节点。 (中间有许多列表类型)根据您的要求,一种可能比另一种更好。
  • @harper:不,它必须是 NULL 或真实对象的地址,而不仅仅是像 0xffffffff 这样的任意值。否则,即使将它与另一个指针进行比较也是未定义的行为。

标签: c pointers null linked-list initialization


【解决方案1】:

但据我了解,未初始化的指针与 NULL 指针拥有相同的地址

可能,运气不好。

在任何情况下,读取 未初始化 指针都会调用未定义的行为。这是否会迟早导致崩溃(或任何其他“奇怪”行为)是未知的,因为未定义行为的性质。

但是,根据指针变量“存在”的内存的分配方式,如果分配内存,内存可能会“已经”初始化

这两种方法都会提前分配内存和0。对于最近的系统来说,有一个指针变量(位于此内存中)承载NULL 的值就足够了。

但请注意,可能仍有一些实现为NULL 使用不同 位模式,而不仅仅是0-bits。因此,为了保持 100% 的可移植性,最好始终显式地使用 NULL 进行初始化,而不是依赖于隐式清除的内存。顺便说一句,这也有助于您的资源的潜在读者。

【讨论】:

    【解决方案2】:

    当你创建一个指针而不初始化它时,比方说

    char *ptr;
    

    内存指向一些字节(取决于您的指针类型)。 这些字节,可能是任何东西。就像一些之前初始化的未释放指针,或者,指向一些垃圾。

    这与 NULL 指针不同。

    为避免这种情况,您应该养成初始化每个指针的习惯(除了初始化为 0 的全局变量和静态变量),并在每次使用数组或包含多元素的任何内容时添加一个 NULL。 假设在这种情况下,NULL 是数组/列表的“\0”。 例如,如果你想创建一个包含几个 char * 的数组,这样做:

    void function()
    {
     char *array[4];
    
     array[0] = strdup("Jason");
     array[1] = strdup("Mike");
     array[2] = strdup("Nicole");
     array[3] = NULL;
    }
    

    它可以帮助您不要超出您之前为此指针分配的内存,避免内存失败和分段错误。如果您使用计数器来遍历此数组的每个案例。

    否则,不要在任何地方使用NULL,如果你分配了一个字符串,不要在on之后用NULL填充它。

    int main()
    {
        char *ptr;
        if ((ptr = malloc(sizeof(char) * 42)) == NULL)
            return (-1);
        ptr = NULL;
     return (0);
    }
    

    这不起作用,因为您将 NULL 发送到您之前直接清理的字节中。 如果您想正确使用指针并在使用前对其进行清理,则可以使用 memset。这会将 x 数量的相同字节发送到指针中,通过传递给 memset 参数的字节清除其中可能存在的垃圾。

    【讨论】:

    • "内存指向一些字节" 取决于平台,它甚至可能根本没有指向内存!-)
    • This "... 每次使用数组或包含多元素的任何内容时添加一个 NULL。假设在这种情况下,NULL 是数组的 '\0' /list.” 不知何故我不(完全?)清楚。您可能想花时间澄清您想要表达的内容。
    • 我确实澄清了我想说的话。
    • “假设在这种情况下,NULL 是数组/列表的'\0'。” 这是什么意思? NULL 是一个空指针宏,而'\0' 是一个空字符——它们不是一回事。
    • 你能看一下我的帖子吗,紧接着我正在写一个例子。 Null 是数组的终止指针,因为 \0 是字符串的终止字节
    【解决方案3】:

    您可能认为空指针是未初始化的指针,但这是错误的。空指针是一种特殊的指针,它不指向任何地方。

    //  To declare a null pointer.
    int *ptr=NULL;
    
    
    if(ptr==NULL) //..do something..
    

    malloc() 和 getchar() 等函数在无法执行任务或完成任务时返回空指针。

    【讨论】:

      【解决方案4】:

      未初始化的指针可以保存任何垃圾值。

      【讨论】:

        【解决方案5】:

        未初始化的局部变量的值未定义。而静态或全局将被授予者为0。

        最好初始化你定义的所有变量,否则可能会导致非常棘手的错误。

        【讨论】:

          【解决方案6】:

          与您的理解相反,未初始化的指针的内容是未定义的。只有当对象被静态分配时,它才保证被初始化为零。

          【讨论】:

          • 即使在分配的情况下,malloc 也不保证零初始化。只有calloc 可以。
          • @KDM:我不明白你的意思吗?我没有提到动态分配。静态分配是编译器在声明变量static时生成的;显然与malloc()无关。
          • 错过了statically allocated 中的statically。对不起。
          • 甚至0ed 内存也不能保证其中的“活动”指针带有NULL 值。请在此处查看脚注 296:iso-9899.info/n1570.html#7.22.3.2(浮点变量相同)
          • @alk :绝对正确 - 在 C 中 NULL 允许为非零值,但实际上在大多数架构上不太可能。然而,“通常可以侥幸逃脱”当然不是糟糕代码的借口。我认为这主要是学术性的。这将取决于链表的实现,但是在调用者提供要添加到链表的节点的情况下,不能保证节点的链接指针在任何情况下都处于任何“初始”状态 - 它可能例如,已被重复使用并包含以前所在列表的链接。
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2013-07-26
          • 1970-01-01
          • 2014-05-22
          • 1970-01-01
          • 2014-10-16
          • 2013-06-15
          • 2023-03-15
          相关资源
          最近更新 更多