2016-12-31 4 views
0

У меня есть программа C для вставки элементов в начале связанного списка, но когда я пытаюсь распечатать элементы, он всегда пропускает первый элемент. Может кто-то, пожалуйста, указать, что я делаю неправильно в своей программе.Перемещённый список traversal пропускает первый элемент

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


void PrintElements(); 
void InsertElement(int x); 

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

struct node* HEAD; 
struct node* temp; 
struct node* temp1; 


void PrintElements() 
{ 
    temp1=HEAD; 
    while(temp1->next!=NULL) 
    { 
     printf("\n\r Data %d\n\r",temp1->data); 
     printf("\n\r Address %x\n\r",temp1->next); 
     temp1=temp1->next; 
    } 
} 

void InsertElement(int x) 
{ 
    struct node* temp=(struct node*)malloc(sizeof(struct node)); 
    temp->data=x; 
    temp->next=HEAD; 
    HEAD=temp; 

} 

int main() 
{ 

    int i, x; 
    int n; //n stores the number of elements to be added to the linked list 
    HEAD=NULL; //Assigning HEAD to null when there are no elements in the list 
    printf("Enter the number of elements\n"); 
    scanf("%d",&n); 
    for(i=0;i<n;i++) 
    { 
     printf("\n\rEnter the number"); 
     scanf("%d",&x); 
     InsertElement(x); 
     PrintElements(); 
    } 

    return 0; 
} 

Когда я изменил следующую строку

while(temp1->next!=NULL) 

в

while(temp1!=NULL) 

программа работает правильно, но я до сих пор не могу понять, почему.

+0

Потому что в одном вы проверяете указатель на элемент, а в другом вы проверяете указатель на элемент _next_, то есть вы заканчиваете с разными условиями. Попробуйте использовать более длинные списки, и вы увидите, что произойдет. PS: глобальные переменные являются злыми. – Jens

+0

Если вы установите флажок 'while (temp1-> next! = NULL)', тогда вы всегда пропустите первый элемент. – RoadRunner

+2

Ответ на ваш второй вопрос после изменения: что происходит, когда вы вставляете свой первый узел? Какова ценность 'HEAD' в тот момент? (подсказка: 'NULL'). Поскольку вы всегда вставляете в начало списка, ваш «первый» узел всегда будет иметь последний * узел. При печати * последнего * узла, что такое значение 'node-> next'? (это 'NULL'). Если вы используете 'while (temp1-> next! = NULL)', когда вы доходите до последнего узла (первое значение) 'temp1-> next == NULL', то цикл завершается, оставив последний узел (первое значение) непечатанным. Выполнение предложенных изменений устраняет эту проблему. –

ответ

1

Проблема, которую вы описываете, может быть исправлена ​​путем изменения управляющего выражения в вашей функции PrintElements() на temp1 != NULL. Таким образом, если temp1 указывает на узел, то печатаются поля data и next, и цикл продолжается до тех пор, пока не будет больше узлов. При переходе по связанному списку, как правило, это путает вещи, когда вы смотрите на следующий узел, чтобы решить, что вы будете делать с текущим узлом. Но есть и другие проблемы с этим кодом.

Во-первых, было бы гораздо лучше объявить указатели struct в main() и передать их функциям вместо объявления их как глобальных переменных. Вы должны проверять возвращаемые значения функций, которые вы вызываете, когда это возможно. Вы должны проверить scanf(), чтобы убедиться, что вход соответствует ожиданиям; это также обеспечивает способ управления входным контуром, устраняя необходимость явного ввода счетчика перед вводом данных. Вы также должны проверить значение, возвращаемое вызовами, на malloc(), чтобы уловить ошибки распределения. Такая ошибка выделения в вашем коде приведет к неопределенному поведению, когда temp разыменовывается в самой следующей строке.

Вы должны free все распределения памяти, один free() для каждого звонка до malloc(). Когда вы печатаете адрес узла next в списке в функции PrintElements(), вы вызываете неопределенное поведение. Чтобы напечатать значение указателя, вы должны использовать спецификатор формата %p, и вы должны наложить указатель на (void *). Наконец, нет необходимости в #include <malloc.h>; stdlib.h заботится о том, что вам нужно.

Это измененная версия вашего кода, которая реализует предложенные изменения. Обратите внимание, что в случае ошибки распределения сообщение печатается на stderr, а программа exit s. Вызов метода malloc() был упрощен: нет причин, чтобы привести результат malloc() в C, и лучше использовать имя указателя, которому вы назначаете память вместо явного типа в аргументе, указанном в malloc(). new_node возвращается вызывающей функции, где указатель на head списка переназначается для указания на new_node.

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

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

void print_elements(struct node *start); 
struct node * insert_element(int x, struct node *head); 


int main(void) 
{ 
    struct node* head = NULL; 
    struct node* curr = NULL; 
    int x; 

    /* Read data into linked list */ 
    printf("Enter the first integer (q to quit): "); 
    while (scanf("%d", &x) == 1) { 
     head = insert_element(x, head); 
     print_elements(head); 
     printf("Enter another integer (q to quit): "); 
    } 

    /* Free allocated memory */ 
    while (head) { 
     curr = head; 
     head = curr->next; 
     free(curr); 
    } 

    return 0; 
} 

void print_elements(struct node *curr) 
{ 
    while(curr) { 
     printf(" Data: %d\n",curr->data); 
     printf("Address: %p\n\n",(void *) curr->next); 
     curr = curr->next; 
    } 
} 

struct node * insert_element(int x, struct node *head) 
{ 
    struct node *new_node = malloc(sizeof(*new_node)); 

    if (new_node == NULL) { 
     fprintf(stderr, "Allocation error in function insert_element()\n"); 
     exit(EXIT_FAILURE); 
    } 

    new_node->data = x; 
    new_node->next = head; 

    return new_node; 
} 
3

while(temp1->next!=NULL)

Измените это

while(temp1 != NULL)

И он должен работать нормально.

Причина:: Я думаю, что он не печатает первый элемент, который вы вводите.

Пример: Входной сигнал: 1 2 3

Связанный список сформирован как: 3 -> 2 -> 1 -> NULL обозначения, используемые: Каждое число является data, а стрелка показывает указатель next.

Тогда при запуске цикла, для каждой итерации:

  • temp1 точек в адрес 3

  • temp1 -> next != NULL (правда, как temp1 -> next точек в адрес 2)

  • распечаток 3 и temp1 теперь указывает на адрес 2

  • temp1 -> next != NULL (правда, как temp1 -> next указывает на адрес 1)

  • распечаток 2 и temp1 теперь указывает на адрес 1

  • temp1 -> next != NULL Это становится Ложные как temp1 указывает на адрес 1 и temp1 -> next NULL.

Поэтому мы никогда не заходим в петлю для печати 1.

Так что правильная вещь - использовать temp1 != NULL, так как это устранит вышеупомянутую ошибку.

+0

Хорошее объяснение !! Из чего вы JNV? –

+0

Что такое JNV, я понятия не имею. –