【问题标题】:Should the stack pointer point to the value on the top, or the the position where the next value should be?堆栈指针应该指向顶部的值,还是下一个值应该在的位置?
【发布时间】:2023-03-09 14:53:02
【问题描述】:

以这个函数为例:

#include <stdlib.h>

#define MAX 100
typedef struct stack {
int sp;
int val [MAX];
} STACK;


void initStack (STACK *s){
    s->sp = 0;
}

int push (STACK *s, int x){
    if(s->sp == MAX) return -1;
    else s->val[s->sp++] = x;
    return 0;
}

int main(){
    STACK s;
    int pushval, p;

    initStack(&s);

    p = push(&s, 1);
    pushval = s.val[s.sp-1];
    printf("pushval %d\n", pushval);

    return 0;
}

所以在这种情况下,如果我执行 s.val[s.sp],我就会胡言乱语。如果我这样做 s.val[s.sp-1] 我会得到我推入堆栈的值。我不知道堆栈指针是否应该指向“下一个可用空间”,即等于数组中的元素数应该等于数组最后一个元素的索引,也就是 数组中的元素数 - 1

【问题讨论】:

  • 你可以做你喜欢的,但你也需要一个空栈的表示。使用您当前的代码,将sp 设置为0 表示一个空堆栈。如果sp 索引堆栈中的顶部元素,则需要通过将sp 设置为-1 来表示空堆栈。

标签: c arrays pointers stack


【解决方案1】:

这只是一个约定俗成的问题。许多实现让顶部堆栈指针指向“下一个可用空间”,但您可以真正做您喜欢的事情,前提是您的堆栈在外部表现得像预期的那样。

【讨论】:

  • 后递增堆栈指针有一个优点:堆栈的第一个元素可以在不调用 C 中未定义的行为的情况下使用。
  • @EOF 你是什么意思? int isEmpty() { return sp==-1; }int pop(){ return s[sp--];}void push(int i) { s[++sp]=i; } 没有 UB...
  • 是的,这行得通。虽然这不是一个堆栈-指针。如果你有一个实际的 pointer 你递增/递减,你不能使用预先递增的堆栈并使用第一个元素。
  • 好的,现在我理解了您的评论(表示堆栈指针的指针),那么您的评论(当然)是正确的。原谅我。
【解决方案2】:

对我来说,基于数组的堆栈最自然的实现是“向下”增长,堆栈指针指向最近推送的元素:

void initStack (STACK *s)
{
    s->sp = MAX;
}

int push (STACK *s, int x)
{
  if( !s->sp ) 
    return 0;               
  else                      
    s->val[--s->sp] = x;    
  return 1;                 
}    

int pop(STACK *s, int *x)
{
  if ( s->sp == MAX )
    return 0;
  else
    *x = s->val[s->sp++];
  return 1;
}

IMO 检查更简单,并且由于它从不低于 0,因此您可以安全地使用无符号类型作为堆栈指针(我倾向于这样做,原因可能并不完全合理)。

请注意,这模仿了 x86(和许多其他架构的)堆栈行为,因为 SP“向下”增长,朝向 0。

请注意,我更改了成功和失败的返回值,因为在 C 中 0 表示“假”,非零表示“真”。这样你就可以编写类似的代码

if ( push( stack, val ) )
{
  ...
}
else
{
  // push failed, handle as appropriate
}

同样,这只是 IMO 更自然的实现。

编辑

这种方法的一个大缺点是,如果需要,很难增加堆栈。如果您动态分配后备数组,您可以使用realloc 来扩展它,但是您必须将所有现有数据移动到新堆栈的“底部”,这将是昂贵且令人头疼的。相比之下,如果你向上增长堆栈,你就不会有这个问题。但是,如果我想要一个可以根据需要增长或缩小的堆栈,我不会使用基于数组的堆栈,我会使用基于链表的堆栈,其中项目通过将它们添加到列表的头部来推送并通过将它们从头部移除而弹出。

【讨论】:

  • 将“推入堆栈”的整个概念表明它是向上增长的。仅用高级语言来表示这一点并不是一个荒谬的概念——当然,这完全是另一回事。
  • @RichieHH:这完全是任意的。重要的是我们正确地实现了堆栈的 LIFO 行为——它在底层是什么样子并不重要。想象一个基于链表的堆栈,我们通过将节点添加到链表头来进行推送,并通过从链表头中删除节点来弹出。在那种情况下,“向上”和“向下”的概念是没有意义的
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-10-17
  • 2014-12-09
  • 1970-01-01
  • 2014-08-13
  • 1970-01-01
  • 1970-01-01
  • 2011-03-14
相关资源
最近更新 更多