Ошибка при выделении объекта (узла связанного списка) автоматически, но не динамически - PullRequest
0 голосов
/ 26 февраля 2020

Я играл с автоматами c против динамического c выделения памяти для узла связанного списка. Следующий код представляет минимальный рабочий пример.

Следующий код работает и печатает ожидаемый результат:

list 1:
1 
list 2:
2 
list 3:
1 2 

Код:

#include <iostream>

struct ListNode {
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* merge_two_lists_iter(ListNode* l1, ListNode* l2) {

    ListNode* res = nullptr;
    res = new ListNode(l1->val);
    res->next = new ListNode(l2->val);

    return res;
}

void print_list(ListNode* l) {
    while (l) {
        std::cout << l->val << " ";
        l = l->next;
    }
    std::cout << std::endl;
}

int main() {

    // List l1 consists of one node with value 1
    ListNode* l1 = new ListNode(1);

    // List l2 consists of one node with value 2
    ListNode* l2 = new ListNode(2);

    // List l3 is l1 and l2 merged
    ListNode* l3 = merge_two_lists_iter(l1, l2);

    std::cout << "list 1:" << std::endl;
    print_list(l1);
    std::cout << "list 2:" << std::endl;
    print_list(l2);
    std::cout << "list 3:" << std::endl;
    print_list(l3);

    return 0;
}

Однако, когда я замените строку res = new ListNode(l1->val); следующим:

ListNode test (l1->val);
res = &test;

Кажется, что l3 состоит из нескольких случайных значений:

list 1:
1 
list 2:
2 
list 3:
-1845946528 -272632592 -2092384207 (lldb)

Я попытался отладить функцию merge_two_lists_iter и l3 выглядит правильно. Однако функция print_list печатает некоторые случайные значения. Я был бы очень признателен, если бы кто-нибудь смог ELI5, что здесь происходит.

1 Ответ

2 голосов
/ 26 февраля 2020
ListNode* merge_two_lists_iter(ListNode* l1, ListNode* l2) {

    ListNode* res = nullptr;
    ListNode test (l1->val);
    res = &test;
    res->next = new ListNode(l2->val);

    return res;
}

Я предполагаю, что именно так выглядел merge_two_lists, когда вы заменили эту строку. Обратите внимание, что test является локальной переменной, которая размещена в стеке. Когда функция возвращает res, test выводит go из области видимости, поэтому функция возвращает адрес освобожденной стековой памяти. Однако то, что на самом деле происходит с этой памятью после ее освобождения, не определено в стандарте C. Таким образом, в этом случае вы получили случайный мусор в адресе объединенного списка.

...