Verkettete Listen



  • Hallo!

    Ich habe eine Klasse, mit einer Verketteten Liste, ihr Name ist explosion, der Pointer auf das nächste Element ist jeweils next. Um diese Explosionen zu verwalten, besitze ich eine Verwaltungsklasse explosionen, in welcher E jeweils der Pointer auf die erste Explosion ist, von welchem ich dann die restlichen suche. In dieser Klasse ist eine Funktion für das Aufrufen der jeweiligen Anzeigeroutinen verantwortlich.

    Diese Funktion sieht wie folgt aus:

    void explosionen::anz()
    {
      if (pos>0)
      {
        explosion *anzeiger, *temp;
        temp = E;anzeiger=E;
        while (anzeiger!=0)
        {
          if (temp->gibstatus()<20)//Wenn noch nciht alle Frames angezeigt sind..
          {
            R->anzrs(G[temp->gibstatus()].graphikid, temp->gibx(), temp->giby());
            //Anzeigeklasse aufrufen
            temp->anz();//setze Status hoch und neue Koordinaten
          }
          else
          {
    
            if (pos>1)
            {
              //Element löschen, da ich mich von Anfang durchhangel -> erstpointer kann umgesetzt werden
              explosion *neuE;//Element nach E, das auf E geschoben werden soll
              neuE = E->next;//Element nach E wird zugewiesen
              delete E;//E wird gelöscht
              E = neuE;//Element nach E wird zugewiesen
              pos--;//Position wird 1 weniger, da Anzahl um 1 gesunken
            }
            else
            {
              //falls nur eine Exlosion läuft (->nur E gesetzt ist)
              temp->next=0;anzeiger=0; // damit aus whileschleife rausgesprungen wird -> tut er net
              delete E;//löschen der einen Explosion
              pos=0;//Speichern, dass keine Explosion vorhanden ist
              return;//Anzeige geht seltsamerweise trotzdem weiter -> muss aus Funktion rausspringen
            }
          }
          anzeiger = temp->next; 
          temp = anzeiger;
        }
      }
    }
    

    Leider funktionieren dabei 2 Sachen nicht:
    1. Das löschen bei pos>1:(d.h. noch andere Explosionen vorhanden als E)
    Ich habe mir gedacht, da eine Explosion immer 20 Frames hat, die immer gleich schnell ablaufen, brauche ich nichts groß machen, um etwas zu löschen, es reicht bereits, das erste Element, also E, zu löschen, und einfach eines der anderen Elemente auf E zu setzen. Leider funktioniert das nicht, und bei temp->gibstatus() stürzt er ab, da temp irgendwie nicht gesetzt ist..
    Könnt ihr mir bitte sagen, wieso das nicht funktioniert, und wieso ev.
    2. Bei else:
    Hier hab ich mir gedacht, reicht es schon, einfach das Zeug zu setzen, um aus der Schleife rauszuspringen, pos auf 0 zu setzen(da keine Explosion mehr vorhanden ist) und die Explosion zu löschen. Seltsamerweise bleibt er hier irgenwdie in der Schleife, und kommt wieder zum temp->gibstatus(). Kann sich einer von euch erklären, wieso das passiert, und wieso er nicht einfach aus dem while rausspringt?

    Ich hoffe, das ist jetzt im richtigen Unterforum, aber da ich keine Klasse, keine Windows oder Linuxspezifischen Sachen aufrufe, nehme ich an, dass das hier rein gehört..



  • Aus dem Code, den Du gepostet hast, ist nicht klar ersichtlich, was er tun soll. Ich unterstelle mal folgendes. Eine Menge von Explosionen soll angezeigt werden. Mit oder nach jeder Anzeige wird der Status (gibStatus) (um 1?) erhöht. Erreicht der Wert des Status den Wert 20 oder mehr, so soll dieses (und nicht das erste!) Element aus der Liste gelöscht werden.

    So wie Du es gemacht hast, sägst Du den Ast, auf dem Du sitzt ab, wenn Du Pointer auf ein ein Element setzt, was nachher gelöscht wird. Außerdem versucht Du immer das erste zu löschen; es kann natürlich sein, dass das erste auch immer die Explosion ist, die als erste 'fertig' ist, aber das wäre eine implizite Annahme.

    Also gut ich würde Dir folgenden Code vorschlagen:

    void explosionen::anz()
    {
        explosion* prev = 0; // prev zeigt auf den Vorgänger, falls vorhanden
        for( explosion* anzeiger = E; anzeiger;  )
        {
            if( anzeiger->gibstatus() < 20 )
            {
                R->anzrs(G[anzeiger->gibstatus()].graphikid, anzeiger->gibx(), anzeiger->giby());
                anzeiger->anz();
    
                prev = anzeiger;
                anzeiger = anzeiger->next;  // Übergang zum nächsten Element
            }
            else
            {
                // prev bleibt stehen!
                anzeiger = anzeiger->next;  // Übergang zum nächsten Element
    
                // Element *prev->next (vorher *anzeiger) löschen
                if( prev )
                {
                    delete prev->next;
                    prev->next = anzeiger;
                }
                else
                {
                    delete E;
                    E = anzeiger;
                }
                --pos;
            }
        }
    }
    

    Es wird auch jeweils der Vorgänger 'next' immer aktualisiert, wenn ein Element aus der Liste entfernt wird.

    Ansonsten benutzte besser std::list<>, dann hast Du diese Probleme erst gar nicht.

    Gruß
    Werner



  • Hallo!

    Danke für deine Antwort.
    Ich habe mal meine Funktion aktuallsisiert, damit ichs mal selbst gemacht hab, das Hauptproblem war ja, dass der jeweilige Anzeiger falsch gesetzt wurde, und das ist jetzt raus:

    void explosionen::anz()
    {
      if (pos>0)
      {
        explosion *anzeiger, *temp;
        temp = E;anzeiger=E;
        while (anzeiger!=0)
        {
          if (temp->gibstatus()<20)//Wenn noch nicht alle Frames angezeigt sind..
          {
            R->anzrs(G[temp->gibstatus()].graphikid, temp->gibx(), temp->giby());
            //Anzeigeklasse aufrufen
            temp->anz();//setze Status hoch und neue Koordinaten
    
            anzeiger = temp->next;
            temp = anzeiger;
          }
          else
          {
    
            if (pos>1)
            {
              //Element löschen, da ich mich von Anfang durchhangel -> erstpointer kann umgesetzt werden
              explosion *neuE;//Element nach E, das auf E geschoben werden soll
              neuE = E->next;//Element nach E wird zugewiesen
              delete E;//E wird gelöscht
              E = neuE;//Element nach E wird zugewiesen
              anzeiger = E; temp = anzeiger;
    
            }
            else
            {
              //falls nur eine Exlosion läuft (->nur E gesetzt ist)
              temp->next=0;anzeiger=0; // damit aus whileschleife rausgesprungen wird
              delete E;//löschen der einen Explosion
            }
            pos--;//Position wird 1 weniger, da Anzahl um 1 gesunken
          }
    
        }
      }
    }
    

Anmelden zum Antworten