Почему эта ошибка сегментации несовместима между сборками? - PullRequest
2 голосов
/ 26 мая 2011

Я написал программу AC, скомпилировал ее, и она работала нормально.После нескольких компиляций - он начал давать мне ошибку сегментации.Я переименовал папку, перекомпилировал, и она снова заработала.
Это что-то нормальное?Неправильная ошибка сегментации?Я изменяю имя вывода, меняю имена папок и т. Д., И он отскакивает от ошибки сегментации до ошибки сегментации.Я не знаю, что делать дальше.
Я имею в виду, если это проблема кодирования, ошибка сегмента должна быть последовательной, верно?Я должен получить это каждый раз.Вот код:
file 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 ]

6 голосов
/ 26 мая 2011

Инициализируйте ваши переменные!

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

ADD: Непоследовательное поведение может возникнуть в результате отладки и выпуска релиза, обычно компиляторы в режиме отладки устанавливают неинициализированные переменные в странные значения, например 0xDDDDDDDD,проблема сразу видна.В режиме освобождения, если блок памяти обнуляется, может случиться так, что содержимое переменных будет равно 0, но это не гарантируется.

1 голос
/ 26 мая 2011

Вам следует проверить возвращаемые значения из malloc() на случай, если он вернет NULL (недостаточно памяти).

1 голос
/ 26 мая 2011

Периодические ошибки в программах на языке c / c ++ обычно вызываются неинициализированной памятью, часто в переменных-указателях.

Вы опубликовали много кода, который затрудняет отладку, просто читая его. Я предлагаю пройтись по коду и, где бы ни была объявлена ​​переменная, дать ей начальное значение (например, ноль или NULL). Помните, что компилятор не инициализирует их для вас.

Возможно, вам следует начать с инициализации значений num и head в main(). Э.Г.

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, а затем разыменуете его, то вы всегда получите segfault. Проще отладить, но все равно вылетает.
  2. Всегда объявляйте переменные как можно ближе к той точке кода, в которой вы их впервые используете. Это снижает вероятность использования неинициализированной переменной, поскольку компилятор выдаст ошибку «необъявленная переменная». Практика объявления всех переменных в начале функции - это похмелье от старого стиля 'K & R' C , где вы должны были это сделать. Современному С это не требуется.

Итак, вместо:

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