Ошибка реализации связанного списка в 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 4

2 ответа:

while(scanf("%s", &s) == 1) push(list, s);

Каждый раз, когда вы звоните push, вы нажимаете s в список. Таким образом, каждая запись будет содержать точно такое же значение указателя, которое, вероятно, не является тем, что вы хотите.

Когда вы переходите к печати, s содержит "c". Каждый узел имеет указатель на s, поэтому вы печатаете "c" три раза, по одному разу для каждого узла.

Поле data в структуре является указателем, поэтому его нужно рассматривать как таковой. Вы неправильно его используете. Попробуйте что-нибудь вроде этого:

node->data = strdup(newValue);
Изучите документацию для strdup, чтобы точно знать, как она работает.

Также

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