2014-01-22 3 views
2

Я только что начал изучать C и изучал простые реализации связанных списков. Когда я попробовал распечатать свой список, я понял нечто особенное. Я бы получил ошибки сегментации в части кода, даже если этот код никогда не выполнялся. Как это может быть?Ошибка сегментации, хотя код никогда не выполняется?

Насколько я знаю, цикл while никогда не выполняется, поскольку следующий указатель не указывает ни на что. Я думал, что, возможно, при оценке цикла while это может привести к тому, что он указывает на то, что вызывает ошибку сегментации, но как ни странно, если вы удаляете строку root = root->next, она выполняется отлично (без каких-либо ошибок). Даже тогда он никогда не входит в цикл while. Итак, как может строка кода (root = root->next вызывать ошибку, если код никогда не выполняется? Код компилируется просто отлично. Я сделал простую ошибку где-то?

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

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

struct linkedlist { 
    int value; 
    struct linkedlist * next; 
}; 

typedef struct linkedlist item; 

int main(int argc, char **argv) { 
    item * root; 
    item * current; 

    root = malloc(sizeof(item)); 
    root->value = 500; 

    int i; 
    for(i = 0; i <= 20; i++) { 
     current->next = malloc(sizeof(item)); 
     current = current->next; 
     current->value = i; 
    } 

    while(root->next != 0) { 
     //This is never executed 
     printf("[%d]\n", root->value); 
     //the line below does cause the segmentation error 
     //but how can this affect anything at all if this is never executed? 
     root = root->next; 
    } 
    return 0; 
} 

ответ

3

Первая строка с current->next является разыменование неинициализированного указателя. Вы, наверное, забыли инициализировать current к root перед циклом. Derefencing неинициализированного указателя является неопределенным поведением (UB), что означает все может случиться. На практике неинициализированные переменные будут иметь значения, соответствующие любому контенту s хранится в памяти. Таким образом, неинициализированный указатель будет установлен на некоторый полуслучайный адрес и будет либо указывать на некоторое также полуслучайное содержимое в памяти (возможно, на другие программные переменные), либо быть недействительным.

Существует еще один неинициализированный указатель, который разыменован в состоянии для тестирования цикла while root->next. Как правило, вы должны убедиться, что поле next каждого из элементов списка (включая root) установлено на 0, иначе вы не сможете обнаружить конец связанного списка (неинициализированный указатель снова, так что UB снова и снова практика значение, вероятно, будет отличаться от 0).

предложение исправить такого рода проблемы в вашем коде:

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

struct linkedlist { 
    int value; 
    struct linkedlist * next; 
}; 

typedef struct linkedlist item; 

int main(int argc, char **argv) { 
    item * root; 
    item * current; 

    root = malloc(sizeof(item)); 
    root->value = 500; 
    root->next = 0; 

    current = root; 

    int i; 
    for(i = 0; i <= 20; i++) { 
     current->next = malloc(sizeof(item)); 
     current = current->next; 
     current->value = i; 
     current->next = 0; 
    } 

    while(root->next != 0) { 
     printf("[%d]\n", root->value); 
     root = root->next; 
    } 
    return 0; 
} 
+0

Но если я раскомментировать корень строки = корне-> следующая; и введите инструкцию prinf, в конце концов она выполняется без сбоев. –

+2

root-> next также не инициализируется до цикла while. – OldProgrammer

+0

@OldProgrammer Могу ли я проверить, что в цикле while? while (root-> next! = NULL)? –

Смежные вопросы