【问题标题】:Linked stack in C. Pop causes segmentation fault, but Push does not!C 中的链接堆栈。 Pop 会导致分段错误,但 Push 不会!
【发布时间】:2010-07-08 17:36:27
【问题描述】:

我正在做一些简单的事情,所以希望这个问题可以很容易地得到回答。我正在使用 gcc 进行编译。推动工作非常好。问题是流行音乐。每当我编译和运行它时,我都会遇到分段错误。

这里是弹出和推送功能:

int push(stack *stk, int data)
{
    stk->head = makeNode(data, stk->head);
    stk->length += 1;
    return data;
}

int pop(stack *stk)
{
    //Returns popped item
    //Returns -1 if stack length is zero
    if (stk->length < 1)
    {
        printf("No items to pop.");
        return -1;
    }
    int data = stk->head->value;
    struct node *toBeFreed = stk->head;
    stk->head = stk->head->ptr;
    free(toBeFreed);
    stk->length -= 1;
    return data;
}

老实说,我不知道问题出在哪里,因为代码很相似。我在 push 函数中重新分配堆栈中的 head 变量,但它会导致 pop 函数中的错误。对数据的分配也给了我一个段错误。除了返回和堆栈长度赋值语句之外,几乎所有的东西都给了我分段错误。你们中的任何人都可以帮我解决这个问题吗?是什么导致了这些段错误?

这是整个程序:

#include <stdio.h>
#include <stdlib.h>
struct node 
{
    int value;
    struct node *ptr;
};

struct node *makeNode(int value, struct node *ptr)
{
    struct node *newNode = malloc(sizeof(struct node));
    newNode->value = value;
    newNode->ptr = ptr;
    return ptr;
}

typedef struct stack
{
    struct node *head;
    int length;
} stack;

stack makeStack()
{
    stack stk;
    stk.head=NULL;
    stk.length = 0;
    return stk;
}

int push(stack *stk, int data)
{
    stk->head = makeNode(data, stk->head);
    stk->length += 1;
    return data;
}

int pop(stack *stk)
{
    if (stk->length < 1)
    {
        printf("No items to pop.");
        return -1;
    }
    int data = stk->head->value;
    struct node *toBeFreed = stk->head;
    stk->head = stk->head->ptr;
    free(toBeFreed);
    stk->length -= 1;
    return data;
}

int main()
{
    stack s = makeStack();
    printf("Pushing ints one through five. Should display ints one through five on separate lines: \n");
    int i;
    for (i = 1; i <= 5; i++)
            printf("%d\n",push(&s, i));
    printf("Popping ten values. Should display ints one through five in reverse order on separate lines along with 5 error statements.\n");
    for (i = 0; i <= 10; i++)
            printf("%d\n",pop(&s));
    return 0;
}

【问题讨论】:

    标签: c


    【解决方案1】:
    struct node *makeNode(int value, struct node *ptr)
    {
        struct node *newNode = malloc(sizeof(struct node));
        newNode->value = value;
        newNode->ptr = ptr;
        return ptr;
    }
    

    您想返回newNode,而不是ptr

    你得到segfault的原因是由于makeNode中的错误堆栈将保持空,但是size将增加到5,所以当你pop时堆栈不知道它是空的并且它尝试取消引用空指针。

    【讨论】:

    • 非常感谢!这完全解决了一切!
    • @caf:在 makeStack 中,他没有返回任何东西的地址。他正在按值返回局部变量的内容,这是完全有效的。
    【解决方案2】:

    我建议您在poppush 中添加对NULL 指针的检查。 makeStack 函数让我不寒而栗,因为它返回的是一个局部变量。

    另外,我建议进行以下更改:

    struct stack * makeStack()
    {
        struct stack * p_stk = 0;
        p_stk = (struct stack *) malloc(sizeof(struct stack);
        if (p_stk)
        {
          p_stk->head=NULL;
          p_stk->length = 0;
        }
        return p_stk;
    }
    

    或者

    void makeStack(stuct stack * p_stack)
    {
     // Initialize the stack ...
    }
    

    【讨论】:

      【解决方案3】:

      sepp2k 已经给出了正确的答案。所以我只是添加一些有用的建议。

      一种可以帮助您在大型程序中发现此类问题的方法是一种名为 valgrind 的工具。例如,如果你编译:

      $ gcc -Wall -Wextra -g linked_stack.c -o linked_stack
      

      然后运行:

      $ valgrind ./linked_stack
      

      您将获得以下输出:

      ==1503== Invalid read of size 4
      ==1503==    at 0x80484C6: pop (linked_stack.c:62)
      ==1503==    by 0x8048584: main (linked_stack.c:79)
      ==1503==  Address 0x0 is not stack'd, malloc'd or (recently) free'd
      ==1503== 
      ==1503== Process terminating with default action of signal 11 (SIGSEGV)
      ==1503==  Access not within mapped region at address 0x0
      ==1503==    at 0x80484C6: pop (linked_stack.c:62)
      ==1503==    by 0x8048584: main (linked_stack.c:79)
      

      这有效地告诉你第 62 行的语句:

      int data = stk->head->value;
      

      正在尝试使用值为 0x0 的无效指针。到时候你只需要回溯,找出那个指针无效的原因。

      使用 -g 编译调试符号然后在 valgrind 下运行所提供的额外信息可以真正帮助您在大型程序中追踪此类问题。

      【讨论】:

        【解决方案4】:

        在 makeNode 中,您正在创建一个新节点,将该节点指向传入的值,然后返回 传入的值,而不是新节点。因为你传入了stk-&gt;head,它以NULL开头,每次推送都会创建一个指向NULL的新节点,然后返回NULL,所以stk-&gt;head不会像你期望的那样改变。当您弹出时,您正在尝试访问NULL-&gt;ptrNULL-&gt;value,这显然不起作用。

        如果你把makeNode改成:

        struct node *makeNode(int value, struct node *ptr)
        {
            struct node *newNode = malloc(sizeof(struct node));
            newNode->value = value;
            newNode->ptr = ptr;
            return newNode; // pass back the new node
        }
        

        它会起作用的。

        【讨论】:

          【解决方案5】:

          当您调用函数makeNode 时,您的头指针不会改变。 您必须将 head 指向新创建的节点。

          【讨论】:

            【解决方案6】:

            我认为您在 makeode 函数中返回的节点不正确。 试试

            ptr = newNode;
            

            在你回来之前。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2017-02-08
              • 1970-01-01
              • 2020-05-04
              • 2011-10-22
              • 2016-02-09
              • 2019-06-14
              相关资源
              最近更新 更多