推送功能C语言中堆栈中的分段错误

问题描述 投票:-1回答:1

当我启动程序时,我遇到了问题,它在功能完全崩溃并推送第70和78行(Linux)。我试着解决它,但我总是在同一个地方崩溃。

   #include <stdio.h>
   #define SIZE 64

   struct stack{
      int TowerTop;
      int Elem[SIZE];
   };

   /* Forward Declarations */                    
   void push(int Elem, struct stack *x);
   int  create (struct stack *x);
   int  full(const struct stack *x);
   void pop(struct stack *x);
   int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a);

   void main() {
      int j;
      int a = 5; 

      //scanf("%d",&a);

      struct stack Tower1;
      struct stack Tower2;
      struct stack Tower3;

      create(&Tower1);
      create(&Tower2);
      create(&Tower3);

      for(int i=0; i<=SIZE-1; i++) {
          Tower1.Elem[i]=0;
          Tower2.Elem[i]=0;
          Tower3.Elem[i]=0; 
      }

      for(int i=0; i<=a; i++){
          Tower1.Elem[i]=i+1;
      }

      // Display initial tower setup
      for(int i=0; i<a; i++){
         printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
      }

      lolol(&Tower1,&Tower2,&Tower3,a);

      // Display Tower after move made by lolol
      printf("%d\n", j);
      for(int i=0; i<a; i++) {
         printf("%d %7d %7d\n",Tower1.Elem[i],Tower2.Elem[i],Tower3.Elem[i]);
      }
    }

    int lolol(struct stack *x,struct stack *x2,struct stack *x3,int a) {
       if(a == 1) {
          printf("\n Disk 1 move to");
          push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
          pop(x->Elem[x->TowerTop]);
          return 0; 
       }

       lolol(x, x3, x2, a-1);
       push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]); j++;
       pop(x->Elem[x->TowerTop]);
       lolol(x3, x2, x, a-1);
      }

      int create(struct stack *x) {
         x->TowerTop = -1;
      }

      int full(const struct stack *x) {
          if (x->TowerTop == SIZE-1) {
             return 1;
          } else {
             return 0;
          } 
       }

       void push(int Elem, struct stack *x){
          if(full(x)) {
             printf("Stack is full"); 
          } else {
             x->TowerTop++;
             x->Elem[x->TowerTop]=Elem;
          }
       }

       void pop( struct stack *x) {
          if(x->TowerTop== -1) {
             printf("Empty");
          } else {
             x->TowerTop--;
          }
       }
c linux stack sigsegv towers-of-hanoi
1个回答
2
投票

我们将一起调试你的代码。但首先,我会告诉你如何在论坛上提问(因此在StackOverflow上)。

首先,没有“尽可能快”,因为我们都在这里帮忙。我们会尽力而为,它可能会或可能不会准时。然后请用您的代码再次阅读您的消息并问自己,这是否可读?我真的希望你的代码在你的文件中看起来不一样,你只是以某种方式复制/粘贴失败,因为这段代码是完全不可读的。

First step: Change the code to make it readable.

我将跳过这一步的冗长,但基本上它是缩进,在需要时添加空格等。

#include <stdio.h>

#define SIZE 64

struct stack
{
  int TowerTop;
  int Elem[SIZE];
};

void push(int Elem, struct stack *x);
void pop(struct stack *x);
int create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);

int a;
int j;

void main()
{

  //scanf("%d", &a);
  a = 5;
  struct stack Tower1;
  struct stack Tower2;
  struct stack Tower3;
  create(&Tower1);
  create(&Tower2);
  create(&Tower3);

  for (int i = 0; i <= SIZE - 1; i++)
    {
      Tower1.Elem[i] = 0;
      Tower2.Elem[i] = 0;
      Tower3.Elem[i] = 0;
    }

  for (int i = 0; i <= a; i++)
    {
      Tower1.Elem[i] = i + 1;
    }

  for (int i = 0; i < a; i++)
    {
      printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
    }

   lolol(&Tower1, &Tower2, &Tower3, a);

   printf("%d\n", j);

   for (int i = 0; i < a; i++)
    {
      printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
    }
}

int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
  if (a == 1)
    {
      printf("\n Disk 1 move to");
      push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
      j++;
      pop(x->Elem[x->TowerTop]);
      return 0;
    }
  lolol(x, x3, x2, a - 1);
  push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);
  j++;
  pop(x->Elem[x->TowerTop]);
  lolol(x3, x2, x, a - 1);
}

int create(struct stack *x)
{
  x->TowerTop = -1;
}

int full(const struct stack *x)
{
  if (x->TowerTop == SIZE-1)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}

void push(int Elem, struct stack *x)
{
  if (full(x))
    {
      printf("Stack is full");
    }
  else
    {
      x->TowerTop++;
      x->Elem[x->TowerTop] = Elem;
    }
}

void pop(struct stack *x)
{
  if (x->TowerTop == -1)
    {
      printf("Empty");
    }
  else
    {
      x->TowerTop--;
    }
}

请注意,我没有改变任何逻辑或类型或其他任何东西。

Second step: reading code.

