Ошибка реализации связанного списка в C
У меня есть программа, написанная на языке Си, и я борюсь с эффектом, который не могу понять. Приложение считывает последовательность слов в качестве ввода командной строки. При чтении входных данных он помещает одно за другим слова в список. А потом распечатывает список. Что меня поражает, так это то, почему значения, добавленные вне цикла, печатаются правильно, а значения, добавленные внутри цикла, - нет. я имею в виду, что какие бы значения ни были введены пользователем, будет напечатан только последний. И кроме того, он будет напечатан столько раз, сколько количество введенных значений равно. Двумя основными подозреваемыми являются методы push и printList:
void push(struct List * list, char* newValue){
assert(list != NULL);
assert(newValue != NULL);
Node* node = createNode();
node->data = newValue;
node->next = NULL;
if(list->firstNode != NULL){
node->next = list->firstNode;
list->firstNode = node;
}
else list->firstNode = node;
}
void printList(struct List * list){
assert(list != NULL);
Node *node = list->firstNode;
while(node->next != NULL){
printf("%s ", node->data);
node = node->next;
}
if(node != NULL) printf("%s ", node->data);
}
Но я не смог найти там никаких жучков. Что я сделал, так это сравнил поведение с циклом while и без него:
int main(){
struct List* list = createList();
char s[256];
int a;
push(list, "he");
push(list, "bee");
push(list, "gee");
while(scanf("%s", &s) == 1) push(list, s);
printList(list);
}
Вывод, который я получил:
C c C gee bee he
В то время как входные данные:
A b c
Поэтому я ожидал получить
C b A gee bee he
Что я пропустил? Любое предложение высоко оцененный.
P.S. типы defs и методы, используемые выше:
typedef struct Node {
char* data;
struct Node *next;
} Node;
typedef struct List {
struct Node *firstNode;
} List;
Node *createNode(){
Node* node = malloc(sizeof(struct Node));
assert(node != NULL);
node->data = "";
node->next = NULL;
return node;
}
List *createList(){
List* list = malloc(sizeof(struct List));
list->firstNode = NULL;
assert(list != NULL);
return list;
}
2 ответа:
while(scanf("%s", &s) == 1) push(list, s);
Каждый раз, когда вы звоните
push
, вы нажимаетеs
в список. Таким образом, каждая запись будет содержать точно такое же значение указателя, которое, вероятно, не является тем, что вы хотите.Когда вы переходите к печати,
s
содержит "c". Каждый узел имеет указатель наs
, поэтому вы печатаете "c" три раза, по одному разу для каждого узла.
Поле
data
в структуре является указателем, поэтому его нужно рассматривать как таковой. Вы неправильно его используете. Попробуйте что-нибудь вроде этого:Изучите документацию для strdup, чтобы точно знать, как она работает.node->data = strdup(newValue);
Также
if(list->firstNode != NULL){ node->next = list->firstNode; list->firstNode = node; } else list->firstNode = node;
Можно изменить на
if(list->firstNode != NULL){ node->next = list->firstNode; } list->firstNode = node;
Или даже лучше просто
Другой комментарий заключается в том, что вы должны выбрать, хотите ли вы установитьnode->next = list->firstNode; list->firstNode = node;
node->next
вNULL
вcreateNode
или снаружи. Не делай так. Это просто загромождает ваш код. Я бы выберите, чтобы сделать это вcreateNode
. Я бы также установилnode->data
вNULL
в той же функции. Это указатель, и его следует рассматривать как таковой.