Forum: PC-Programmierung Zeiger zeigt nicht mehr auf Array


von Sam .. (sam1994)


Lesenswert?

Hallo

Ich habe in meinem Projekt eine struct die ein Array (unsigned short**) 
enthält, welches zur Laufzeit generiert wird. Danach wird es bis zur 
Zerstörung nicht mehr verändert. Eine andere struct bekommt einen Zeiger 
der 2. Dimension des Arrays als Argument im Konstruktor übergeben.

bloons ist die struct welche das Array enthält.
1
Bloon(0,bloons->ways[0]);

Im Konstruktor werden die richtigen Arraywerte ausgelesen.
1
Bloon::Bloon(int SLevel, unsigned short* SWay)
2
{
3
    level = SLevel;
4
    way = SWay;
5
    x = (way[0] & 0xFF) * TILE_WIDTH;
6
    y = ((way[0] >> 8) & 0xFF) * TILE_HEIGHT;
7
    speed = 10;
8
    printf("%d, %d\n", (way[1]>>8) & 0xFF, way[1] & 0xFF);
9
}

Jetzt kommt das Problem. Die Updateroutine, welche regelmäßig aufgerufen 
wird, greift anscheinend nicht auf das Array zu obwohl dieses in der 
struct gespeichert worden ist. Die Testausgabe per printf bringt das 
Programm zum Absturz, ohne stürzt das PRogramm nur manchmal ab, die 
Updateroutine funktioniert aber nicht, da die Werte nicht stimmen.
1
void Bloon::Update(double dt)
2
{
3
    if((way[1] - way[0]) & 0xFF)    //Bewegung in X-Richtung
4
        x += dt * speed;   
5
    if((way[1] - way[0]) & 0xFF00)  //Bewegung in Y-Richtung
6
        y += dt * speed;
7
    printf("%d, %d", (way[1]>>8) & 0xFF, way[1] & 0xFF);
8
    
9
}

Die festen Arrayindexe sind natürlich nur Testwerte, später werden dafür 
variablen eingesetzt.

Die Zuweisung des Zeigers sollte reichen um später wieder zugreifen zu 
können, anscheinend funktioniert dies aber nur im Konstruktor.

von Karl H. (kbuchegg)


Lesenswert?

Samuel K. schrieb:

> Die Zuweisung des Zeigers sollte reichen um später wieder zugreifen zu
> können, anscheinend funktioniert dies aber nur im Konstruktor.

Da musst du mehr zeigen.
Das Problem scheint nicht in den von dir gezeigten Routinen zu sitzen. 
Es könnte auch überhaupt nichts mit der Bloon Struktur/Klasse an sich zu 
tun haben, sondern ganz wo anders sitzen.

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Das hasse ich an c++: Ein kleiner Fehler, der erst hunderte Zeilen Code 
später auftritt.

Ich vermute das es mit den dynamischen Arrays zu tun haben muss, da es 
ein Speicherfehler sein müsste. Blöd ist nur, dass die structs alle von 
einander abhängen, d.h. den Fehler durch auskommentieren geht nicht so 
einfach.

Anbei alle Dateien welche dynamische Arrays enthalten, das sind einmal 
die Bloons.cpp/h und die world.cpp/h.
Das 2 dimensionale way[][] Array wird in Bloonlist::load_world erzeugt, 
das andere (map[]) in World::open.

Das Bloon-Testobjekt wird in Bloonlist::list (vom type std::list) 
gespeichert und wird so eingefügt:
1
bloons->list.push_back(Bloon(0,bloons->ways[0]));

Gibt es eigentlich Programme, die den Speicher eines Programmes zur 
Laufzeit überwachen und Fehler bemerken?

von Ano (Gast)


Lesenswert?

valgrind kann da einiges analysieren, wenn ich mich noch richtig 
entsinne.

von Karl H. (kbuchegg)


Lesenswert?

Samuel K. schrieb:

> Das hasse ich an c++: Ein kleiner Fehler, der erst hunderte Zeilen Code
> später auftritt.

Im Normalfall ist es eher umgekehrt.
Bei entsprechender Programmierdisziplin ist das kein Thema.

>
> Ich vermute das es mit den dynamischen Arrays zu tun haben muss, da es
> ein Speicherfehler sein müsste. Blöd ist nur, dass die structs alle von
> einander abhängen,

