2014-08-28 17 views
0

Я пытался создать Очереди в C (как проект класса). Демо-код, который они предоставили, предназначен для Borland Turbo C. Я пытаюсь перестроить программу через gcc. Хотя код отлично работает в Turbo C, он выдает ошибку в gcc во время выполнения как Segmentation Fault (core dumped).Инициализация указателя итератора: ошибка сегментации

Я не включил ненужные части кода. Пробовал и тестировал его по строкам.

struct node { 
    int data; 
    struct node *link; 
}; 

struct queue { 
    struct node *front; 
    struct node *rear; 
}; 

void initQ(struct queue *q) { 
    q->front = q->rear = NULL; //  Error : Segmentation Fault! (core dumped) 
} 


void main() { 
    struct queue *Q; 
    initQ(Q); 
} 

Я уверен, что проблема связана с версией C в компиляторе. Поскольку Turbo C довольно древний, он не поддерживает последние исправления. Я получаю подобную ошибку Segmentation Fault в различных других частях коды, как:

void displayQ(struct queue *q) { 
     struct node *temp; 
     temp->link = q->front; //  Error : Segmentation Fault! (core dumped) 
} 

Вопрос 1: Почему GCC дает такую ​​ошибку во время выполнения? (в этом коде)

Вопрос 2: Почему код работает нормально в Turbo C, но не gcc?

Вопрос 3: Есть ли альтернатива такому стилю программирования?

+1

Вопрос 2: код недействителен в каждой версии C, поэтому изучение того, почему он работает с Turbo C, будет зависеть от нескольких других данных. Например. Платформа. Также обратите внимание, что он может работать для небольших очередей, но не работает для большего ввода, или может быть немедленно сработал, если снова запустится и так далее.Кажется, что 'Q' имеет какое-то случайное значение, которое может быть разыменовано (то, на что оно указывает, и другие данные, которые вы могли бы перезаписать, - это другое дело). Также обратите внимание, что он мог работать, когда скомпилирован с Gcc. – mafso

ответ

1

Вопрос 1: Почему gcc дает такую ​​ошибку во время выполнения? (в этом коде)

Поскольку код неправильный - вы разыскиваете инициализированный указатель.


Вопрос 2: Почему код отлично работает в Turbo C, но не GCC?

Это не работает нормально, оно просто не обнаруживает ошибку. 16-битный код DOS не имеет преимущества защиты памяти и виртуальной памяти. Он не может определить разницу между реальной памятью, принадлежащей вашему процессу (в DOS нет памяти процесса, поскольку она не многозадачна. Вся подсистема DOS работает в своей собственной защищенной VM. Единственная защита, которую вы можете иметь, - это разыменование указателя NULL. Значение указателя будет разрешено для некоторого недетерминированного местоположения памяти и может работать корректно, пока что-то еще не использует ту же самую ячейку памяти для какой-либо другой цели - это может никогда не произойти, что может случиться иногда, или это может произойти при выполнении на другой машине - вы не можете сказать.

Чаще всего проблема проявится задолго до того, как код будет написан, когда ваше приложение станет больше и будет использовать все больше и больше памяти. Если ссылка на местоположение находится в вашем кодовом пространстве, у вас будет интересная перспектива случайного изменения кода при выполнении. s очень трудно найти, потому что причина и следствие часто разделяются близостью времени и кода.

Если бы ваш написано:

struct queue *Q = NULL ; 

Вы, возможно, был отчет об ошибке выполнения. Это не делает код более правильным, но это делает более вероятным обнаружение таких ошибок.


Вопрос 3: Есть ли альтернатива такому стилю программирования?

Это не вопрос стиля, это вопрос правильности. Однако, если вы всегда инициализируете свои указатели в объявлении указывать либо на действительный экземпляр, либо на NULL, вы можете избежать проблемы или, по крайней мере, добиться раннего обнаружения ошибки.

Несмотря на то, что в этом случае в 32-битном коде ошибка была обнаружена во время выполнения, что отнюдь не гарантировано - ваш инициализированный указатель находится в стеке, который в других случаях может содержать значения, которые являются действительными адресами в вашем процесс, и вы просто будете топать своими данными.

3
void initQ(struct queue *q) { 
    q->front = q->rear = NULL; 
} 

В коде q не инициализируется, когда вы используете его и указывает на некоторый случайный адрес. Попробуйте:

struct queue Q; 
initQ(&Q); 
+0

Больше ошибок в 'initQ()', но я получаю такую ​​же ошибку в 'temp-> link = q-> front;' из функции displayQ() '. –

4

Вам необходимо зарезервировать место (с использованием malloc):

struct queue *Q = malloc(sizeof(*Q)); 
initQ(Q); 

calloc или еще лучше:

struct queue *Q = calloc(1, sizeof(*Q)); 
/* initQ(Q); you don't need this, calloc set all members to NULL */ 

Не забудьте позвонить free(Q); в конце.

+2

+1 для приятного 'malloc()' вызова с использованием 'malloc (sizeof * Q);' vs. 'malloc (sizeof (struct queue));'. – chux

+0

Пропуск 'free (Q)' может привести к ошибке программы «Ошибка сегментации!»? –

+1

Нет, пропуская «свободный» [утечка памяти] (http://en.wikipedia.org/wiki/Memory_leak) –

2

Q не был инициализирован, чтобы указывать в любом месте, что означает недействительный значение указателя. Когда вы передаете его initQ, вы пытаетесь разыменовать его с помощью оператора ->. Попытка разыменовать неверный указатель приводит к неопределенным поведением, что может означать что-либо из кода, работающего, как ожидается, сбой на повреждение данных.

Независимо от начального, неопределенные значения Q имеет под Turbo C, это в доступной области памяти (это все еще недействителен указатель, хотя), так что вы не получите Segfault, что вы делаете в НКУ.

Когда вы позвоните initQ, qдолжно указать действительный объект.Вы могли бы назвать initQ на существующий экземпляр очереди, например, так:

struct queue Q; // Q is an instance of struct queue, not a pointer to it 
initQ(&Q); 

Или, вы можете создать псевдо-конструктор, который динамически выделяет память для нового объекта очереди и вызывает initQ на нем:

struct queue *create_queue_element() 
{ 
    struct queue *q = malloc(sizeof *q); 
    if (q) 
    initQ(q); 
    return q; 
} 
... 
struct queue *Q = create_queue_element(); 
Смежные вопросы