Некоторая путаница с указателями в C (PPP2, глава 17, упражнение 11)

#c

#c

Вопрос:

Изучаю C с помощью Bjarne Stroustrup PPP2 и застрял в упражнении 11 из 17 главы.Там я должен понять, Link* add(Link* n) функция, где помещается объект после, как я могу догадаться, что это то же самое, что Link* insert(Link* n) функция, где помещается объект раньше.Проблема в том, что моя функция добавления не работает должным образом, например, вызывает this* указатель, а prev указатель не назначен должным образом. Мой источник —>>

 #include <iostream>
#include <vector>
#include <sstream>
#include <string>
using namespace std;

class Link {
public:
    Link(string n, Link* p = nullptr, Link* s = nullptr) :value{n}, prev{ p }, succ{ s }{};
    string value;
    Link* insert(Link* n);
    Link* add(Link* n);
    Link* erase();
    Link* find(const stringamp; s);
    const Link* find(const  stringamp; s) const;
    Link* advance(int n);
    Link* next() const { return succ;}
    Link* previous() const { return prev; }
private:
    Link* prev;
    Link* succ;
};

Link* Link::insert(Link* n) {
    if (n == nullptr) return this;
    if (this == nullptr) return n;
    n->succ = this;
    if (prev) prev->succ = n;
    n->prev = prev;

    prev = n;
    return n;

}

Link* Link::add(Link* n) {
    if (n == nullptr) return this;
    if (this == nullptr) return n;
    n->prev = this;
    if(succ) succ->prev = n; 
    n->succ = succ;
    succ = n;
    return n;
}



Link* Link::erase() {
    if (this == nullptr) return nullptr;
    if (succ) succ->prev = prev;
    if (prev) prev->succ = succ;
    return succ;
}

Link* Link::find(const  stringamp; s) {
    Link* p=this;
    while (p) {
        if (p->value == s) return p;
        p = next();
    }
    return nullptr;
}

const Link* Link::find(const  stringamp; s) const {
    const Link* p = this;
    while (p) {
        if (p->value == s) { return p; }
        p=p->next();
    }
    return nullptr;
}

Link* Link::advance(int n) {
    Link* p=this;
    if (p == nullptr) return nullptr;
    if (0 < n) {
        while (n--) {
            if (p->succ == nullptr) return nullptr;
            p = p->succ;
        }
    }
    else if (n < 0) {
        while (n  ) {
            if (p->prev == nullptr) return nullptr;
            p = p->prev;
        }
    }
    return  p;
}

void print_all(Link* p) {
    cout << "{ ";
    while (p) {
        cout << p->value;
        if (p = p->next())cout << ", ";
        
    }
    cout << " }";
}

    

int main()
{
    Link* norse_gods = new Link{ "Thor"};
    norse_gods = norse_gods->insert(new Link{ "Odin"});
    norse_gods = norse_gods->insert(new Link{ "Loki"});
    norse_gods = norse_gods->insert(new Link{ "Freia" });

    Link* greek_gods = new Link{ "Hera" };
    greek_gods = greek_gods->add(new Link{ "Appolo" });  //There is Appolo is must be placed before "Hera", but is just eat her =)
    greek_gods = greek_gods->insert(new Link{ "Athena"});
    greek_gods = greek_gods->insert(new Link{ "Ares"});
    greek_gods = greek_gods->insert(new Link{ "Poseidon"});


    /*
    
    Link* p = greek_gods->find("Mars");
    if (p) p->value="Ares";

    Link* p2 = norse_gods->find("Zeus");
    if (p2) {
        if (p2 == norse_gods) norse_gods = p2->next();
        p2->erase();
        greek_gods=greek_gods->insert(p2);
    }
    */
    
    print_all(norse_gods);
    cout << "n";
    print_all(greek_gods);
    cout << "n";
         
}
  

Мой вывод —>

{ Фрейя, Локи, Один, Тор }

{ Посейдон, Арес, Афина, Апполо }

Где создается перед Hera?

Спасибо за внимание, ребята, надеюсь на вашу помощь.

Комментарии:

1. if (this == nullptr) 0_0

2. Да, это странно,но этот код взят из книги.

Ответ №1:

Проблема просто в том, что вы не печатаете свой второй список с самого начала, так как greek_gods указывает на его второй элемент.

Попробуйте:

 print_all(greek_gods->previous());
  

Если вы не понимаете почему, я предлагаю использовать ручку и бумагу и записывать, как список выглядит после каждого обновления. Или используйте отладчик.

Комментарии:

1. Спасибо. Но с print_all(greek_gods->previous()) у меня есть этот вывод. Не могу понять, почему поместите Hera на первое место. { Hera, Poseidon, Ares, Appolo, Athena }

2. @c_thief Потому что после add , greek_gods указывает на Apollo . Затем вы вставляете элементы между ними. Это точно соответствует коду. Опять же, используйте ручку и бумагу и решайте каждую операцию по отдельности.

Ответ №2:

Спасибо. Мне просто нужен был свежий взгляд. Когда вставка работает, просто каждый раз последовательно перемещает предыдущее. После изменения бита add функция

 Link* Link::insert(Link* n) {
    if (n == nullptr) return this;
    if (this == nullptr) return n;
    if (prev) {
        n->succ = prev;
        prev->prev = n;
        n->prev = prev->prev;
    }
    else {
        n->succ = this;
        n->prev = prev;
        prev = n;
    }
    return n;
  

На данный момент вывод: { Poseidon, Ares, Dionis, Athena, Hera, Appolo }

Спасибо!