C++ Problem mit Klasse

RonZ

Lt. Junior Grade
Registriert
Aug. 2005
Beiträge
260
Hallo Gemeinde,
es geht um ein Projekt zu einem genetischen Algorithmus.
Und zwar habe ich zu diesem Zweck eine Klasse "Indi" erstellt, die sämtliche Angaben zum einzelnen Individuum enthält:

PHP:
//globale Variablen

int SIZE(5);
int Gnummer(1);
long fit_summe(0);

class Indi
{
	private:	
                int nummer; 
                char bin[*/ Warum kann ich hier die Größe nicht mit Variable SIZE definieren? */];  
                int gendezwert;
                int const_genwert;
                int fitness;

	public:
    		Indi();
    		void Draw();
};

Indi::Indi()
{  
	int obergrenze(0);
   	nummer=Gnummer++;
   	obergrenze = bin_stellen_wertigkeit(SIZE);
	gendezwert = random(obergrenze,nummer);
        // Funktion random() gibt an gendezwert z.B.17 zurück
        const_genwert=gendezwert; 
	dez_bin(const_genwert,SIZE,bin);
        // Paradoxerweise: ab hier ist gendezwert = 3204342 o.ä.

	fitness= fitnessfkt(const_genwert);
	fit_summe = fit_summe + fitness;

}

void Indi::Draw()
{  
	cout<<setw(6)<<nummer<<setw(6);
   	for(int i=0;i<=SIZE;i++){cout<<bin[i];};
   	cout<<setw(8)<<const_genwert<<setw(6)<<fitness<<"\n";

}

Meine Probleme liegen beim Verständis darin, dass man die Größe eines Arrays ausserhalb einer Klasse mit einer Variable bestimmen kann, innerhalb aber nicht ?
Ich habe auch keine Ahnung wieso er im obigen Beispiel die Variable "gendezwert" beliebig ändert.
Und genauso frag ich mich, warum in der Memberfkt. Draw(), wenn das Genom 4 Zeichen lang ist, die Variable "gendezwert" immer 0 ist, obwohl bei Länge 3 die Zufallswerte drinstehen?

Wenn ihr mir weiterhelfen könntet, wäre ich euch richtig dankbar, denn ich weiß nichmehr weiter ..

Um das Phänomen besser nachzuvollziehen, hier nochmal der komplette Quelltext zum selberkompilieren:

PHP:
#include <time.h>

#include <iostream>

#include <iomanip>

#include <string>

#include <stdlib.h>



#include <cmath>

#include <cstdlib>

using std::cout;

using std::endl;

using std::string;

using namespace std;


//ermittelt Obergrenze der darstellbaren Zahl des Binärtrings-> an random übergeben

int bin_stellen_wertigkeit(int stellen)

{   
	int erg(1);

	for(int i = 0;i < stellen;i++)	{erg = erg*2;}
	erg--;
	cout << "aus Werigkeitsfkt: "<< erg << endl;
 	return erg;

}


//erstellt eine zufällige Zahl für den späteren Binärcode-> an dez_bin übergeben    

int random(int obergrenz,int nummer)

{
	nummer++;	
	int x(1),y(1),z(1),z2(1);

     int t1 = time(0)*nummer;

     int t2 = (time(0)+56789)*nummer;

     srand(t1);

     x = (rand()%10);

     srand(t2);

     y = (rand()%20);

     z = (x*y*nummer);

     srand(z);

     z2 = (rand()%obergrenz)+1;

     cout<<"z2="<<z2<<"\n";

     return z2;

}

 



  //übergebene dezimalzahl als binärstring in array bin[]

void dez_bin(int dez, int stellen, char bin[])

{    	
	int r(0);  

     char temp[stellen];

     bin[0] = '\0';

     while(dez > 0)

        {    r = dez%2;

            (r==0) ? strcpy(temp,"0") : strcpy(temp,"1");  

            strcat(temp,bin);

            strcpy(bin,temp); 

            dez /= 2;

        }



        int b = strlen(bin);

        if(b<stellen)

        {   int h = (stellen - b);

            char zw[10000];	

            for(int m(0);m<stellen;m++)

            {zw[m]='\0';

            }//MIT NULLEN FÜLLEN

            for(int j=0;j<h;j++)

            {zw[j]='0';   

            }//REST DER BINÄRZAHL bin AN zw ANHÄNGEN UND INHALT VON zw IN bin ÜBERSCHREIBEN

            strcat(zw,bin);

            strcpy(bin,zw);



        }

}
//-------------------------------------------------

int fitnessfkt(int x)	{return (x*x);}

