Mr. Miyagi Geschrieben 13. November 2008 Geschrieben 13. November 2008 (bearbeitet) Hallo, wieder ein weiteres Problem das mich in meiner anfänglichen Zeit überfordert. Ich habe folgende Struktur: Hauptprogramm -> externe Klasse (Header u. Rumpf seperat) -> einmalige(!) Berechnungen der Konstruktionsdaten im Array speichern -> Arraydaten sollen nach dem einmaligen Aufruf des If Blocks weiter verwendet werden zum zeichnen eines Objekts -> Rückkehr zum Hauptprogramm ... Buffer leeren und auf Bildschirm ausgeben. (und wieder von vorne) Mein Problem sind nun die Daten in dem Array. In Delphi hab ich globale, dynamische Arrays angegeben dessen Größe und Werte nur einmal zur Laufzeit per if(done == false) ... ...Berechnungen... ... Ende des Blocks ... (done = true) berechnet werden und danach griff die Zeichenroutine immer wieder auf die Werte im Array zurück. Das Problem ist ja das die Variablen in C++ die in einen Anweisungsblock deklariert wurden ja nur für diesen gelten. Hab da was mit Zeigern gelesen und die Werte im Heap speichern, aber da blick ich noch nicht so ganz durch und ich wollte es vermeiden ein Array vorher im Hauptprogramm zu deklarieren. Wie gehe ich nun am besten ran an mein Problem? Noch was: Wenn ich eine kleine Testroutine in die Klasse schreibe die mir nur ein Viereck zurückgeben soll muss ich auch einen Pointer auf die Klasse angeben da mir das Programm, wenn ich eine Variable verwende, nur einen Grafikfehler ausgibt. Wie ist das zu erklären? Danke schonmal für eure Hilfe. Bearbeitet 13. November 2008 von Mr. Miyagi Syntaxfehler Zitieren
Mr. Miyagi Geschrieben 14. November 2008 Autor Geschrieben 14. November 2008 Da niemand antwortet, habe ich mich bestimmt nur umständlich ausgedrückt. Was ich machen will: Ich will in einer Klasse ein Array erstellen. Man übergibt Werte durch eine Funktion, die dann zur Größenbestimmung des Arrays dienen (nicht das Problem). Danach wird das Array einmalig(!) mit Daten gefüllt. Nun ruft eine andere Funktion (in einer Endlosschleife) immer wieder die Daten aus dem Speicher ab. Die Schleife wird erst durch Tastendruck beendet. Meine Lösungsidee: Ich erstelle das Array im Heap und die Funktion die, die Daten braucht bekommt sie über Zeiger auf die Werte. Mein Problem: Wie würde der Syntax dazu aussehen und vorallem, warum ?! Ich habe zwar C++ in 21 Tagen, aber das behandelt Zeiger und Arrays seperat und damit kenne ich keine Kombination aus beiden. Zitieren
Klotzkopp Geschrieben 14. November 2008 Geschrieben 14. November 2008 In C++ solltest du Arrays nach Möglichkeit vermeiden. Meistens ist es besser, std::vector zu benutzen. Diese Klasse stellt einen zusammenhängenden Speicher für Objekte desselben Typs bereit, kann dynamisch wachsen und kümmert sich selbst um die Speicherverwaltung. Zitieren
Mr. Miyagi Geschrieben 14. November 2008 Autor Geschrieben 14. November 2008 Danke für deine Information. Ich kenne mich zwar überhaupt nicht aus mit std::vector, aber ich versuche mal etwas im Internet dazu zu finden. Ist Vector, wenn ich Daten hinein schreibe dann im Heap abgelegt ? Mir geht es ja darum, dass ich ich die Klasse in der das Array erstellt wird von "außen" aufrufe, es erstelle, mit Daten fülle, zum Hauptprogramm zurück kehre und dann durch eine Endlosschleife nur wieder die Daten abfrage. Oder sind die Daten nach Aufruf der Funktion aus der Klasse und Rückkehr zum Hauptprogramm durch den Destructor wieder gelöscht ? Zitieren
Klotzkopp Geschrieben 14. November 2008 Geschrieben 14. November 2008 Ist Vector, wenn ich Daten hinein schreibe dann im Heap abgelegt ? Mir geht es ja darum, dass ich ich die Klasse in der das Array erstellt wird von "außen" aufrufe, es erstelle, mit Daten fülle, zum Hauptprogramm zurück kehre und dann durch eine Endlosschleife nur wieder die Daten abfrage. Ein Vector legt seine Daten im Free Store ab, solange du nichts anderes festlegst. Der Free Store entspricht dem Heap in C. Viele Compiler unterscheiden das gar nicht. Die Lebenszeit der Objekte ist aber an die Lebenszeit des Vector gekoppelt. Wenn der Vector allerdings ein Member deiner Klasse ist, existiert er so lange, wie die Instanz der Klasse existiert. Zitieren
Mr. Miyagi Geschrieben 14. November 2008 Autor Geschrieben 14. November 2008 Da ich mal annehme das die Instanz einer Klasse sich genauso verhällt wie eine lokale Variable. Sprich nur für den Anweisungsblock in dem sie deklariert ist auch gültig ist, werde ich da keine weiteren Probleme haben. (hoffe ich zumindest ^^) Falls meine Annahme nicht richtig ist, berichtigt mich bitte. Es könnte ja auch sein, dass die Instanz erst ihre Gültigkeit verliert in dem man explizit den Destructor aufruft. Ansonsten sag ich schon mal Danke. Zitieren
Klotzkopp Geschrieben 14. November 2008 Geschrieben 14. November 2008 Wenn du eine Instanz einer Klasse als lokale Variable anlegt, dann verliert sie ihre Lebenszeit, wenn der Block, in dem sie definiert ist, beendet ist. Wenn du die Instanz mit new anlegst, endet ihre Lebenszeit, wenn du delete aufrufst. Es könnte ja auch sein, dass die Instanz erst ihre Gültigkeit verliert in dem man explizit den Destructor aufruft. Das macht man eigentlich nie. Den Destruktor darf man nur dann explizit aufrufen, wenn man placement-new benutzt hat, um die Instanz zu erzeugen. Zitieren
AndiE Geschrieben 18. November 2008 Geschrieben 18. November 2008 Könntest du dich etwas präziser ausdrücken. Wenn ich dich richtig verstanden habe, würde ich dies vorschlagen: Wenn du die Kapselung konsequent anwendest, ist das Array nur über die beiden Lese- und Schreibfunktionen manipulierbar. Das Feld, in dem du die Daten abspeicherst, kannst du im Konstruktor allokieren(Speicherplatz festlegen), und im Destruktor wieder freigeben. VC++ erlaubt auch Konstruktoren mit Argumenten. Das ist ein Beispiel in VC++ /* header */ class daten { public: daten(); daten(int groesse) ~daten(); private: int* zeiger; public: void ErstelleDaten(int groesse); void ZerstoereDaten(); int LeseDaten(int pos); void SchreibeDaten(int pos, int zahl); }; daten : daten() { } daten : daten(int groese) { zeiger=malloc(groesse); /Nur Anhalt malloc muß nicht stimmen! } daten:~daten() { free(zeiger); } Das wendest du dann so an: main() { int eingabe; daten feld; / Datenfeld lebt solange wie main() int anzahl; do { anzahl=feldgroesse(); feld.ErstelleDaten(anzahl); Dateneingeben(feld); Zeichen(feld); feld.ZerstoereDaten(); printf("Nochmal?(0/1); eingabe=getch(); } while(eingabe!=0); } Das sollte es in etwa sein. LG Andre' Zitieren
Mr. Miyagi Geschrieben 23. November 2008 Autor Geschrieben 23. November 2008 Danke, hab das Problem schon genauso gelöst. ^^ Nun hab ich aber ein anderes Problem. Ich kann meine Zeiger und Variablen nur Global deklarieren. Wenn ich sie im privaten Teil der Klasse deklariere, kennt meine Cpp Datei dazu zwar die Variablen und schreibt auch die richtigen Werte in diese, nur kann ich diese dann nicht verwenden. Immer wenn ich es versuche, dann blitzt kurz mein Fenster auf und ist auch gleich wieder weg. einfaches Beispiel if (done==FALSE) { ... } Dann wird das Programm einfach beendet obwohl done eine boolischer Variable ist und ich vorher in einer anderen Prozedur done den Wert false zugewiesen habe. Deklariere ich done nun global in der Cpp Datei funktioniert alles super. So gesehen funktioniert also alles. Mein schlaues Buch sagt mir aber, dass man globale Variablen möglichst vermeiden sollte und daran will ich mich auch halten. Zitieren
Klotzkopp Geschrieben 24. November 2008 Geschrieben 24. November 2008 Ohne Code lässt sich da nicht viel machen. Versuch bitte mal, ein kompilierbares Minimalbeispiel zu erstellen, das den Fehler reproduziert. Zitieren
Mr. Miyagi Geschrieben 25. November 2008 Autor Geschrieben 25. November 2008 Ich hab nun ein kleines Beispiel geschrieben in dem das Problem auftritt. Ich habe erst versucht eine normale Klasse zu erstellen, doch die lief einwandfrei. Der Fehler tritt also nur auf wenn ich OpenGL und SDL verwende und dann im Publicteil die Variablen deklariere und versuche diese zu benutzen. Ich hänge einfach mal das Projekt von Code::Blocks an. Dort wird nur ein Vierreck mit einer einfachen Textur gerendert. Hab jeglichen Zusatz weggelassen um es so übersichtlich wie möglich zu halten. Wichtig ist noch zu sagen, dass man auf jedenfall die SDL Bibliotheken braucht um das Projekt überhaupt compilieren zu können. Einmal das normale SDL Developement Paket und SDL Image. Die beiden Pakete sind aber in der Zip enthalten. In Code::Blocks muss man dann im Linker noch folgende Bibliotheken angeben: -lmingw32 -lSDLMain -lSDL -lopengl32 -lglu32 -lSDL_image Hoffe ihr könnt mir helfen. Beispiel.zip Zitieren
Klotzkopp Geschrieben 25. November 2008 Geschrieben 25. November 2008 Das habe ich auch noch nicht erlebt, dass jemand ein Minimalbeispiel von 1,6 MByte abliefert :eek Zum Glück lässt sich das Problem auch leicht erkennen, ohne das Projekt kompilieren zu müssen: Test* use; use->draw(a,move); [/code] Das ist Blödsinn. use ist ein uninitialisierter Zeiger. Du erstellst nirgends ein Objekt der Klasse Test. Der Code verursacht undefiniertes Verhalten, da kann alles passieren. Zitieren
Mr. Miyagi Geschrieben 25. November 2008 Autor Geschrieben 25. November 2008 Das ist nur 1,6 MB groß weil die SDL Bibliothek noch beiliegt. Ich wollte ja nur das Gesuche nach den Dateien vermeiden. Ja ehm. Wenn der Zeiger nicht richtig ist ... was dann? Wie muss ich das denn richtig initialisieren? Ich hoffe mal das der Fehler darauf beruht, aber wenn ich eine Klasse genauso aufrufe die nicht SDL verwendet dann geht das trotzdem. Zitieren
Klotzkopp Geschrieben 25. November 2008 Geschrieben 25. November 2008 Ja ehm. Wenn der Zeiger nicht richtig ist ... was dann? Wie muss ich das denn richtig initialisieren?Du brauchst eine Instanz dieser Klasse. Die solltest du natürlich nicht in deiner Render-Funktion erzeugen, denn dann hättest du ja bei jedem Durchlauf eine neue. Eine Instanz legst du durch Test use; oder, wenn eine Lebenszeit über den enthaltenen Block hinaus erforderlich ist, durch Test* use = new Test; an. Ich hoffe mal das der Fehler darauf beruht, aber wenn ich eine Klasse genauso aufrufe die nicht SDL verwendet dann geht das trotzdem. Das ist das Schöne an undefiniertem Verhalten: Es kann alles passieren. Daraus, dass etwas funktioniert, darfst du nicht folgern, dass der Code richtig ist. Dein uninitialisierter Zeiger zeigt irgendwo in den Speicher. Wenn das Programm dann dort versucht, Werte abzulegen oder auszulesen, kann das zufällig gut gehen oder auch dein Programm abstürzen lassen. Zitieren
Mr. Miyagi Geschrieben 25. November 2008 Autor Geschrieben 25. November 2008 (bearbeitet) Es funktioniert. Es hat tatsächlich am dem undefinierten Pointer gelegen. Das ist das Schöne an undefiniertem Verhalten: Es kann alles passieren. Daraus, dass etwas funktioniert, darfst du nicht folgern, dass der Code richtig ist. Den Satz vergess ich definitiv nicht. ^^ Dann bedanke ich mich nochmal für eure guten Tipps und die Hilfe. mfg Mr. Miyagi Bearbeitet 25. November 2008 von Mr. Miyagi Zitieren
Empfohlene Beiträge
Dein Kommentar
Du kannst jetzt schreiben und Dich später registrieren. Wenn Du ein Konto hast, melde Dich jetzt an, um unter Deinem Benutzernamen zu schreiben.