ST程序中的STACK。弹出操作不起作用

时间:2015-04-27 14:28:10

标签: c stack

这个程序有什么问题。我遇到pop操作问题,即使堆栈为空,它也会显示一个额外的值。 ??

void initstack (struct stack * p, int maxSize) 

void push (struct stack * p, int item) 

int pop (struct stack * p) 

void display (struct stack p) 

 struct stack

{

   int * a;

   int top;

   int maxSize;

};

注意:使用d以上的结构和功能是强制性的。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
struct stack {
    int * a;
    int top;
    int maxSize;
};
void initstack(struct stack * p, int maxSize);
void push(struct stack * p, int item);
int pop(struct stack * p);
void display(struct stack p);
int StackIsEmpty(struct stack * p);
int StackIsFull(struct stack * p);
void printMenu();

int main()  {
    struct stack p;
    int data,ch, data1, m;
    printf("Enter the maximum size of the stack\n");
    scanf("%d",&m);
    initstack(&p,m);
    do {
    printMenu();    
    printf("Enter your choice\n");
    scanf("%d",&ch);
    switch(ch) {
      case 1:
        printf("Enter the element to be pushed\n");
        scanf("%d",&data);
        push(&p, data);
        break;
      case 2:
        data1 = pop(&p);
        if(data1 != -1000)
        printf("The popped element is %d\n",data1);
        break;
      case 3:
        printf("The contents of the stack are");
        display(p);
        printf("\n");
        break;
      default:
        exit(0);
    }
    } while(1);
    return 0;
}

void printMenu()
{
    printf("Choice 1 : Push\n");
    printf("Choice 2 : Pop\n");
    printf("Choice 3 : Display\n");
    printf("Any other choice : Exit\n");
}

void initstack(struct stack * p, int maxSize) {
    int *newContents;
  newContents=(int *)malloc(sizeof(int)*maxSize);
  p->a=newContents;
  p->maxSize=maxSize;
  p->top=-1; 
}

void push(struct stack * p, int item) {
    if(StackIsFull(p))
    {
      printf("Stack is full\n");
    }
  p->a[++p->top]=item;
}

void display(struct stack p) {
  int i;
  struct stack *b=&p;
  if(StackIsEmpty(b))
    printf(" {}");
  for(i=0;i<b->top;i++)
  {
    printf(" %d",b->a[i]);
  }
}

int pop(struct stack * p) {
    if(StackIsEmpty(p))
    {
      printf("Stack is empty\n");
      return -1000;
    }
  else
    return p->a[--p->top];
}

int StackIsEmpty(struct stack *p)
{
  return p->top == -1;          //p->top==-1;
}

int StackIsFull(struct stack *p)
{
  return p->top >= p->maxSize-1;
}

5 个答案:

答案 0 :(得分:1)

让我们来看看你的推送和弹出操作:

p->a[++p->top]=item; // push
p->a[--p->top];      // pop

假设堆栈为空,top为-1。当您执行推送时,将top增加到0并将您的元素写入p->a[0]。当您弹出该元素时,首先将top减少回-1,然后尝试访问元素p->a[-1]

这是一个问题。您不仅会弹出错误的元素,还要访问数组范围之外的元素并调用未定义的行为。

您需要在之后更改堆栈指针,以便访问所需的元素,如下所示:

p->a[++p->top] = item; // push
item = p->a[p->top--]; // pop

对于基于数组的堆栈,它实际上更有利于堆栈增长&#34;向下&#34;,如下所示:

p->top = p->maxSize = maxSize; // init

if ( p->top )            // p->top != 0 means room left on the stack
  p->a[--p->top] = item; // push

if ( p->top < p->maxSize ) // p->top < p->maxSize means elements left on stack 
  return p->a[p->top++];   // pop

这样,您就不会冒着访问数组范围之外的元素的风险。 p->top将始终介于0和maxSize之间 - 1.

最后,一个风格笔记:

你不需要投射malloc的结果;它只会增加视觉混乱,并且在某些情况下可以抑制有用的诊断。你只需写下来就可以清理它:

 /**
  * Whitespace is your friend.  Use it.
  */
 newContents = malloc( sizeof *newContents * maxSize );

sizeof *newContentssizeof (int)相同;这样,如果您决定更改堆栈数组的类型,则不必担心更改malloc调用本身。节省一些维护麻烦,读取更容易一些。

修改

这是导致您头痛的部分原因:

void push(struct stack * p, int item) {
    if(StackIsFull(p))
    {
      printf("Stack is full\n");
    }
    p->a[++p->top]=item; // DANGER WILL ROBINSON!
}

如果堆栈已满,则打印警告,然后按推送元素。

你需要一个else分支

void push(struct stack * p, int item) 
{
  if(StackIsFull(p))
  {
    printf("Stack is full\n");
  }
  else
  {
    p->a[++p->top]=item;
  }
}

答案 1 :(得分:1)

谢谢大家,我修好了......工作正常。谢谢你的所有建议。

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
struct stack {
    int * a;
    int top;
    int maxSize;
};
void initstack(struct stack * p, int maxSize);
void push(struct stack * p, int item);
int pop(struct stack * p);
void display(struct stack p);
int StackIsEmpty(struct stack * p);
int StackIsFull(struct stack * p);
void printMenu();

int main()  {
    struct stack p;
    int data,ch, data1, m;
    printf("Enter the maximum size of the stack\n");
    scanf("%d",&m);
    initstack(&p,m);
    do {
    printMenu();    
    printf("Enter your choice\n");
    scanf("%d",&ch);
    switch(ch) {
      case 1:
        printf("Enter the element to be pushed\n");
        scanf("%d",&data);
        push(&p, data);
        break;
      case 2:
        data1 = pop(&p);
        if(data1 != -1000)
        printf("The popped element is %d\n",data1);
        break;
      case 3:
        printf("The contents of the stack are");
        display(p);
        printf("\n");
        break;
      default:
        exit(0);
    }
    } while(1);
    return 0;
}