//-------------------------------------------------


void PrintTabellenkopf()

{

   cout << "Nummer"<< setw(12)<<"Gen-String" << setw(8)<<"x-Wert" << setw(17)<<"Fitness f(x)=x*x" << setw(8)<<"W.keit" << setw(8)<<"E-Wert" << setw(18)<<"Rundung-neueAnz.\n";

   cout << "------------------------------------------------------------------------------\n" ;

} 

//globale Variablen

int SIZE(1);

int Gnummer(1);
long fit_summe(0);


// Klassendefinition

class Indi

{
	private:	
		int nummer; 

          char bin[];      

          int gendezwert;
		int const_genwert;

          int fitness;

	public:

    		Indi();

   		//~Indi();   

    		void Draw();

};

// Definition der Memberfunktionen
// Konstruktor

Indi::Indi()

{  
	int obergrenze(0);

   	nummer=Gnummer++;

   	obergrenze = bin_stellen_wertigkeit(SIZE);

	gendezwert = random(obergrenze,nummer);
	const_genwert=gendezwert;

	dez_bin(const_genwert,SIZE,bin);  

	fitness= fitnessfkt(const_genwert);
	fit_summe = fit_summe + fitness;

}


void Indi::Draw()

{  
	cout<<setw(6)<<nummer<<setw(6);

   	for(int i=0;i<=SIZE;i++){cout<<bin[i];};

   	cout<<setw(8)<<const_genwert<<setw(6)<<fitness<<"\n";

}

// Destruktor

/*Indi::~Indi()

{   delete [] pIndArray;

}

*/



   



// Hauptprogramm

// =============

int main()

{   
	int anzahl(0);

    	cout<<"Wieviele Individuen?";

    	cin>>anzahl;

    	cout<<"Wieviele Gene?";

    	cin>>SIZE;

    	Indi *pIndArray = new Indi[anzahl];

    	PrintTabellenkopf();
	//pIndArray[].Draw(anzahl);
	

    	for(int i=0;i<anzahl;i++){pIndArray[i].Draw();};
	cout << fit_summe << endl; 

   	// PrintTabellenfuss(pIndArray, anzahl);   

    	system("PAUSE");

	return 0;

}

Vielen Dank!
 
Wenn du ein dynamisches Array willst musst du es mit new[] anlegen (und mit delete[] wieder freigeben), statische Arrays kannst du nur mit einer (zur compile-Zeit) konstanten Größe erstellen.

Dass sich gendezwert "zufällig" verändert liegt wohl daran, dass es nach bin (für das du keinen Speicher reservierst) definiert ist und du somit bei den Zugriffen auf bin wild im Speicher rumschreibst.

In VS 2008 kompiliert dein Code übrigens (unter anderem aus obigen Gründen) nicht.
 
