C++ Game of Life - Speicherzugriffs Fehler

H4ckHunt3r

Erfahrenes Mitglied
Hallo zusammen,
ich habe im moment im Studium eine C++ Aufgabe,
welche von mir verlangt das so genannte
"Game of Life" von J.H.Conway
zu Programmieren.

Dabei wurden uns alle Funktions-Prototypen
sowie 2 Funktionen bereits vorgegeben
(sonst würde ich bool statt int verwenden für das Feld).

Die zu Implementierenden Regeln sind:
1. Eine tote Zelle mit genau drei Nachbarn wird in der nächsten Generation neu geboren.
2. Eine lebende Zelle mit weniger als zwei Nachbarn stirb in der folgenden Generation an Vereinsamung.
3. Eine lebende Zelle mit zwei oder drei Nachbarn bleibt in der folgenden Generation am Leben.
4. Eine lebende Zelle mit mehr als drei Nachbarn stirbt in der folgenden Generation an Überbevölkerung.

Jedoch bekomme ich nachdem das Feld mit der Zufallsbelegung ausgegeben wurde
einen Speicherzugriffsfehler (Speicherabzug geschrieben), wodurch
das Programm natürlich abbricht.

Hier einmal der Code:
C++:
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <iomanip>
#include <ctime>
#include <cassert>

using namespace std;

//----------------------------------------------------------------------
//  TYPE DEFINITIONS
//----------------------------------------------------------------------
typedef unsigned int uint;


//----------------------------------------------------------------------
//  FUNCTION PROTOTYPES
//----------------------------------------------------------------------
void 	zufallsbelegung 		(int **feld, uint hoehe, uint breite);
uint 	next_generation 		(int **feld1, int **feld2, uint breite, uint hoehe);
void 	print_feld 				(int **feld, uint hoehe, uint breite);
int**   new_int_matrix 			(int rows, int columns);
void 	delete_int_matrix 		(int **m);



//----------------------------------------------------------------------
//  Global Vars
//----------------------------------------------------------------------
uint gen = 1;

Die uns vorgegebenen Funktionen:
C++:
// ===  FUNCTION  ======================================================================
//         Name:  new_int_matrix
//  Description:  
// =====================================================================================
int** new_int_matrix ( int rows, int columns )
{
	int **m;
	m = new int* [rows];													// allocate pointer array
	*m = new int [columns]();												// allocate data array; +initialize
	for(int counter = 1; counter < rows; counter++)	// set (all) pointers
	{
		m[counter] = m[counter - 1] + columns;
	}
	return m;
}		// -----  end of function new_int_matrix  -----

// ===  FUNCTION  ======================================================================
//         Name:  delete_int_matrix
//  Description:  
// =====================================================================================
void delete_int_matrix ( int **m )
{
		delete[] *m; 		// delete data array
		delete[] m;			// delete pointer array
}		// -----  end of function delete_int_matrix  -----

Die von mir selbst geschriebenen Funktionen:
C++:
uint next_generation ( int **feld1, int **feld2, uint breite, uint hoehe )
{
	int sum = 0;
	int fh = (int)hoehe;
	int fb = (int)breite;
	for(int counterH = 0; counterH < fh; counterH++)
	{
		for(int counterB = 0; counterB < fb; counterB++)
		{
			if(counterB == (fb-1) || counterH == (fh-1) || counterB == 0 || counterH == 0)
			{
				feld2[counterH][counterB] = 0;
			}
			else
			{
				sum = 0;
				
				sum += feld1[counterH-1][counterB-1];
				sum += feld1[counterH-1][counterB];
				sum += feld1[counterH-1][counterB+1];

				sum += feld1[counterH][counterB-1];
				sum += feld1[counterH][counterB];
				sum += feld1[counterH][counterB+1];

				sum += feld1[counterH+1][counterB-1];
				sum += feld1[counterH+1][counterB];
				sum += feld1[counterH+1][counterB+1];

				if(sum > 3 || sum < 2 || (sum == 2 && feld1[counterH][counterB] == 0) ) feld2[counterH][counterB] = 0; // Überbevölkerung + Vereinsamung
				if( (sum == 2 && feld1[counterH][counterB] == 1) || sum == 3) feld2[counterH][counterB] = 1;			// neu Geburt + am leben bleiben
			}
		}
	}
	gen++;

	return gen;
}		// -----  end of function next_generation  -----

// ===  FUNCTION  ======================================================================
//         Name:  print_feld
//  Description:  
// =====================================================================================
void print_feld ( int **feld, uint hoehe, uint breite )
{
	assert(feld != NULL);

	system("clear"); // bei Windows "cls" statt "clear"

	int population = 0;

	int fh = (int)hoehe-1;
	int fb = (int)breite-1;
	for(int counterH = 1; counterH < fh; counterH++)
	{
		for(int counterB = 1; counterB < fb; counterB++)
		{
			cout << ( feld[counterH][counterB] == 1 ? '#' : ' ');
			if(feld[counterH][counterB] == 1) population++;
		}
		cout << endl;
	}

	cout << "Generation: " << setw(5) << gen << "  Population: " << setw(5) << population << endl;

}		// -----  end of function print_feld  -----