void printMenu()
{
    printf("Choice 1 : Push\n");
    printf("Choice 2 : Pop\n");
    printf("Choice 3 : Display\n");
    printf("Any other choice : Exit\n");
}

void initstack(struct stack * p, int maxSize) {
    int *newContents;
  newContents=malloc(sizeof(int)*maxSize);
  p->a=newContents;
  p->maxSize=maxSize;
  p->top=-1; 
}

void push(struct stack * p, int item) {
    if(StackIsFull(p))
    {
      printf("Stack is full\n");
    }
    else
    {
    p->a[++p->top]=item;  //FIXED LINE, ELSE BLOCK ADDED
    }
}

void display(struct stack p) {
  int i;
  struct stack *b=&p;
  if(StackIsEmpty(b))
    printf(" {}");
  for(i=0;i<=b->top;i++)   //FIXED PREVIOUSLY for(i=0;i<b->top;i++)
  {
    printf(" %d",b->a[i]);
  }
}

int pop(struct stack * p) {
    if(StackIsEmpty(p))
    {
      printf("Stack is empty\n");
      return -1000;
    }
  else
    return p->a[p->top--];     //FIXED PREVIOUSLY p->a[--p->top];
}

int StackIsEmpty(struct stack *p)
{
  return p->top < 0;          //FIXED PREVIOUSLY p->top==-1;
}

int StackIsFull(struct stack *p)
{
  return p->top >= p->maxSize-1;
}

答案 2 :(得分:0)

您的显示逻辑有问题。它有一个off-by-one错误并跳过最顶层的元素。

答案 3 :(得分:0)

int result =  p->a[p->top];

在这部分我认为你应该先

p->top --;
return result;

然后

@Override
public boolean onInterceptTouchEvent (MotionEvent ev) {
    getMaxLeftScroll();
    myLastX = ev.getX();
    myLastY = ev.getY();
    return super.onInterceptTouchEvent(ev);
}


@Override
public boolean onTouchEvent(final MotionEvent ev){

    final int action = ev.getAction();
    final float x;
    final float y;

    switch (action) {
        case MotionEvent.ACTION_MOVE:
            // This handles Scrolling only.
            x = ev.getX();
            y = ev.getY();

            final int deltaX = (int) (myLastX - x);
            final int deltaY = (int) (myLastY - y);

            if(Math.abs(deltaX) > Math.abs(deltaY)) {

                if( (iCurrentLeftScroll+deltaX) > 0 &&
                        iCurrentLeftScroll+deltaX < iMaxLeftScroll) {
                    scrollBy(deltaX, 0);
                    //Listener and call the method here to scroll the header
                    mScrollChangeListener.onGridViewScrolled(deltaX);

                    iCurrentLeftScroll+=deltaX;
                }  //Scrolled by some value

                // Close to right edge within 10? Smooth Scroll remaining small distance if not already there
                else if(deltaX > 0 && (iCurrentLeftScroll<iMaxLeftScroll)) {
                    if ((iMaxLeftScroll - iCurrentLeftScroll) < 10) {
                        scrollBy(iMaxLeftScroll-iCurrentLeftScroll, 0);
                        mScrollChangeListener.onGridViewScrolled(iMaxLeftScroll-iCurrentLeftScroll);
                        iCurrentLeftScroll = iMaxLeftScroll;
                    }
                }
                // Close to left edge within 30? Smooth Scroll remaining small distance if not already there
                else if(deltaX < 0 && (iCurrentLeftScroll>0)) {
                    if ((iCurrentLeftScroll) < 10) {
                        scrollBy(iCurrentLeftScroll*-1, 0);
                        mScrollChangeListener.onGridViewScrolled(iCurrentLeftScroll*-1);
                        iCurrentLeftScroll = 0;
                    }
                }

                //left and right are subjective
                if(iCurrentLeftScroll == iMaxLeftScroll)
                    iScrollStatus = SCROLLED_FULL_LEFT;
                if(iCurrentLeftScroll == 0)
                    iScrollStatus = SCROLLED_FULL_RIGHT;
                if( (iCurrentLeftScroll > 0) && (iCurrentLeftScroll < iMaxLeftScroll) )
                    iScrollStatus = 0;
                Log.d(TAG," Scroll Status " + String.valueOf(iScrollStatus) );
                Log.d(TAG," MaxLeftScroll " + String.valueOf(iMaxLeftScroll) );
                Log.d(TAG," Current Left Scroll " + String.valueOf(iCurrentLeftScroll) );

            }

            myLastX = x;
            myLastY = y;

            break;
    }
    return super.onTouchEvent(ev);
}

我有同样的问题,这帮助了我。

答案 4 :(得分:0)

这个问题与推送和弹出功能有关。两者都使用preincrements,因此您推送的最后一个项目不是您弹出的第一个项目。

您的push会:首先递增top,然后将值存储在a[top]中。所以top指向新推出的元素。

您的pop确实:首先递减top,然后检索a[top]处的值。检索到的值不会是最后一次推送,而是前一次推送。 top始终指向同一个值。

我的建议:按原样保留push,然后更改pop

int pop(struct stack * p) {
    if(StackIsEmpty(p))
    {
      printf("Stack is empty\n");
      return -1000;
    }
  else
    return p->a[p->top--]; /* post-increment!! */
}

因此,push将使顶部指向最后推送的值。 pop将检索此值,然后递减top,使其指向要检索的下一个值。