繁体   English   中英

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

[英]Segmentation fault in stack in push Function C language

当我启动程序时,我遇到了问题,它在功能Full并按下第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--;
          }
       }

我们将一起调试您的代码。 但是首先,我将向您详细介绍如何在论坛上提问(因此请在StackOverflow上)。

首先,因为我们都在这里为您提供帮助,所以没有“尽快”的方法。 我们会尽力而为,可能会或可能不会准时。 然后,请使用您的代码再次阅读您的消息并问自己,这可读吗? 我确实希望您的代码在文件中看起来不一样,并且您以某种方式使复制/粘贴失败,因为该代码非常不可读。

第一步:更改代码以使其可读。

我将跳过此步骤的详细信息,但基本上是缩进,在需要时添加空格等。

#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--;
    }
}

请不要说我没有更改任何逻辑或类型或任何其他内容。

第二步:阅读代码。

实际上,我稍后可能会再讲到这一点,但是我快速阅读了一些基本的知识。 main函数应始终返回一个int 根据C标准,只能使用两种方式声明main函数: int main(void) (不带参数)或int main(int argc, char *argv[]); (采用命令行参数)。

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

最后,评论。 请赞扬您的代码。 虽然在这里可以轻松理解大多数内容,但是快速浏览一下代码时,函数lolol (该名称根本没有意义)正在执行我不理解的操作。

第三步:编译

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传递给它时,将int作为第一个参数,将struct stack *作为第二个参数。 让我们修复一下: 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即可编译和运行。

最后一步:进一步

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

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

我建议也研究GNU Linux调试器gdb 很强大。

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

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

谢谢。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM