为什么这个while循环不终止?

huangapple go评论85阅读模式
英文:

Why does the while loop not terminate?

问题

这段代码是用栈操作来解决汉诺塔问题的,但输出不断地打印出来,导致无法终止。

你期望的条件是size(&z) < n-1,但是循环没有终止。

终端输出如下:

Enter number of disks: 3
*无法控制的输出*

建议你使用调试器来解决这个问题,但是由于你不熟悉如何使用调试器,这里无法提供具体的调试步骤。如果你需要帮助使用调试器,可以查找相关的教程或文档,或者提出具体的调试问题,我将尽力回答。

英文:

The code is written to solve the Towers of Hanoi using stack operations, but output gets printed into the indefinitely.

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAX_SIZE 100

struct stack{
int a[MAX_SIZE];
int top;
}x, y, z;

typedef struct stack stk;

void push(stk *s, char n)
{
  if(s->top == MAX_SIZE-1)
    printf("Stack Overflow\n");
  else
    s->a[++s->top] = n;
}

int pop(stk *s)
{
  if(s->top < 0)
  {
    printf("Stack Underflow\n");
    return -1;
  }
  else
  {
    return s->a[s->top--];
  }
}

int top(stk *s)
{
  if(s->top < 0)
  {
    return -1;
  }
  else
  {
    return s->a[s->top];
  }
}

int isEmptyStack(stk *s)
{
  if(s->top < 0)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

int isFullStack(stk *s)
{
  if(s->top == MAX_SIZE - 1)
  {
    return 1;
  }
  else
  {
    return 0;
  }
}

int size(stk *s)
{
  return s->top;
}

int main()
{
    x.top = -1;
    y.top = -1;
    z.top = -1;

    int n;
    printf("Enter number of disks: ");
    scanf("%d", &n);

    for(int i=0;i<n;i++)
    {
        push(&x, i+1);
    }

    if(n > 0)
    {
        while(size(&z) < n-1)
        {
            if(n % 2 != 0)
            {
                if(top(&x) > top(&z))
                {
                    push(&z, pop(&x));
                    printf("X to Z\n");
                }
                if(top(&z) > top(&x))
                {
                    push(&x, pop(&z));
                    printf("Z to X\n");
                }

                if(top(&x) > top(&y))
                {
                    push(&y, pop(&x));
                    printf("X to Y\n");
                }
                if(top(&y) > top(&x))
                {
                    push(&x, pop(&y));
                    printf("Z to X\n");
                }

                if(top(&y) > top(&z))
                {
                    push(&z, pop(&y));
                    printf("Y to Z\n");
                }
                if(top(&z) > top(&y))
                {
                    push(&y, pop(&z));
                    printf("Z to Y\n");
                }
            }

            else
            {
                if(top(&x) > top(&y))
                {
                    push(&y, pop(&x));
                    printf("X to Y\n");
                }
                if(top(&y) > top(&x))
                {
                    push(&x, pop(&y));
                    printf("Y to X\n");
                }

                if(top(&x) > top(&z))
                {
                    push(&z, pop(&x));
                    printf("X to Z\n");
                }
                if(top(&z) > top(&x))
                {
                    push(&x, pop(&z));
                    printf("Z to X\n");
                }

                if(top(&y) > top(&z))
                {
                    push(&z, pop(&y));
                    printf("Y to Z\n");
                }
                if(top(&z) > top(&y))
                {
                    push(&y, pop(&z));
                    printf("Z to Y\n");
                }   
            }
        }
    }

    return 0;
}

I was expecting the condition size(&z) < n-1 to become 0 which would terminate the loop, but the loop isn't terminating.

Terminal:

Enter number of disks: 3
*Out of control output*

It was suggested that I use a debugger, but I don't know how to, as I am only in the process of learning to use it.

答案1

得分: 0

无限循环意味着循环条件,即在这种情况下 size(&z) < n-1,将永远保持为真。由于右侧 (rhs) n-1 是固定的,n = 3,这意味着您期望 size(&z) 至少增加到 2,但它永远不会增加。从输出中我们看到一个重复的循环:

Z 到 X
X 到 Y
Z 到 X
X 到 Z
Z 到 X
...

这告诉我们我们将一个值推送到 z,然后立刻将其弹出,因此我们永远无法取得进展。

我建议您重新设计您的接口,以便您的错误域 (-1) 和值域不重叠。如果现在你 push(..., -1),你无法确定当 top(...) 返回 -1 时是错误还是刚好是你推送的最后一个值。pop() 有同样的问题,再次强调,调用者无法确定,但至少有一个错误消息。

在您的情况下,要么不允许推送 -1,要么让函数返回操作的状态,并通过传入的指针返回值(使用一个常量 OK 以提高可读性):

#define OK 0

int push(stk *s, char n) {
	if(s->top == MAX_SIZE-1) {
		printf("栈上溢\n");
        return !OK;
    }
    s->a[++s->top] = n;
    return OK;
}

int pop(stk *s, int *v) {
	if(s->top < 0) {
		printf("栈下溢\n");
		return !OK;
	}
    *v = s->a
展开收缩
;
return OK; }
英文:

An infinite loop means that the loop condition, in this case size(&z) < n-1, remains true forever. As the right hand side (rhs) n-1 is fixed with n = 3 this means you expect size(&z) to increment to at least 2 but it never does. From the output we see a repeating cycle:

Z to X
X to Y
Z to X
X to Z
Z to X
...

which tells us that we pushed a value to z and popped it right off again so we never make progress.

I suggest you rework your interface so your error domain (-1) and value domain doesn't overlap. If you push(..., -1) now you cannot tell when top(...) returns -1 if it's an error or of it just happens to be the last value you pushed. pop() has the same issue, and again, caller cannot tell but at least there is an error message.

In your case either disallow push of -1, or have functions return the status of the operation and return the value via a pointer you passed in (using a constant OK here to improve readability):

#define OK 0

int push(stk *s, char n) {
	if(s->top == MAX_SIZE-1) {
		printf("Stack Overflow\n");
        return !OK;
    }
    s->a[++s->top] = n;
    return OK;
}

int pop(stk *s, int *v) {
	if(s->top < 0) {
		printf("Stack Underflow\n");
		return !OK;
	}
    *v = s->a[s->top--];
    return OK;
}

huangapple
  • 本文由 发表于 2023年3月10日 01:14:48
  • 转载请务必保留本文链接:https://go.coder-hub.com/75687924.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定