这个程序在倒车堆栈上出了什么问题?

时间:2018-03-28 00:30:34

标签: c stack

我在c中制作了这个程序来反向堆栈。但它崩溃了。请帮我弄清楚出了什么问题。该计划工作正常,直到接受投入。但是当调用反向时它会崩溃。我无法找到错误。所有内存都正确分配。所以我不认为有分段错误。

#include<stdio.h>
#include<stdlib.h>
typedef struct Node{
    int data;
    struct Node *next, *prev;
}SNode;

typedef struct{
     SNode *top;
     int count;
 }Stack;

 int isEmpty(Stack *s){
     return (s->count==0);
  }
 void push(Stack *s,int x){
        SNode *temp = (SNode *)malloc(sizeof(SNode));
        temp->next = s->top;
        temp->prev = NULL;
        s->top->prev = temp;
        temp->data = x;
        s->top = temp;
        s->count++;
   }

   int pop(Stack *s){
     if(isEmpty(s)){
     printf("Underflow");
      return;
    }
   SNode *temp = s->top;
   s->top = s->top->next;
   s->top->prev = NULL;
   int a = temp->data;
   free(temp);
   s->count--;
   return a;
   }

   void reverse(Stack *s,Stack *rs){
      while(!isEmpty(s)){
      int p = pop(s);
      push(rs,p);
    }
   }

   int main(){
       Stack *s = (Stack *)malloc(sizeof(Stack));
       Stack *rs = (Stack *)malloc(sizeof(Stack));
       char p='y';
       while(p=='y'){
           int pu;
           printf("Enter data to be pushed: ");
           scanf(" %d",&pu);
           push(s,pu);
           printf("Do you want to push another number? y/n:");
           scanf(" %c",&p);
         }
        reverse(s,rs);
        printf("Top of reversed stack: %d",rs->top->data);
        return 0;
        }

我不知道我改变了什么。我重写了代码,这次使用单链表,现在它工作得很好。不知道怎么样!! ??

#include<stdio.h>
#include<stdlib.h>
typedef struct node{
 int data;
 struct node *next;
}SNode;

typedef struct{
 int count;
 SNode *top;
}stack;

int isEmpty(stack *s){
 return (s->count==0);
}

void push(stack *s,int x){
 SNode *temp = (SNode *)malloc(sizeof(SNode));
 temp->data = x;
 temp->next = s->top;
 s->top=temp;
 s->count++;
}

int pop(stack *s){
    if(isEmpty(s)){
        printf("Underflow");
        return -1;
    }
 SNode *temp = s->top;
 s->top = temp->next;
 int a = temp->data;
 free(temp);
 s->count--;
 return a;
}

void reverseStack(stack *s, stack *rs){
 while(!isEmpty(s)){
    push(rs,pop(s));
 }
}

int main(){
 stack *s = (stack *)malloc(sizeof(stack));
 stack *rs = (stack *)malloc(sizeof(stack));
 s->count = rs->count =0;
 char p ='y';
 while(p=='y'){
    int x;
    printf("Enter data to push: ");
    scanf("%d",&x);
    push(s,x);
    printf("Do you want to push more data? : y/n");
    scanf(" %c",&p);
 }
 reverseStack(s,rs);
 printf("Top of reversed stack: %d",rs->top->data);
 return 0;
}

4 个答案:

答案 0 :(得分:0)

malloc不会将struct成员初始化为零和NULL。你必须自己做或者使用calloc。因此,将程序中的malloc行更改为以下内容:

Stack *s = calloc(1, sizeof(Stack));
Stack *rs = calloc(1, sizeof(Stack));

答案 1 :(得分:0)

我至少看到两个问题。

当您malloc()新的Stack结构时,您不会初始化*topcount字段,而且其内容可能是垃圾。< / p>

pop()

SNode *temp = s->top;
s->top = s->top->next;
s->top->prev = NULL;

如果s->top->next的初始值为NULL,会发生什么?

答案 2 :(得分:0)

您的堆栈实现中存在许多问题。当你打电话时,第一个是push()

temp->next = s->top;

s->top是一个未初始化的指针,其值是不确定的。这会调用未定义的行为。由于这是在您第一次调用push(s, pu)时发生的,因此您对其余代码的操作没有信心。

接下来,pushpop函数都无法以适当的方式测试和处理被推送或弹出的节点是否是堆栈中的第一个或最后一个节点。这些必须以不同方式处理,因为prevnext指针的处理将取决于是否存在其他节点。 (如果您要推送第一个节点,则无法分配nextprev节点,并且无法在top上分配新的pop如果不存在更多节点。

注意:您似乎也使用了prevnext。但只要您使用它们一致,它就不会是否对prevtop上的现有push使用next。我倾向于prev指向堆栈并next指向从下往上 - 但你可以自由地做另一种方式)

要正确处理堆栈中的第一个和最后一个节点,您可以对isempty()进行简单检查,或只需检查if (s->top == NULL)if (s->count == 0)

在为堆栈和节点分配存储空间时,还需要初始化所有指针和count。未能在分配时初始化所有值可能会导致无意中尝试从未初始化的值读取(调用未定义行为的其他实例)。

