【问题标题】:Linked List Stack in CC中的链表堆栈
【发布时间】:2012-10-25 18:49:38
【问题描述】:

我正在看《Programming Interviews Exposed》一书中的以下段落,其中提到了 C 中链表堆栈的实现:

typedef struct Element {
   struct Element *next;
   void *data; 
} Element;

void push( Element *stack, void *data ); 
void *pop( Element *stack );

现在从适当的角度考虑这些例程中会发生什么 功能和错误处理。两个操作都改变了第一个 列表的元素。调用例程的堆栈指针必须是 修改以反映此更改,但您对 传递给这些函数的指针不会被传播回 调用例程。您可以通过同时拥有两者来解决此问题 例程采用指向堆栈指针的指针。这样,您可以 更改调用例程的指针,使其继续指向 列表的第一个元素。实施此更改会导致 以下:

void push( Element **stack, void *data ); 
void *pop( Element **stack);

有人可以用不同的话解释为什么我们需要在这里使用双指针吗?我对所提供的解释有点不确定。

【问题讨论】:

    标签: c linked-list stack


    【解决方案1】:

    第一个版本发送一个指针的copy,如果它在函数内部被更改,那么本地副本只会在函数返回给调用者时被更改> 调用者仍然有一个指向旧地址的指针。

    Element *stack =...
    push (stack)
    void push( Element *stack, void *data ) {
      stack = ... // this changes the local pointer allocated on the function's stack
    }
    //call returns
    stack //still points to old memory
    

    然而,第二个版本将一个指针传递给堆栈指针,因此当它更改时,它会更改调用函数中的堆栈指针。

    【讨论】:

      【解决方案2】:

      在 C 中,一切都是按值传递的,假设我有这个函数:

      void foo(void* ptr)
      {
          ptr=NULL;
      }
      

      如果你在main中调用这个方法,你传递的指针不会是NULL(除非它已经是NULL)。因为在传递给函数之前会复制指针。所以如果你想修改它的值,你必须传递一个双指针:

      void foo(void** ptr)
      {
          *ptr=NULL;
      }
      

      同样适用于要修改值的堆栈。

      【讨论】:

        【解决方案3】:

        有了单指针签名,你可以想象使用如下代码

        Element *myStack = NULL ;
        
        .... bla bla bla ....
        
        push(myStack, something);
        

        然后在 push 调用中,您将告诉堆栈实现 old 堆栈的头元素在哪里,但是 push 的实现无法告诉您在哪里新头是。它无法更改您的 myStack 变量,因为在 C 中传递的参数始终是按值传递的——即,push 函数被告知 myStack 的 value 恰好是什么,但没有有机会改变调用者的变量。

        为了使事情正常工作,您需要告诉推送原语它需要更改的局部变量的地址:

        ....
        push(&myStack, something);
        

        由于myStack 本身具有Element * 类型,一个指向myStack 变量的指针具有Element ** 类型。

        【讨论】:

          【解决方案4】:

          类似于C语言中著名的swap()函数。

          案例一:

          void swapFails(int x, int y) {
              int temp = x;
              x = y;
              y = temp;
          }
          

          案例 2:

          void swapOk(int *x, int *y) {
              int temp = *x;
              *x = *y;
              *y = temp;
          }
          

          我们像这样调用交换:

          int x = 10;
          int y = 20;
          

          案例一:

          swapFails(x, y);
          

          案例 2:

          swapOk(&x, &y);
          

          请记住,我们想要更改 x 和 y 的值。为了改变数据类型的值,我们需要指针。将此提升到一个新的水平以获得指针。为了改变指针的值,我们需要双指针。

          对于使用链表的堆栈: 如果您推送值 10、20 和 30,它们的存储方式如下:

          top --- bottom
          30 -> 20 -> 10
          

          因此,您每次从堆栈(链表)推送或弹出值时,都会看到链表的顶部或第一个节点发生变化。因此你需要双指针。

          【讨论】:

            猜你喜欢
            • 2012-09-30
            • 2017-12-23
            • 1970-01-01
            • 2014-12-18
            • 2017-03-01
            • 2012-10-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多