Ошибка реализации связанного списка в 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в той же функции. Это указатель, и его следует рассматривать как таковой.