为了消除这种可能性,您可以创建简单的辅助函数,比如create_nodecreate_stack来分配,验证分配,初始化所需的值,然后提供有意义的返回,表明成功或失败。你可以做一些简单的事情,如下所示:

snode *create_node (int x)
{
    snode *tmp = malloc (sizeof *tmp);
    if (!tmp) {
        perror ("create_node: memory exhausted.");
        return NULL;
    }
    tmp->data = x;
    tmp->prev = tmp->next = NULL;

    return tmp;
}

stack *create_stack (void)
{
    stack *tmp = malloc (sizeof *tmp);
    if (!tmp) {
        perror ("create_stack: memory exhausted.");
        return NULL;
    }
    tmp->top = NULL;
    tmp->count = 0;

    return tmp;
}

现在没有未初始化价值的可能性。

(另请注意:虽然不是错误,但C的标准编码样式避免使用camelCaseMixedCase变量名来支持所有小写保留大写名称以用于宏和常量。这是一个风格问题 - 所以它完全取决于你,但没有遵循它可能会导致在某些圈子中错误的第一印象。)

定义了辅助函数后,在main()中分配和初始化正向和反向堆栈变得非常简单:

    int pu;
    stack *s = create_stack();
    stack *rs = create_stack();

    if (!s || !rs)      /* validate the return from create_stack */
        return 1;

创建了前向和反向堆栈之后,您可以在push()pop()中处理第一个和最后一个节点的情况,并添加一个简单的条件,如上所述:

void push (stack * s, int x)
{
    snode *temp = create_node (x);
    if (!s->top)             /* is the stack empty? */
        s->top = temp;
    else {
        s->top->next = temp;
        temp->prev = s->top;
        s->top = temp;
    }
    s->count++;
}

pop()

int pop (stack *s)
{
    int x;
    snode *temp;
    if (isempty (s)) {      /* checking empty as you did in original */
        printf ("underflow");
        return 0;
    }
    x = s->top->data;

    temp = s->top;
    if (s->top->prev)
        s->top = s->top->prev;
    s->top->next = NULL;
    free (temp);

    s->count--;
    return x;
}

添加一个简短的prn_stack()函数来迭代堆栈,而不需要pop释放节点,你可以组合一个简短的示例程序来测试push,{{1} }和pop如下:

reverse

注意:不要忘记#include <stdio.h> #include <stdlib.h> typedef struct node { int data; struct node *next, *prev; } snode; typedef struct { snode *top; int count; } stack; snode *create_node (int x) { snode *tmp = malloc (sizeof *tmp); if (!tmp) { perror ("create_node: memory exhausted."); return NULL; } tmp->data = x; tmp->prev = tmp->next = NULL; return tmp; } stack *create_stack (void) { stack *tmp = malloc (sizeof *tmp); if (!tmp) { perror ("create_stack: memory exhausted."); return NULL; } tmp->top = NULL; tmp->count = 0; return tmp; } int isempty (stack *s) { return (s->count == 0); } void prn_stack (stack *s) { snode *iter; if (isempty(s)) { puts ("stack empty"); return; } iter = s->top; for (; iter; iter = iter->prev) printf (" %d\n", iter->data); } void push (stack * s, int x) { snode *temp = create_node (x); if (!s->top) s->top = temp; else { s->top->next = temp; temp->prev = s->top; s->top = temp; } s->count++; } int pop (stack *s) { int x; snode *temp; if (isempty (s)) { printf ("underflow"); return 0; } x = s->top->data; temp = s->top; if (s->top->prev) s->top = s->top->prev; s->top->next = NULL; free (temp); s->count--; return x; } void reverse (stack * s, stack * rs) { while (!isempty (s)) push (rs, pop (s)); } int main () { int pu; stack *s = create_stack(); stack *rs = create_stack(); if (!s || !rs) return 1; while (scanf (" %d", &pu) == 1) push (s, pu); printf ("stack:\n"); prn_stack (s); reverse (s, rs); printf ("\nreversed stack:\n"); while (!isempty (rs)) printf (" %d\n", pop (rs)); free (s); free (rs); return 0; } 在弹出所有值后为前向和反向堆栈分配的内存,并始终使用a来验证内存使用情况内存错误检查程序,如Linux上的free。所有操作系统都有类似的程序

示例使用/输出

valgrind

要验证您的内存使用情况并释放所有已分配的内存并且没有内存错误,只需通过内存检查程序运行代码,类似于以下使用$ echo "10 9 8 7 6 5 4 3 2 1" | ./bin/stack_rev stack: 1 2 3 4 5 6 7 8 9 10 reversed stack: 10 9 8 7 6 5 4 3 2 1 ,例如

内存使用/错误检查

valgrind

仔细看看,如果您有任何其他问题,请告诉我。

答案 3 :(得分:0)

您的代码随机崩溃,因为当您在main中首次声明时,s-&gt; count不为0。如果你很幸运,s-&gt; count是0,那么反向就好了,因为isEmpty()可以正常工作。否则,您将获得分段错误。