C. Pop中的链接堆栈会导致分段错误,但Push不会!

时间:2010-07-08 17:36:27

标签: c

我正在做一些简单的事情,所以希望这个问题很容易回答。我正在使用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函数出错。对数据的分配也给了我一个seg错误。除了返回和堆栈长度赋值语句之外,几乎所有内容都会给出分段错误。你们任何人都可以帮我解决这个问题吗?造成这些段错误的原因是什么?

以下是整个计划:

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

6 个答案:

答案 0 :(得分:8)

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

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

答案 1 :(得分: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 ...
}

答案 2 :(得分:2)

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下运行提供的额外信息可以帮助您在较大的程序中找到这些类型的问题。

答案 3 :(得分:0)

在makeNode中,您正在创建一个新节点,将该节点指向传入的值,然后返回传入的值,而不是新节点。由于您传入的stk->headNULL开头,因此每次推送都会创建一个指向NULL的新节点,然后返回NULL,因此stk->head并没有像你期望的那样改变。当您弹出广告时,您正试图访问NULL->ptrNULL->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
}

它会起作用。

答案 4 :(得分:0)

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

答案 5 :(得分:0)

我认为你没有在你的makeode函数中返回正确的节点。 试试

ptr = newNode;

返回之前。