Ok, das ist schonmal ein Ansatz. Nur klappt das so auch nicht, denn der g++ - Compiler meint:
Code:
genom.cpp:102: Fehler: `new' kann nicht in einem Konstanten-Ausdruck auftreten
genom.cpp:102: Fehler: ISO-C++ verbietet Initialisierung des Elementes »bin«
genom.cpp:102: Fehler: »bin« wird statisch gemacht
genom.cpp:102: Fehler: ungültige Initialisierung innerhalb der Klasse des statischen Datenelements vom nicht eingebauten Typen »char*«

Die Klasse jetzt:

PHP:
//globale Variablen

int SIZE(5);

int Gnummer(1);
long fit_summe(0);



// Klassendefinition

class Indi

{
	private:	
		int nummer; 

          char *bin = new char[SIZE];      

          int gendezwert;

          int fitness;

	public:

    		Indi();

   		~Indi();   

    		void Draw();

};





// Definition der Memberfunktionen

// Konstruktor

Indi::Indi()

{  
	int obergrenze(0);

   	nummer=Gnummer++;

   	obergrenze = bin_stellen_wertigkeit(SIZE);

	gendezwert = random(obergrenze,nummer);

	dez_bin(gendezwert,SIZE,bin);  

	fitness= fitnessfkt(gendezwert);
	fit_summe = fit_summe + fitness;

}



void Indi::Draw()

{  
	cout<<setw(6)<<nummer<<setw(6);

   	for(int i=0;i<=SIZE;i++){cout<<bin[i];};

   	cout<<setw(8)<<gendezwert<<setw(6)<<fitness<<"\n";

}

// Destruktor

Indi::~Indi()

{
	delete [] bin;

}

Ist das Problem formaler Natur, oder hab ich da etwas mit der Klassen- oder Felddeklaration missverstanden?

Danke schonmal für deine Gedult :)
 
Die Reservierung des Speichers mittels new muss (bzw. sollte) im Konstruktor erfolgen (analog zum delete[] im Destruktor).
 
Und wie bekommen die anderen Members dann Wind von dem Array?

Edit:
Ok, natürlich, indem man den Pointer außerhalb erstellt und innerhalb des Konstruktors initialisiert.

Gut, jetzt hab ich nur noch das Problem, dass ich während der Laufzeit unter Ubuntu eine
Code:
*** glibc detected *** ./a.out: double free or corruption (fasttop): 0x0804b0a0 ***
Meldung ausgegeben bekomme ..

Aber gut, das ist wahrscheinlich jetzt zu spezifisch ..

Auf jedenfall bin ich dir für deine Mühe richtig Dankbar!
 
Zuletzt bearbeitet:
Poste nochmal deinen (neuen) Code. Wie die Fehlermeldung schon sagt schreibst du wahrscheinlich noch immer irgendwo an der falschen Stelle in den Speicher (z.B. über die Grenzen des Arrays hinaus) oder du gibst den Speicher mehrmals frei.
 
Genau! Er muss irgendwo den delete auf einen verlorenen Zeiger anwenden. Allerdings weiß ich nicht, wie ich das dynamische Array so löschen kann, dass ich zwischendurch noch damit arbeiten kann.

PHP:
//---------------------------------------------------------------------------



#include <time.h>

#include <iostream>

#include <iomanip>

#include <string>

#include <stdlib.h>



#include <cmath>

#include <cstdlib>

using std::cout;

using std::endl;

using std::string;

using namespace std;



//PROTOTYPEN

//ermittelt Obergrenze der darstellbaren Zahl des Binärtrings-> an random übergeben

int bin_stellen_wertigkeit(int stellen)

{   
	int erg(1);

	for(int i = 0;i < stellen;i++)	{erg = erg*2;}
	erg--;
	cout << "aus Werigkeitsfkt: "<< erg << endl;
 	return erg;

}


//erstellt eine zufällige Zahl für den späteren Binärcode-> an dez_bin übergeben    

int random(int obergrenz,int nummer)

{
	nummer++;	
	int x(1),y(1),z(1),z2(1);

     int t1 = time(0)*nummer;

     int t2 = (time(0)+56789)*nummer;

     srand(t1);

     x = (rand()%10);

     srand(t2);

     y = (rand()%20);

     z = (x*y*nummer);

     srand(z);

     z2 = (rand()%obergrenz)+1;

     cout<<"z2="<<z2<<"\n";

     return z2;

}

 



  //übergebene dezimalzahl als binärstring in array bin[]

void dez_bin(int dez, int stellen, char bin[])

{    	
	int r(0);  

     char temp[stellen];

     bin[0] = '\0';

     while(dez > 0)

        {    r = dez%2;

            (r==0) ? strcpy(temp,"0") : strcpy(temp,"1");  

            strcat(temp,bin);

            strcpy(bin,temp); 

            dez /= 2;

        }



        int b = strlen(bin);

        if(b<stellen)

        {   int h = (stellen - b);

            char zw[10000];	

            for(int m(0);m<stellen;m++)

            {zw[m]='\0';

            }//MIT NULLEN FÜLLEN

            for(int j=0;j<h;j++)

            {zw[j]='0';   

            }//REST DER BINÄRZAHL bin AN zw ANHÄNGEN UND INHALT VON zw IN bin ÜBERSCHREIBEN

            strcat(zw,bin);

            strcpy(bin,zw);



        }

}
//-------------------------------------------------

int fitnessfkt(int x)	{return (x*x);}

//--------------------------------------------------



void PrintTabellenkopf()

{

   cout << "Nummer"<< setw(12)<<"Gen-String" << setw(8)<<"x-Wert" << setw(17)<<"Fitness f(x)=x*x" << setw(8)<<"W.keit" << setw(8)<<"E-Wert" << setw(18)<<"Rundung-neueAnz.\n";

   cout << "------------------------------------------------------------------------------\n" ;

} 



/*void PrintTabellenfuss(Indi* pIndArray,int anzahl)

{   cout << "------------------------------------------g------------------------------------\n" ;

    cout << "Summe"<< setw(58);

    for(int i;i<anzahl;i++){cout<<pIndArray[i].fitness;

} 

*/



//globale Variablen

int SIZE(1);

int Gnummer(1);
long fit_summe(0);



// Klassendefinition

class Indi

{
	private:	
		char *bin;
		int nummer;       

          int gendezwert;

          int fitness;

	public:

    		Indi();

   		~Indi();   

    		void Draw();

};

	Indi::Indi()

	{  
		bin = new char[SIZE];
		int obergrenze(0);

   		nummer=Gnummer++;

   		obergrenze = bin_stellen_wertigkeit(SIZE);

		gendezwert = random(obergrenze,nummer);

		dez_bin(gendezwert,SIZE,bin);  

		fitness= fitnessfkt(gendezwert);
		fit_summe = fit_summe + fitness;

	}



	void Indi::Draw()

	{  
		cout<<setw(6)<<nummer<<setw(6);

   		for(int i=0;i<=SIZE;i++){cout<<bin[i];};

   		cout<<setw(8)<<gendezwert<<setw(6)<<fitness<<"\n";

	}

	// Destruktor

	Indi::~Indi()

	{
		delete [] bin;

	}




   



// Hauptprogramm

// =============

int main()

{   
	int anzahl(0);

    	cout<<"Wieviele Individuen?";

    	cin>>anzahl;

    	cout<<"Wieviele Gene?";

    	cin>>SIZE;

    	Indi *pIndArray = new Indi[anzahl];

    	PrintTabellenkopf();
	//pIndArray[].Draw(anzahl);
	

    	for(int i=0;i<anzahl;i++)
	{
		pIndArray[i].Draw();
		pIndArray[i].~Indi();		
	}
	cout << fit_summe << endl; 

   	// PrintTabellenfuss(pIndArray, anzahl);
	delete [] pIndArray;

    	//system("PAUSE");

	return 0;

}
 
Du belegst für deine Arrays zu wenig Speicher (vermutlich hast du die abschließende 0 vergessen), ein Zeichen mehr und das Problem sollte gelöst sein. Noch einfacher und sinnvoller wäre es natürlich wenn du einfach die string Klasse anstelle von char Arrays verwenden würdest, dann könnte deine dez_bin Funktion zum Beispiel einfach so aussehen:
PHP:
string dez_bin(unsigned int dez, int stellen)
{
	string temp;

	for (int i = stellen - 1; i >= 0; --i)
		temp += ((dez >> i) & 1) ? "1" : "0";

	return temp;
}

Code:
pIndArray[i].~Indi();
Ist einfach nur "böse", du solltest wirklich so gut wie nie selbst einen Destruktor aufrufen. Insbesondere weil "delete [] pIndArray;" das für dich erledigt und du somit alle deine Destruktoren zweimal aufrufst.

Übrigens solltest du dir auch angewöhnen deinen Code "richtig" zu formatieren (Einrücken, Leerzeilen, ...), so wie du ihn hier postest ist er fast unleserlich.

Mehrfache Aufrufe von srand() in einem Programm sind auch nicht so toll, ein Aufruf der Form " srand(time(NULL));" zu Beginn reicht vollkommen.
 
Sehr schön. Ich hab deine Empfehlungen beherzigt, den Typ char über den Haufen geschmissen, und den Stil angepasst und die Random-Funktion kommt auch nur noch mit einem srand() aus. Außerdem ist die Idee mit den binären Opperatoren eine wahnsinnige Bereicherung. Da spart man locker mal 20 Zeilen / Fkt. :)

Den Fehler hab ich beseitigt, jetzt wird nur noch zum Schluss das pIndArray deletet. Das klappt ohne Murren. Und man kommt ohne Destruktor aus, soweit ich das überblicke ?!

Nochmals schönen Dank für deine Hilfe! Jetzt müssen die Genome noch gekreuzt werden, Es bleibt spannend. :)
 
RonZ schrieb:
Und man kommt ohne Destruktor aus, soweit ich das überblicke ?!

Leicht vereinfacht:
Für Objekte auf dem Stack (also alle die nicht mittles new erzeugt wurden) wird der Destruktor automatisch bei Verlassen des Gültigkeitsbereichs aufgerufen.
Für die Objekte auf dem Heap (also alle mit new angelegten) wird der Destruktor beim Aufruf von delete aufgerufen.
Solange du also allen mit new belegten Speicher schön brav mittels delete wieder freigibst sorgt der compiler dafür, dass deine Destruktoren aufgerufen werden.

RonZ schrieb:
Jetzt müssen die Genome noch gekreuzt werden, Es bleibt spannend. :)
Viel Erfolg :) Wenn du fertig bist kannst du das Ergebnis ja hier posten damit man sieht, dass die Mühen nicht umsonst waren ;)
 
Zurück
Oben