堆栈结构指向自己 - 这里发生了什么?

时间:2016-10-21 05:50:38

标签: c data-structures linked-list

typedef struct _s {     // same definition as before   
    int         value;
    struct _s   *next;
}  STACKITEM;

STACKITEM    *stack = NULL;

 ....

void push_item(int newvalue)
{
    STACKITEM  *new = malloc( sizeof(STACKITEM) );  

    if(new == NULL) {     // check for insufficient memory   
        perror("push_item");
        exit(EXIT_FAILURE);
    }

    new->value   = newvalue;
    new->next    = stack;
    stack        = new;
}

这两行的目的是什么:

new->next    = stack;
stack        = new;

从我所看到的,新STACKITEM结构的下一个字段设置为指向堆栈。然后将堆栈设置为指向STACKITEM结构的新增功能?这是对的吗?

如果是这样,我不明白这是什么意思。好像它正在包装'堆栈周围和关闭'它。换句话说,当我们尝试访问堆栈中的下一个结构时,由于这实际上是最后一个可用的结构,它只能访问自己?

谢谢。

2 个答案:

答案 0 :(得分:2)

继续关注此事:

  • stack将始终(a)指向" top"的动态节点。您的堆栈,或者(b)如果堆栈为空,则为NULL。
  • 当要推送一个新分配的STACKSTRUCT节点时,最后stack必须指向该节点,但首先新分配的结构next指针必须指向前一个stack的先前值(并更改为stack)。

我的ascii艺术很糟糕,所以我不打扰。相反,我已经准备了一个使用您的代码的简单示例,但添加了print_stack以在添加每个新节点时转储堆栈的当前状态:

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

typedef struct _s {     // same definition as before
    int         value;
    struct _s   *next;
}  STACKITEM;

STACKITEM    *stack = NULL;

void print_stack()
{
    STACKITEM const* item = stack;
    for (; item != NULL; item = item->next)
        printf("%p : { value=%d; next=%p }\n", item, item->value, item->next);
    fputc('\n', stdout);
}

void push_item(int newvalue)
{
    STACKITEM *new = malloc( sizeof(STACKITEM) );

    if(new == NULL) // check for insufficient memory
    {
        perror("push_item");
        exit(EXIT_FAILURE);
    }

    printf("push.1: stack = %p, new = %p\n", stack, new);
    new->value = newvalue;
    new->next = stack;
    stack = new;
    printf("push.2: stack = %p, new->next = %p\n", stack, new->next);
    print_stack();
}

int main()
{
    for (int i=1; i<=5; ++i)
        push_item(i);
}

注意:这会故意泄漏每个节点。记忆管理不是重点; 节点管理是。

这个输出会因实现和机器(打印的指针值很多)而有所不同。按照指针值查看这一切是如何连接在一起的。请记住,此输出以自上而下的顺序显示堆栈(即每个打印输出中的第一项是堆栈的&#34;顶部和#34;)。另请注意,在推送完成后,每个转储都以stack 指向的节点开始。

示例输出

push.1: stack = 0x0, new = 0x1001054f0
push.2: stack = 0x1001054f0, new->next = 0x0
0x1001054f0 : { value=1; next=0x0 }

push.1: stack = 0x1001054f0, new = 0x100105500
push.2: stack = 0x100105500, new->next = 0x1001054f0
0x100105500 : { value=2; next=0x1001054f0 }
0x1001054f0 : { value=1; next=0x0 }

push.1: stack = 0x100105500, new = 0x100105510
push.2: stack = 0x100105510, new->next = 0x100105500
0x100105510 : { value=3; next=0x100105500 }
0x100105500 : { value=2; next=0x1001054f0 }
0x1001054f0 : { value=1; next=0x0 }

push.1: stack = 0x100105510, new = 0x100105520
push.2: stack = 0x100105520, new->next = 0x100105510
0x100105520 : { value=4; next=0x100105510 }
0x100105510 : { value=3; next=0x100105500 }
0x100105500 : { value=2; next=0x1001054f0 }
0x1001054f0 : { value=1; next=0x0 }

push.1: stack = 0x100105520, new = 0x100200000
push.2: stack = 0x100200000, new->next = 0x100105520
0x100200000 : { value=5; next=0x100105520 }
0x100105520 : { value=4; next=0x100105510 }
0x100105510 : { value=3; next=0x100105500 }
0x100105500 : { value=2; next=0x1001054f0 }
0x1001054f0 : { value=1; next=0x0 }

注意在每种情况下,新结构的next指针被赋予当前值stack,然后stack指针被赋予新结构&#39;的地址。一旦完成,结构就被推到了#34;在堆栈上,新的堆栈顶部反映了这一点。此外,该结构的next指针现在提供指向原始堆栈顶部的指针,从而提供数据结构所需的链表链。

答案 1 :(得分:0)

new->next    = stack;
stack        = new;

以上代码行对于在两个节点之间创建链接非常重要。这里发生的事情是让我们用一个例子来理解。

我们假设您只为值1,23创建了一个链接列表。因此,当您将第一个值作为1传递时会发生什么,值1将存储在node1 new->value =1中,而节点的下一个成员将指定值为{{ 1}},这意味着现在第一个节点的指针为空,而全局new->next = stack;具有第一个节点的地址。

现在您输入的第二个值为stack,现在,将为2分配第一个内存,然后将值2分配为new和{{1} }指针将包含第一个节点的地址,因为new->value =2包含第一个节点的地址。并且next被分配了第二个节点的地址。所以现在已经创建了第一个节点和第二个节点之间的链接。

对于第三个值stack,它与上面相同。

基本上这是stack的{​​{1}}方法。这里每次都为堆栈分配当前节点的地址,下一次分配给创建链接的3指针。