// ===  FUNCTION  ======================================================================
//         Name:  zufallsbelegung
//  Description:  
// =====================================================================================
void zufallsbelegung ( int **feld, uint hoehe, uint breite )
{
	assert(feld != NULL);

	int fh = (int)hoehe-1;
	int fb = (int)breite-1;
	for(int counterH = 1; counterH < fh; counterH++)
	{
		for(int counterB = 1; counterB < fb; counterB++)
		{
			feld[counterH][counterB] = (int)( ((double)rand() / RAND_MAX) + 0.5 );
		}
	}
}		// -----  end of function zufallsbelegung  -----


Und zu guter letzt, die main:
C++:
// ===  FUNCTION  ======================================================================
//         Name:  main
//  Description:  Hauptprogramm
// =====================================================================================
int main ( int argc, char *argv[] )
{
	time_t t;
	time(&t);
	srand((uint)t);

	int feldB = 40 + 2;
	int feldH = 20 + 2;
	
	/*
	 * Anlegen der Felder bzw. Zeiger auf Felder
	 */
	int **zwsp;
	int **gamefeld  = new_int_matrix(feldH, feldB);
	int **gamefeld1 = new_int_matrix(feldH, feldB);

	zufallsbelegung(gamefeld, feldH, feldB);
	print_feld(gamefeld, feldH, feldB);

	next_generation(gamefeld, gamefeld1, feldB, feldH);	
	
	zwsp = gamefeld1;
	gamefeld1 = gamefeld;
	gamefeld = zwsp;
	
	print_feld(gamefeld, feldH, feldB);

	/*
	 * Löschen der Felder + der Zeiger auf die Felder
	 */
	delete_int_matrix(gamefeld);
	delete_int_matrix(gamefeld1);
	delete_int_matrix(zwsp);

	return EXIT_SUCCESS;
}				// ----------  end of function main  ----------


Ich hoffe jemand kann mir sagen,
was ich falsch gemacht habe,
denn ich finde da keinen Fehler.


Da kommt natürlich noch ne schleife in die Main
und die möglichkeit von Benutzer eingaben,
unter anderem über die Feldgröße
und die Anzahl der Generationen.
Jedoch möchte ich das nicht machen solange
nichtmal ein Durchlauf ohne Probleme funktioniert.
 
Hallo H4ckHunt3r,

wo tritt denn die Speicherzugriffsverletzung auf?

Hast du schonmal einen Debugger ausprobiert?
 
Einen Debugger habe ich nicht verwendet,
da ich keinen kenne bzw. weis wie er Funktioniert.
(Besonders unter Linux nicht)

Das ist die erste C++ Aufgabe
die wir bekommen haben
(Haben voher C gemacht).

Arbeite unter Ubuntu mit gVim.


Allerdings weis ich,
dass der fehler erst nach
der ersten Ausgabe auftritt.

Also nach dem ersten aufruf von:
C++:
print_feld(gamefeld, feldH, feldB);

Allerdings habe ich das Feld in allen Funktionen gleich behandelt,
deshalb denke ich das da irgendwas total falsch sein muss?
 
Ich hab jetzt nur grob drüber geschaut.

Die vorgegeben Funktion new_int_matrix ist Fehlerhaft, bist du dir sicher das diese so vorgegeben wurde und nicht verbessert werden muss. Der Punkt ist, dass in dieser Funktion generierte Feld zu klein ist. Es muss wie folgt heißen:
Code:
 *m = new int [columns*rows]();

Des Weiteren tauscht du die Pointer von den Variablen gamefeld und gamefeld1 mit Hilfe der Variable zswap.
Beachte dass NUR die Pointer getauscht werden, jedoch nicht der komplette Speicherbereich auf den diese Zeigen.
In deinem Fall ist dies auch gut so jedoch entsteht dadurch kein neuer Reservierter Speicherbereich sodass auf die Hilfsvariable kein delete_int_matrix statt finden darf.
 
Danke veeman funktioniert bestens,
abtippen ist schon schwer..
da stand sogar [rows*columns]();...
in der Aufgabe.^^
 
Nur mal so nebenbei: unter Linux gibt's gdb den GNU Debugger. Funktioniert nach diesem Prinzip:

1. Kompilier deine Sourcen mit CFLAGS -ggdb
2. Ruf gdb ./dein_programm an der Commandline auf
3. Starte den Programmablauf mit continue
4. Warte auf den Segfault
5. Gebe bt (backtrace) ein um die Stelle zu finden, an der der Segfault aufgetreten ist.
6. Mit "print variablenname" kannst du Variablen auf NULL- bzw. ungültige Zeiger prüfen.
 

Neue Beiträge

Zurück