eben.
Sowas ist meistens eher schlecht.

> Anbei alle Dateien welche dynamische Arrays enthalten, das sind einmal
> die Bloons.cpp/h und die world.cpp/h.

World ist in Ordnung.
Bloon sieht auch soweit gut aus.

Du hast doch die Zwischenausgaben kontrolliert, ob du da eine ungültige 
Anzahl angetroffen hast.

> gespeichert und wird so eingefügt:
>
1
bloons->list.push_back(Bloon(0,bloons->ways[0]));

Wo wird das gemacht?

warum macht das nicht die Bloonlist Klasse selber?

Gewöhn dir ab, dass du public Variablen hast. Wie ein Objekt intern 
aussieht geht ausserhalb einer Klasse niemand etwas an. Solange du das 
nicht beherzigst, wirst du derartige seltsame Zusammenhänge nie 
loswerden. Du musst schon C++ programmieren, wenn du C++ programmierst 
und nicht nur C++ als einen besseren C Compiler verwenden.

In der delete Methode der Bloonlist Klasse musst du noch:
die Pointer wieder auf 0 setzen. Die Liste ausleeren. Sonst hat deine 
Liste Bloon Objekte, die auf Speicher in Bloonlist verweisen, den es 
nicht mehr gibt.

> Gibt es eigentlich Programme, die den Speicher eines Programmes zur
> Laufzeit überwachen und Fehler bemerken?

Gibt es.

von Karl H. (kbuchegg)


Lesenswert?

Was du auch noch tun müsstest.

Die Copy Konstruktoren bzw. die Zuweisungsoperatoren beider Klassen 
unbrauchbar machen, damit du sie nicht aus versehen irgendwo benutzen 
kannst.

Im Moment machen sie das falsche (und könnten zu deinem Problem führen)
1
struct Bloonlist
2
{
3
    Bloonlist(void);
4
    ~Bloonlist(void);
5
    void load_world(const char* filename);
6
    void delete_world(void);
7
    void Update(double dt);
8
    void Draw(int vx, int vy);
9
    
10
    ALLEGRO_BITMAP* bitmap;
11
    std::list<Bloon> list;
12
    unsigned char waycount;
13
    unsigned short** ways;
14
    unsigned char* waylen;
15
16
  private:
17
    Bloonlist( const Bloonlist& rhs);            // nicht implementieren!
18
    Bloonlist operator=( const Bloonlist& rhs);  // nicht implementieren!
19
};

Für World dasselbe.

Wenn du danach einen Compiler oder Linker Fehler hast, hast du deine 
Problemstelle. Wenn nicht, geht die Suche weiter.

von Karl H. (kbuchegg)


Lesenswert?

Gibt es einen Grund, warum ein Bloon nicht seinen Weg selber hält, 
sondern die Wege in Bloonlist gespeichert sind?

Normalerweise ist das keine gute Idee. Lass jede Klasse ihre Daten für 
sich halten. Aber auch wirklich für sich! Von ausserhalb einer Klasse 
hat niemand direkten Zugriff auf die Daten.

So wirst du dann auch ganz von alleine die Abhängigkeiten der Klassen 
voneinenader los, die dir momentan das Leben schwer machen.

von Sam .. (sam1994)


Angehängte Dateien:

Lesenswert?

Karl Heinz Buchegger schrieb:
> Du hast doch die Zwischenausgaben kontrolliert, ob du da eine ungültige
> Anzahl angetroffen hast.

Diese Ausgaben stimmen alle, die Dateien werden richtig eingelesen, die 
Arrays mit den richtigen Werten gefüllt, es werden keine Fehler 
ausgegeben. Das Programm gibt erst falsche Ausgaben in der Bloon::Update 
Funktion aus, wenn es nicht vorher abstürzt.

Karl Heinz Buchegger schrieb:
> bloons->list.push_back(Bloon(0,bloons->ways[0]));
> Wo wird das gemacht?
>
> warum macht das nicht die Bloonlist Klasse selber?

Die Funktion dafür werde ich später implementieren - ich habe mir 
angewöhnt zum Testen die structs aus dem Hauptprogramm heraus zu 
manipulieren, damit man schon früher Fehler findet.

