为什么static关键字在这里阻止了分段错误?

时间:2015-08-27 03:59:52

标签: c pointers static coredump

我正在玩C中的指针并遇到了一个我不明白的行为。它涉及在以下程序中使用static关键字:

/**
*      Simple LIFO stack implemented using linked lists
*/
#include <stdio.h>
#include <stdlib.h>

typedef struct LinkedList LinkedList;
struct LinkedList{
        int value;
        LinkedList *next;
};

int pop(LinkedList **list){
        LinkedList *next;
        int ret;        
        ret = (*list)->value;
        next = (*list)->next;
        //free(*list);
        *list = next;
        return ret;
}
void push(LinkedList **list, int value){        
        LinkedList *new = (LinkedList*)malloc(sizeof(LinkedList));
        new->value = value;
        new->next = (*list);
        *list = new;
}

int main() {        
        LinkedList *myList;

        for(int i = 0; i<10; i++)
                push(&myList, i);


        while(myList!=NULL)
                printf("popped %i\n", pop(&myList));          

        return 0;
}

当我编译并运行上面的代码时,我遇到了分段错误。但是,当我将myList的声明更改为static LinkedList *myList时,该程序(看起来)非常有效:

output without static keyword:
popped 9
popped 8
popped 7
popped 6
popped 5
popped 4
popped 3
popped 2
popped 1
popped 0
popped 1
popped 1970220846
Segmentation fault (core dumped)

output with static keyword:
popped 9
popped 8
popped 7
popped 6
popped 5
popped 4
popped 3
popped 2
popped 1
popped 0

我真的不明白为什么会这样。我认为它与范围有关,因为以下代码的工作原理完全相同,而不需要static关键字:

/**
*      Simple LIFO stack implemented using linked lists
*/
#include <stdio.h>
#include <stdlib.h>

typedef struct LinkedList LinkedList;
struct LinkedList{
        int value;
        LinkedList *next;
};

int pop(LinkedList **list){
        LinkedList *next;
        int ret;        
        ret = (*list)->value;
        next = (*list)->next;
        //free(*list);
        *list = next;
        return ret;
}
void push(LinkedList **list, int value){        
        LinkedList *new = (LinkedList*)malloc(sizeof(LinkedList));
        new->value = value;
        new->next = (*list);
        *list = new;
}

int main() {        
        LinkedList *myList;

        push(&myList, 0);
        push(&myList, 1);
        push(&myList, 2);
        push(&myList, 3);
        push(&myList, 4);
        push(&myList, 5);
        push(&myList, 6);
        push(&myList, 7);
        push(&myList, 8);
        push(&myList, 9);


        while(myList!=NULL)
                printf("popped %i\n", pop(&myList));          

        return 0;
}

我知道分段错误的原因是pop()函数试图取消引用错误的地址(因为显然myList!=NULL检查不起作用),但由于某种原因{{1关键字神奇地修复了所有内容!

只有其他想到的事情是,它与将for循环中的static指针的引用传递给myList有关。虽然我不知道这有什么不对......

谢谢!

3 个答案:

答案 0 :(得分:3)

未初始化(和零初始化)静态变量被放入BSS。 BSS由加载器归零。因此,通过将变量设为静态,您可以将其有效地初始化为NULL。如果没有静态,则在堆栈上分配相同的变量。未初始化的堆栈变量可以包含任何随机值(取决于之前使用的堆栈),访问此类变量会导致未定义的行为。

答案 1 :(得分:1)

您没有明确初始化myList变量。

当声明为本地(自动)变量时,它最初包含垃圾值,当您尝试从堆栈中弹出所有内容时,这会导致崩溃。

当您将其声明为static时,会使用空指针值隐式初始化它,这最终会使您的弹出循环按预期终止。

答案 2 :(得分:0)

默认情况下,静态变量会自动初始化为0,因此当您使用mylist关键字时,static的初始值将为空指针。然后当你循环遍历列表的元素时,while (mylist != NULL)将在你到达这个空指针时停止。

自动变量不会自动初始化,因此mylist的初始值是垃圾。 while循环不会将此检测为列表的末尾,当您尝试间接执行此操作时,会发生未定义的行为。

要使用自动变量获得相同的行为,只需指定初始值:

LinkedList *myList = NULL;