簡體   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