Проблема, которую вы описываете, может быть исправлена путем изменения управляющего выражения в вашей функции 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;
}
Потому что в одном вы проверяете указатель на элемент, а в другом вы проверяете указатель на элемент _next_, то есть вы заканчиваете с разными условиями. Попробуйте использовать более длинные списки, и вы увидите, что произойдет. PS: глобальные переменные являются злыми. – Jens
Если вы установите флажок 'while (temp1-> next! = NULL)', тогда вы всегда пропустите первый элемент. – RoadRunner
Ответ на ваш второй вопрос после изменения: что происходит, когда вы вставляете свой первый узел? Какова ценность 'HEAD' в тот момент? (подсказка: 'NULL'). Поскольку вы всегда вставляете в начало списка, ваш «первый» узел всегда будет иметь последний * узел. При печати * последнего * узла, что такое значение 'node-> next'? (это 'NULL'). Если вы используете 'while (temp1-> next! = NULL)', когда вы доходите до последнего узла (первое значение) 'temp1-> next == NULL', то цикл завершается, оставив последний узел (первое значение) непечатанным. Выполнение предложенных изменений устраняет эту проблему. –