Das wird übrigens in der Game.cpp in der Hauptroutine gemacht. Die 
sollte allerdings eher uninteressant sein. Die Initialisierungen der 
Daten wird am Ende des Kontruktors gemacht.

Außer Utils.cpp/h (enthält nur eine load_bitmap-Funktion mit 
Fehlerbehandlung) und main.cpp (lädt Konfiguration und übergibt sie an 
die Game-struct) gibt es keine Dateien mehr.

Karl Heinz Buchegger schrieb:
> Für World dasselbe.
>
> Wenn du danach einen Compiler oder Linker Fehler hast, hast du deine
> Problemstelle. Wenn nicht, geht die Suche weiter.

Habe ich gemacht, compiliert sich ohne Probleme.

Karl Heinz Buchegger schrieb:
> Gibt es einen Grund, warum ein Bloon nicht seinen Weg selber hält,
> sondern die Wege in Bloonlist gespeichert sind?

Das Problem ist, das es auf den Karten nur wenigen Wege gibt, aber sehr 
viele Bloons, ich glaube in diesem Fall ist es geschickter die 
Wegbeschreibung extern zu speichern. Im Prinzip wäre es egal, da bei 
selbst 1000 Bloons mit 100Byte mehr Rambedarf speichertechnisch nicht 
ins Gewicht fallen würden.

von Karl H. (kbuchegg)


Lesenswert?

Game braucht auch einen gesperrten Copy Konstr./Assignment Op

Hmm. Wenn du nicht irgendwo eine unbeabsichtigte Objektkopie gemacht 
hast (vergessene Referenz in einer Argumentliste) sehe ich beim reinen 
drüberlesen keinen Fehler.

Lass dir mal die entsprechenden Pointer ausgeben und gib in 
Konstruktor/Destruktor entsprechende Ausgaben rein um den Ablauf 
verfolgen zu können.

von Sam .. (sam1994)


Lesenswert?

Wenn ich in der Game.cpp das Testobjekt mit einem festen Array 
initialisieren, funktioniert es:
1
static unsigned short test[] = {0x0200,0x0207,0x0907,0x090A};
2
bloons->list.push_back(Bloon(0,test/*bloons->ways[0]*/));

Hier sind es nur 4 xy-Paare, in der Datei sind es maximal 8 pro Weg (auf 
der kleinen Testkarte).
Natürlich könnte man die 16 Byte auch in die Bloonsstruct reinpacken, 
aber ich denke es ist wichtiger den Fehler zu finden, als um ihn herum 
zu programmieren.

Ich werde morgen ein bisschen mehr mit den Debugausgaben spielen - 
Problem ist bei mir, dass der Debugger in MS VS nicht mehr funktioniert, 
ich in Codeblocks Allegro5 nicht eingerichtet bekomme und in DevC++ der 
Debugger schrott ist. Also wird es bei der Console bleiben.


edit:

Ich weiß echt nicht was ich gemacht habe (ich wüsste auch nicht was), 
nachdem ich die Testzeilen mit externem Array wieder auskommentiert habe 
um den Fehler ein letztes mal zu sehen, hat es plötzlich funktioniert. 
Ich weiß nicht warum.

von Karl H. (kbuchegg)


Lesenswert?

Samuel K. schrieb:

> ich in Codeblocks Allegro5 nicht eingerichtet bekomme und in DevC++ der
> Debugger schrott ist. Also wird es bei der Console bleiben.

Pointer Werte kann man mit %p im printf ausgeben lassen.


Wenn ich ein Allegro da hätte, hätte ich das alles mal compiliert und 
laufen gelassen. Aber extra installieren werd ich es nicht.

von Sam .. (sam1994)


Lesenswert?

Karl Heinz Buchegger schrieb:
> Wenn ich ein Allegro da hätte, hätte ich das alles mal compiliert und
> laufen gelassen. Aber extra installieren werd ich es nicht.

Unter DevC++ ist es recht einfach, da es dafür ein Package gibt, leider 
haben die das auf einem externem Hoster hochgeladen, so dass der 
Downloadmanager es nicht schafft die Datei selbst herunterzuladen. Das 
manuelle intstallieren dauert aber auch nicht lange.

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.