为什么这种分段错误在构建之间不一致?

时间:2011-05-26 10:37:33

标签: c segmentation-fault

我写了一个c程序,编译它并运行正常。经过几次编译后 - 它开始给我一个分段错误。我重新命名了文件夹,重新编译,然后再次工作。
这是正常的吗?有一个不一致的分段错误?我改变输出名称,更改文件夹名称等。它从给出分段错误反弹到不给出seg错误。我不知道该怎么办。
我的意思是,如果是编码问题,seg错误应该是一致的,对吧?我每次都应该得到它。这是代码:
文件my_set.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
The program acceps a set of numbers from stdin until EOF
And then prints them (not storing duplicate numbers)
*/

int main ()
{
    int num; 
    nodePtr head; /*head of the list*/

    while (scanf("%d", &num) != EOF)
    {
        addToList(num, &head);
    }
    printList(head);
    freeList(head);
    return 0;
}

file list.c:

#include <stdio.h>
#include <stdlib.h>
#include "list.h"

/*
Implements a linked list, each element of which contains a dynamic array.
I used a linked list to maximize potential memory in case it is fragmented.
I use a dynamic array in each node to minimize the percentage of overhead
from creating a list (the pointer, the index...);
*/

/*
Adds number n to list *h
4 cases:
1. list is empty:
    creating one
    updating h with new list
    creating a new dynamic array in the list
    updating it and the index
2. can reallocate current node's array for 1 more int
3. cannot reallocate current node's array:
    creating a new node
    initializing it
4. cannot create a new node
    printing the current list, an "out of memory error" and freeing all memory.
*/
void addToList(int n, nodePtr *h)
{
    static nodePtr p; /*points to current last node*/
    int *temp; /*for use in reallocation*/

    if (!*h) /*first item of set*/
    {
        *h = malloc (sizeof(node));
        (*h)->arr = malloc(sizeof(int));
        (*h)->arr[0] = n;
        (*h)->i = 1;
        p = *h;
        return;
    }

    /*if n is already in the list, no need to add it
    the call comes after first item, because first item cannot be in the list*/
    if(existsInList(n, *h)) return;

    /*using realloc while still possible*/
    if ((temp = realloc(p->arr, (p->i+1)*sizeof(int))))
    {
        p->arr = temp;
        p->arr[p->i] = n;
        p->i++;
        return;
    }

    /*if  realloc no longet possible - start new node*/
    if ((p->next = malloc(sizeof(node))))
    {
        p = p->next;
        p->arr = malloc(sizeof(int));
        p->arr[0] = n;
        p->i = 1;
        return;
    }

    /*can no longer start new nodes - quit with error, after printing*/
    printf("out of memory!");
    printList(*h);
    freeList(*h);
}

/*checks if n is in p assuming p is not null
it can asume so because the call for it comes after the check for first item*/
int existsInList(int n, nodePtr p)
{
    int i;
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            if (p->arr[i] == n)
                return 1;
    return 0;
}

/*frees the list*/
void freeList(nodePtr p)
{
    nodePtr temp = p;

    if (!p) return; /*list is empty*/

    while (p)
    {
        free(p->arr);
        p = p->next;
        free(temp);
    }
}

/*prints the content of the list to stdout*/
void printList(nodePtr p)
{
    if (!p) return;
    int i;
    printf("\n");
    for (; p ; p = p->next)
        for (i = 0; i < p->i; i++)
            printf("%d ", p->arr[i]);   
    printf("\n");
}

file list.h:

/*
pointer to a node
declare a variable of this type to create a list
then start adding to the list
*/
typedef struct s *nodePtr;

/*the struct that represents each node of the list
reason for dynamic array is in "list.c"
*/
typedef struct s
{
    int *arr;
    int i; /*index for next num, also size of array;*/
    nodePtr next;
}node;

/*Adds the int to list at nodePtr omitting duplicates*/
void addToList(int, nodePtr*);
/*prints a list*/
void printList(nodePtr);
/*returns 1 if an int exists in list referenced by nodePtr, 0 otherwise*/
int existsInList(int, nodePtr);
/*frees all dynamically allocated memory*/
void freeList(nodePtr);

基本上我所做的就是从stdin中获取数字,将它们放在一个列表中(没有重复项)然后打印它们。我使用动态数组列表。

3 个答案:

答案 0 :(得分:6)

初始化变量!

int num = 0;  
nodePtr head = NULL; /*head of the list*/

ADD:不一致的行为可能来自调试与发布编译,通常编译器在调试模式下将非初始化变量设置为奇怪的值,如0xDDDDDDDD,以使问题立即可见。在释放模式下,如果内存块为零,则会发生变量内容为0但不能保证它。

答案 1 :(得分:1)

c / c ++程序中的间歇段错误通常是由未初始化的内存引起的,通常是在指针变量中。

你发布了很多代码,这使得调试很难阅读。我建议通过代码,无论在哪里声明变量,给它一个初始值(例如零或NULL)。请记住,编译器不会为您初始化它们。

您应该首先在num中初始化headmain()的值。 E.g。

int num = 0; 
nodePtr head = NULL; /*head of the list*/

编辑1

addToList()中的另一个错误。如果未执行该函数中的第一个if块,则稍后调用p时将无法初始化局部变量realloc(p->arr, ...)的值。当您取消引用p以使p->arr, if p'未初始化时,您通常会获得段错误。

编辑2

使用C / C ++编程时的两种有用技巧:

  1. 始终在声明变量的位置初始化变量。如果不这样,那么它们的值是不确定的。请注意,这并不能解决所有问题。如果取消引用未初始化的指针,那么通常会获得段错误。如果你将它初始化为null然后取消引用它,那么你将总是得到一个段错误。更容易调试,但它仍然崩溃。
  2. 始终将变量声明为尽可能接近您首次使用它们的代码中的点。这具有降低使用未初始化变量的机会的效果,因为编译器将生成“未声明的变量”错误。在函数开头声明所有变量的做法是来自旧式'K&R' C的宿醉,你必须这样做。现代C不需要它。
  3. 所以,而不是:

    int foo()  // Warning: bad code
    {
        int a;
        int b;
    
        func1();
        a=func2(&b);
        return a;
    }
    

    尝试类似:

    int foo()
    {
        func1();
        int b = 42;
        int a = func2(&b);
        return a;
    }
    

答案 2 :(得分:1)

如果它返回malloc()(内存不足),您应该检查NULL的返回值。