实际上我可能会在稍后回到这里,但我快速阅读了一些基本的东西需要说。 main函数应始终返回int。根据C标准,您只能通过两种方式声明main函数:int main(void)(不带参数)或int main(int argc, char *argv[]);(带命令行参数)。

然后,你必须知道两个变量aj是文件的全局变量。这意味着您可以在同一源文件中的任何位置访问它们。听起来不错,不行。你永远不应该做全局变量,除非你没有其他选择(例如使用sigaction)。在你的情况下,他们真的不需要。

最后,评论。请推荐您的代码。虽然这里的大部分内容都很容易理解,但是功能lolol(这个名字在btw中没有意义)在快速查看代码时正在做一些我不明白的事情。

Third step: compiling

gcc file.c => 4警告。除非你知道自己在做什么,并且是一位经验丰富的C程序员 - 你还不是(还是!),编译时不应该有任何警告。此外,您应该使用-Wall -Wextra开关进行编译。这将引发更多警告,但允许您在它们存在之前捕获错误。

所以我们将修复警告:

  • warning: return type of ‘main’ is not ‘int’ [-Wmain]。好吧,让我们改变它。正如我先前所说,void main()成为int main(void)
  • file.c:64:34: warning: passing argument 2 of ‘push’ makes pointer from integer without a cast [-Wint-conversion] =>好吧,在这里你使用push函数,我假设你写了。但是,当你传递int时,这个函数需要一个struct stack *作为它的第一个参数和一个int作为它的第二个参数。让我们解决这个问题:push(x->Elem[x->TowerTop], x2->Elem[x2->TowerTop]);成为push(x->Elem[x->TowerTop], x2);,因为你在x->Elem[x->TowerTop]堆栈的顶部推动x2
  • 接下来的三个警告也是如此,即pop线66,push线70和pop线72。
  • 接下来两个警告是相同的:file.c:74:1: warning: control reaches end of non-void function [-Wreturn-type] =>我仍然不确定lolol是做什么的,所以我只是在它的末尾添加一个return 0,并将create函数切换到void类型。

这是更正后的代码:

#include <stdio.h>

#define SIZE 64

struct stack
{
  int TowerTop;
  int Elem[SIZE];
};

void push(int Elem, struct stack *x);
void pop(struct stack *x);
void create (struct stack *x);
int full(const struct stack *x);
int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a);

int a;
int j;

int main(void)
{

  //scanf("%d", &a);
  a = 5;
  struct stack Tower1;
  struct stack Tower2;
  struct stack Tower3;
  create(&Tower1);
  create(&Tower2);
  create(&Tower3);

  for (int i = 0; i <= SIZE - 1; i++)
    {
      Tower1.Elem[i] = 0;
      Tower2.Elem[i] = 0;
      Tower3.Elem[i] = 0;
    }

  for (int i = 0; i <= a; i++)
    {
      Tower1.Elem[i] = i + 1;
    }

  for (int i = 0; i < a; i++)
    {
      printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
    }

   lolol(&Tower1, &Tower2, &Tower3, a);

   printf("%d\n", j);

   for (int i = 0; i < a; i++)
    {
      printf("%d %7d %7d\n", Tower1.Elem[i], Tower2.Elem[i], Tower3.Elem[i]);
    }
}

int lolol(struct stack *x, struct stack *x2, struct stack *x3, int a)
{
  if (a == 1)
    {
      printf("\n Disk 1 move to");
      push(x->Elem[x->TowerTop], x2);
      j++;
      pop(x);
      return 0;
    }
  lolol(x, x3, x2, a - 1);
  push(x->Elem[x->TowerTop], x2);
  j++;
  pop(x);
  lolol(x3, x2, x, a - 1);
  return 0;
}

void create(struct stack *x)
{
  x->TowerTop = -1;
}

int full(const struct stack *x)
{
  if (x->TowerTop == SIZE-1)
    {
      return 1;
    }
  else
    {
      return 0;
    }
}

void push(int Elem, struct stack *x)
{
  if (full(x))
    {
      printf("Stack is full");
    }
  else
    {
      x->TowerTop++;
      x->Elem[x->TowerTop] = Elem;
    }
}

void pop(struct stack *x)
{
  if (x->TowerTop == -1)
    {
      printf("Empty");
    }
  else
    {
      x->TowerTop--;
    }
}

在没有SIGSEGV的情况下编译和运行。

Last step: Going further

我将谈论更高级的主题,但它可能对您有用。首先,获取有关堆栈及其工作原理的更多信息,因为我不确定您是否完全理解它。

此外,要调试您的程序,您可以使用valgrind,它是一个非常有用的内存检查工具,总是派上用场。要使用它,请在编译时添加标志-g

我建议也查看gdb,GNU Linux调试器。很强大。

功能full可以改为简单的return x->TowerTop == SIZE - 1。它避免了分支,因此运行得更快。

这就是所有人。仍然不确定您的代码应该做什么,但您只询问如何修复您的段错误。现在请记住。编译时不要发出任何警告。

谢谢。

© www.soinside.com 2019 - 2024. All rights reserved.