Forum: PC-Programmierung zufallsabhängig eine Anzahl von Instanzen? eines Structs erstellen


von J. T. (chaoskind)


Lesenswert?

MoinMoin,

da ich nicht so genau weiß, wonach ich suchen müsste, versuche ich 
einfach mal mein Problem zu beschreiben, es wird daher etwas länger 
werden, dafür entschuldige ich mich schonmal im voraus.

Ich befasse mich seit Ewigkeiten mal wieder ein wenig mit dem 
Programmieren auf dem PC, sonst hab ich immer nur Atmegas programmiert. 
Das Ganze passiert in C mit dem Onlinegdbcompiler.

Ich versuche ein Game of Life zu schreiben, das "mehr Möglichkeiten" als 
Conways bietet, und erhoffe mir dadurch mehr Komplexität und 
Lebendigkeit reinzukriegen. Alles passiert auf einem 2D-Spielfeld, 
welches aus Feldern mit einer X und Y Position besteht mit verbundenen 
Rändern besteht, also ein Torus. Jedes Feld soll Rasen haben können, auf 
der Welt laufen Hasen rum, die den Rasen fressen wollen, und es laufen 
Füchse rum, die die Hasen fressen wollen.

Als erstes erzeuge ich ein struct Feld
1
struct Feld 
2
{
3
  unsigned Rasen;
4
  unsigned ZeitSeitAbgefressen;
5
};
Davon ein Array
1
struct Feld Spielfeld[SpielfeldgroesseX][SpielfeldgroesseY];
Das Spielfeld fülle ich dann mit
1
    //Spielfeld füllen
2
    while(x<SpielfeldgroesseX)
3
    {
4
        while(y<SpielfeldgroesseY)
5
        {
6
            Spielfeld[x][y].Rasen = rand()%2;
7
            y++;
8
        }
9
        y = 0;
10
        printf("Feld %d %d hat Rasen %d \n", x, y, Spielfeld[x][y].Rasen);
11
        x++;
12
    }
13
;
Nebenbei noch die Definition für ein struct Hasen und ein Fuchs, die 
dann Eigenschaften wie Alter Geschlecht usw enthalten.

Nun hänge ich daran fest, dass so einen "Initialisierungsdurchlauf" auch 
für die Hasen und Füchse machen möchte. Aus Gründen die mir gerade 
entfallen sind, war irgendwas unpraktikabel daran, in das Feld-Struct 
mitaufzunehmen ob Fuchs und Hase auf dem Feld vorhanden sind. Wobei ich 
glaube, dass war, weil die Hasen und Füchse auch mehrere Eigenschaften 
haben sollten.

Die X und Y-Schleifen wie oben, und dann sollte sowas wie
1
rand()%100;
2
if rand>90 erzeuge Hasen
kommen. Aber Variablen (ein Struct ist doch nichts anderes als ne 
Variable?) kann man doch nur Eingangs der Funktion erzeugen? Soll ich 
also nun für jedes Feld nen toten Hasen und Fuchs vorhalten, der dann 
mit ner 10% Wahrscheinlichkeit lebendig wird?

Oder kann ein Struct auch andere Structs als Member haben? Wobei dass 
dann ja aufs selbe hinaus liefe, wie für jedes Feld nen toten Hasen zu 
erzeugen....

Ich hoffe, es schimmert wenigstens ansatzweise durch, was mein Problem 
ist.

MfG Chaos

: Bearbeitet durch User
von Klaus W. (mfgkw)


Lesenswert?

Ich glaube, du willst einen Zeiger auf ein Feld mit den structs haben 
und zur Laufzeit dann mit malloc() entsprechend viele Structs holen.

von J. T. (chaoskind)


Lesenswert?

Dann mach ich mich mal über malloc() schlau, danke für den Hinweis. Und 
die rasante Geschwindigkeit :D

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Im 
C-how-to-Tutorial(https://www.c-howto.de/tutorial/arrays-felder/speicherverwaltung/) 
hab ich auf die Schnelle das hier gefunden:
1
#include<stdio.h>
2
#include<stdlib.h>
3
4
int main() {
5
  int size=0;
6
  int *array;
7
8
  printf("Array-Groesse eingeben: ");
9
  scanf("%d", &size);
10
11
  // Speicher reservieren
12
  array = (int *) malloc(size * sizeof(int));
13
14
  if(array != NULL) {
15
    printf("\nSpeicher ist reserviert\n");
16
  }else {
17
    printf("\nKein freier Speicher vorhanden.\n");
18
  }
19
20
  return 0;
21
}

In dem Beispiel von denen soll eine Usereingabe entscheiden, wie groß 
das Array ist. In meinem Fall will ich ja
1
struct Hase
2
{
3
  int Alter;
4
  int Geschlecht;
5
  int Hunger;
6
  int PosX;
7
  int PosY;
8
};
9
int Hasenzaehler
10
11
struct Hase *Hasenpointer;       //????
12
int size = sizeof(struct Hase);  //????
13
14
while(x<xsize)
15
{
16
   while(y<ysize)
17
   {
18
      Zufall = rand()%100;
19
      if(rand>=90)
20
      {
21
          Hasenzaehler++;
22
          Hasenpointer = (int *) malloc(size);
23
      }
24
   }
25
}
Wow, das hab ich mir grad ausgedacht und es kompiliert tatsächlich. Wie 
greife ich dann auf meine einzelnen Hasen zu? Ich muss mir die Adresse 
vom ersten merken und kann von da aus mit sizeof(struct Hase) 
hochmultiplizieren, um die einzelnen anzusprechen? Oder muss ich davon 
ausgehen, dass das "Hasenmachen" von nem anderen Prozess unterbrochen 
wird, der möglicherweise auch malloc von verwendet, und mir dann 
zwischen meine Hasen anderen Krams schmeißt?

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> Wow, das hab ich mir grad ausgedacht und es kompiliert tatsächlich. Wie
> greife ich dann auf meine einzelnen Hasen zu?

Wenn Du vorher noch nie was mit malloc gemacht hast, dann mache das 
Spiel zuerst mit einer gedachten Maximalwelt (keine Ahnung, 32000x32000 
Hasen, Felder und Füchsen, egal). Wenn es zuviel Speicher ist oder zu 
lange rechnet, dann nimm 2 Nullen weg.

Erst wenn das Spiel rund läuft, überlege Dir, ob es Sinn macht, 
dynamisch zu werden. Und wenn die Antwort "Ja" ist, dann befasse Dich 
damit.

von J. T. (chaoskind)


Lesenswert?

Grundsätzlich hab ich schon einige solche Spielchen programmiert und hab 
da immer um das Problem herumgeschifft. Ich finde, "jetzt" ist ein guter 
Zeitpunkt, sich mit malloc zu befassen.

Kann wer dazu

J. T. schrieb:
> Oder muss ich davon
> ausgehen, dass das "Hasenmachen" von nem anderen Prozess unterbrochen
> wird, der möglicherweise auch malloc von verwendet, und mir dann
> zwischen meine Hasen anderen Krams schmeißt?

etwas sagen?

von Klaus W. (mfgkw)


Lesenswert?

Auf einem halbwegs aktuelllen Betriebssystem wie Linux oder Windows hat 
jeder Prozeß seinen eigenen virtuellen Speicher, den sie sich nicht 
gegenseitig verpfuschen können (außer daß natürlich nicht jeder 
gleichzeitig beliebig viel nehmen kann).

Ansonsten sind da noch ein paar Grundlagen zu Speicher und 
Zeigerarithmetik nützlich, die vielleicht den Rahmen von ein paar 
Beiträgen eher übersteigen.

Z.B. der gute alte Kernighan und Ritchie, oder eines der vielen anderen 
C-Bücher.

von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> Ich muss mir die Adresse
> vom ersten merken und kann von da aus mit sizeof(struct Hase)
> hochmultiplizieren, um die einzelnen anzusprechen?

Nein, kannst Du nicht.

Du kannst überhaupt keine Annahmen vom Speicher treffen. Weder, dass Du 
welchen bekommst, noch dass Du auch nur ein Byte darüber hinaus 
verwenden oder gar ahnen kannst.

Jeder malloc-Aufruf generiert Dir Speicher irgendwo oder halt nicht.

die Beschreibung von malloc in einer C-Referenz Deiner Wahl ist ein 
guter Startpunkt. Zumindest, wenn Dein Programm ohne Malloc 
funktioniert.

von J. T. (chaoskind)


Lesenswert?

A. S. schrieb:
> Nein, kannst Du nicht.

das allein könnte man als konkrete Antwort stehen lassen.

A. S. schrieb:
> Weder, dass Du
> welchen bekommst, noch dass Du auch nur ein Byte darüber hinaus
> verwenden

warum sollte ich überhaupt auf den Gedanken kommen, mehr Speicher nutzen 
zu wollen, als ich hab?

A. S. schrieb:
> oder gar ahnen kannst.

Deine Hochnäsigkeit kannst du dir gerne sparen

A. S. schrieb:
> Jeder malloc-Aufruf generiert Dir Speicher irgendwo oder halt nicht.

Sagt dir aber freundlicherweise bescheid, ob er es getan hat, oder halt 
nicht.

A. S. schrieb:
> die Beschreibung von malloc in einer C-Referenz Deiner Wahl ist ein
> guter Startpunkt. Zumindest, wenn Dein Programm ohne Malloc
> funktioniert.

Der Hinweis auf malloc wurde doch schon als aller erster Beitrag 
genannt. Mit deiner negativen Art kannst du dich gerne von meinen 
Threads fernhalten.


Gerne darfst du mir vorher noch erklären, warum das hier:
1
    //Hasen erzeugen
2
    while (x<SpielfeldgroesseX)
3
    {
4
        while (y<SpielfeldgroesseY)
5
        {
6
            Zufall = rand()%100;
7
            if (Zufall>=99)
8
            {
9
                
10
                
11
                Hasenpointer = malloc(size_sHase);
12
                Hasenpointer->Geschlecht = rand()%2;
13
                Hasenpointer->Alter = rand()%20;
14
                Hasenpointer->Hunger = rand()%100;
15
                Hasenpointer->PositionY = y;
16
                Hasenpointer->PositionX = x;
17
                
18
                Hasenzaehler++;
19
                
20
                if (ersterHaseDa_Flag==0)
21
                {
22
                    ersterHaseDa_Flag = 1;
23
                    ErsterHase_Pointer = Hasenpointer;
24
                }
25
                
26
                printf("Hase %d ist ", Hasenzaehler);
27
                if ( (Hasenpointer->Geschlecht) == 0 )
28
                {
29
                    printf("weiblich ");
30
                }
31
                else
32
                {
33
                    printf("männlich ");
34
                }
35
                printf("und %d Jahre alt.", Hasenpointer->Alter);
36
                //printf("Feld %d %d hat einen Hasen \n", x, y);
37
            }
38
            y++;
39
        }
40
        y = 0;
41
        x++;
42
    }
43
    x = 0;

exakt so wie in meinen Überlegungen weiter oben dargelegt funktioniert, 
obwohl es ja nicht geht, wie du sagst.

von J. T. (chaoskind)


Lesenswert?

Wobei das hier:
1
    Hasenpointer = ErsterHase_Pointer;
2
    
3
    if ( (Hasenpointer->Geschlecht) == 0 )
4
        {
5
            printf("Die erste Häsin ist %d Jahre alt. ", Hasenpointer->Alter);
6
        }
7
    else
8
        {
9
            printf("Der erste Hase ist %d Jahre alt. ", Hasenpointer->Alter);
10
        }
11
        
12
    Hasenpointer += sizeof(sHase);
13
    printf("\n");
14
    if ( (Hasenpointer->Geschlecht) == 0 )
15
        {
16
            printf("Die zweite Häsin ist %d Jahre alt. ", Hasenpointer->Alter);
17
        }
18
    else
19
        {
20
            printf("Der zweite Hase ist %d Jahre alt. ", Hasenpointer->Alter);
21
        }

nur noch für den ersten Hasen klappt.

von Johannes S. (Gast)


Lesenswert?

J. T. schrieb:
> Hasenpointer += sizeof(sHase);

Ein pointer++ reicht um auf das nächste Element zu zeigen, die 
Elementgröße berücksichtigt der Compiler schon. Habe jetzt aber nicht 
alles im Detail verfolgt.

von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> warum sollte ich überhaupt auf den Gedanken kommen, mehr Speicher nutzen
> zu wollen, als ich hab?

Weil Du a) faktisch genau das wolltest und tatest: Annahmen über 
Speicher außerhalb des zuerst angeforderten.

und es b) womöglich funktioniert, wenn Du es ausprobierst. Darum schrieb 
ich

> A. S. schrieb:
>> oder gar ahnen kannst.

Wenn es für Dich nach
> Hochnäsigkeit
klingt, tut es mir Leid.

> Sagt dir aber freundlicherweise bescheid, ob er es getan hat, oder halt
> nicht.
Ja. Sonst wäre es nicht nutzbar.

J. T. schrieb:
> Der Hinweis auf malloc wurde doch schon als aller erster Beitrag
> genannt. Mit deiner negativen Art kannst du dich gerne von meinen
> Threads fernhalten.
Du hast explizit nochmal nachgefragt. Sorry, dass ich Deine Beiträge 
lese.

> Gerne darfst du mir vorher noch erklären, warum das hier:

dort sehe ich nichts, was irgendwie mit +=sizeof oder ptr++ zu tun hat.

Dass Du im nächsten Post ptr++ nehmen müsstest, geschenkt, hat Johannes 
schon gesagt. Dein Konstrukt mit +=sizeof() gibt es genauso, allerdings 
dann mit Byte-Pointern (uint8_t* oder char* z.B.).

Mit den üblichen Implementierungen von Malloc funktioniert beides 
meistens *nicht*, da malloc seine Kontroll-Informationen an den Block 
(bzw. davor) klatscht UND oft die nächst größere "glatte" Blockgröße 
nimmt. Und wenn es bei Dir funktioniert, ist es trotzdem Unsinn darüber 
nachzudenken.

Gruß

achim

(Und ja, es gibt sogar einen Befehl, mit dem Du genau das machen 
könntest. Aber auch der führt ins Chaos im jetzigen Projekt, also 
sprechen wir nicht drüber)

von Rolf M. (rmagnus)


Lesenswert?

J. T. schrieb:
> Wobei das hier:
> [...]
> nur noch für den ersten Hasen klappt.

Das ist genau das Problem, von dem A.S. spricht. malloc liefert dir 
einen Pointer auf Speicher zurück, in den du deinen Hasen stecken kannst 
(sofern es erfolgreich war). Mehr Annahmen darfst du über diesen Pointer 
nicht treffen. Insbesondere darfst du nicht davon ausgehen, dass mehrere 
aufeinander folgende malloc-Aufrufe dir die Speicherbereiche an 
aufeinanderfolgenden Adressen gibt. Jeder malloc-Aufruf gibt dir einen 
Speicher-Block, der zu den anderen in keinerlei Beziehung steht.
Es kann zwar je nach System sogar funktionieren, aber das ist dann 
reines Glück (oder Pech, da man einen Bug produziert hat, den man in dem 
Moment nicht erkennt).

von Experte (Gast)


Lesenswert?

J. T. schrieb:
> nur noch für den ersten Hasen klappt.

Der Speicherbereich, den Dir malloc() reserviert, ist (praktisch 
gesehen) rein zufällig. D.h. wenn Du drei mal hintereinander malloc() 
aufrufst, bekommst Du insgesamt drei Zeiger zurück, die irgendwo hin 
zeigen. Die Speicherbereiche sind nicht hintereinander.

D.h. wenn Du so mit malloc() arbeitest, um für jeden Hasen ein neuen 
Speicherbereich dir geben lässt, hast Du erst den halben Weg geschafft. 
Denn für jeden Hasen-Speicherbereich musst Du Dir jetzt noch den Zeiger 
auf diesen Hasen-Speicher merken.

Du hast das Problem nicht gelöst, sondern nur "verschoben". Also:

Wenn Du 5 Hasen mit malloc() besorgt hast, hast Du 5 Speicherblöcke und 
zusätzlich 5 unterschiedliche Zeiger auf diese Speicherblöcke. Diese 
Zeiger musst Du irgendwo speichern. Am besten in einer Tabelle.

Da Du aber nicht weist, wie groß Deine Tabelle sein soll, denn es kommen 
ja gelegentlich neue Hasen hinzu, stehst Du wieder vor dem gleichen 
Problem: Du besorgst Dir Speicher für eine Tabelle, die Platz für 5 
Zeiger auf Hasen-Speicherbereiche hat. Aber mit dem 6. Hasen, geht's 
nicht weiter. Du brauchst eine größere Tabelle. Dafür gibt es die 
Funktion realloc(). Die vergrößert (oder verkleinert) einen 
Speicherbereich, der zuvor mit malloc() besorgt wurde. Aber Achtung: 
Nach dem vergrößern oder verkleinern hat sich die Adresse des 
Speicherbereichs geändert!

von J. T. (chaoskind)


Lesenswert?

A. S. schrieb:
> Wenn es für Dich nach
>> Hochnäsigkeit
>
> klingt, tut es mir Leid.

Tat es allerdings tatsächlich. Aber nach deinem Nachschub und einer 
Erklärung, sehe ich, dass es nicht so gemeint war und möchte mich für 
meine Ungehaltenheit entschuldigen. Scheinbar hat die Miesepeterigkeit 
mich auch schon ein wenig angefallen.

Experte schrieb:
> Dafür gibt es die Funktion realloc().

Auch dir vielen Dank für deine Ausführungen. Realloc hab ich inzwischen 
auch entdeckt gehabt. Bin aber genau auf die von dir erwähnten Probleme 
gestoßen.

Naja ich werd mal etwas weitertüfteln. Evtl fallen mir ja noch die 
richtigen Kniffe ein

von Klaus W. (mfgkw)


Lesenswert?

Es gibt ja bekanntlich viele Wege, die nach Rom führen.


Z.B.:

Vorschlag 1:

Das Feld stellt man sich mit Zeilen und Spalten etwa so vor:
1
+-                                                -+
2
| feld_11 feld_12 feld_13  ... feld_1j ... feld_1n |
3
| feld_21 feld_22 feld_23  ... feld_2j ... feld_2n |
4
| ...                                              |
5
| feld_i1 feld_i2 feld_i3  ... feld_ij ... feld_in |
6
| ...                                              |
7
| feld_m1 feld_m2 feld_m3  ... feld_mj ... feld_mn |
8
+-                                                -+
Jedes der Elemente ist vom Typ deiner struct.

Man allokiert jetzt nicht jeweils Platz für eine struct, sondern gleich 
für alle.
1
typedef struct { ... } feld_t;
2
size_t   nFeld = 0; // Anzahl in die eine Richtung (Zeilenlänge)
3
size_t   mFeld = 0; // Anzahl in die andere Richtung (Spaltenlänge, Anzahl Zeilen)
4
feld_t   * feld = NULL;
5
...
6
// irgendwie Größe ermitteln:
7
nFeld = ...;
8
mFeld = ...;
9
// Speicher holen für alle Elemente:
10
feld = (feld_t*)malloc( nFeld*mFeld*sizeof(feld_t) );
11
if( !feld ) ...Fehlerbehandlung...;
12
// jetzt alle Elemente initialisieren...
Jetzt liegen die Elemente einfach hintereinander im Speicher, üblich ist 
in C zeilenweise Organisation. Also feld[0] ist gedacht feld_0,0, 
feld[1] ist feld_0,1 etc. bis feld[nFeld\*mFeld-1] ist 
feld_mFeld-1,nFeld-1.
feld_ij wäre also feld[i*nFeld+j].

Mit Makros oder Funktionen könnte man die Indices umrechnen, damit man 
es nicht dauernd verwechselt.

Vorschlag 2:
Man macht für jede Zeile des Feldes ein malloc(nFeld*sizeof(feld_t)) und 
speichert die Adresse dieser Zeile in einem Feld von Zeigern (das 
ebenfalls allokiert wird)
1
feld_t   ** feld = NULL;
2
size_t   nFeld = ...;
3
size_t   mFeld = ...;
4
5
// Feld mit Zeigern auf die Zeilen:
6
feld = (feld_t**)malloc( mFeld*sizeof(feld_t*) );
7
if( !feld ) ...Fehlerbehandlung...;
8
size_t iZeile;
9
for( iZeile=0; iZeile<mFeld; ++iZeile )
10
{
11
  feld[iZeile] = (feld_t*)malloc( nFeld*sizeof(feld_t) );
12
  if( !feld[iZeile] ) ...Fehlerbehandlung...;
13
  // jetzt alle Elemente der Zeile initialisieren...
14
}

Das sieht erstmal umständlicher aus.
Hat aber einen charmanten Vorteil: man kann auf die Elemente einfach mit 
feld[i][j] zugreifen.

Oder eine von vielen anderen Möglichkeiten...


Wer das zu umständlich findet, ist ein Kandidat für C++ (std::vector< 
std::vector< feld_t > > ...).
Aber zum Üben darf man sich auch gerne mal mit C durchquälen, dann weiß 
man etwas moderneres zu schätzen.

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

WOW! Ich bin begeistert, vielen Dank für die sehr konkreten Vorschläge. 
Ich glaube, meine letzten Grübeleien gingen sehr in Richtung von 
Vorschlag2, waren aber leider noch nicht ausgegoren, als ich nochmal 
guckte, ob wer geschrieben hat :D

Ich werd erstmal meinen Ansatz weiterfolgen, und wenn er fertig oder 
unfunktionell ist, mich mal deinem Vorschlag widmen.

von J. T. (chaoskind)


Lesenswert?

So ich hab da nun was, das zu funktionieren scheint. Mir ist aber auch 
kein besserer "Stresstest" eingefallen, als die Viecher 2mal abzufragen 
:D
1
#include <stdio.h>
2
#include <stdlib.h>
3
#include <math.h>
4
#include <time.h>
5
6
#define SpielfeldgroesseX 256
7
#define SpielfeldgroesseY 256
8
9
10
11
typedef struct 
12
{
13
    unsigned Geschlecht;
14
    unsigned Alter;
15
    unsigned Hunger;
16
  unsigned PositionX;
17
  unsigned PositionY;
18
}sHase;
19
20
typedef struct
21
{
22
    unsigned Rasen;
23
    unsigned ZeitSeitAbgefressen;
24
}sFeld;
25
26
27
28
int main()
29
{
30
    sHase *Hasenliste_Pointer = NULL;
31
    sHase *Hase_Pointer = NULL;
32
    unsigned size_sHase = sizeof(sHase);
33
    unsigned Hasenzaehler = 0;
34
    unsigned Hasenherdengroesse = 0;
35
    
36
    unsigned x = 0;
37
    unsigned y = 0;
38
    unsigned *p = &x;
39
    
40
    /* Intializes random number generator */
41
    srand(time(NULL));
42
    
43
    printf("Ein unsigned ist %d byte groß\n\n", (int)sizeof(x));
44
    
45
    printf("Ein Pointer auf ein unsigned ist %d byte groß\n\n", (int)sizeof(p));
46
    
47
    printf("Ein Struct vom Typ sHase ist %d byte groß\n\n", size_sHase);
48
    
49
    //ersten Platz auf der Hasenliste erschaffen
50
    Hasenliste_Pointer = (sHase*)malloc(size_sHase);  
51
    if(Hasenliste_Pointer != NULL)
52
    {
53
        
54
    }
55
    else
56
    {
57
        printf("Kein Speicher verfügbar");
58
        return 1;
59
    }
60
    
61
    //Hasen erzeugen
62
    while(x<SpielfeldgroesseX)    //Felder in X Richtung durchtickern      
63
    {
64
        while(y<SpielfeldgroesseY)  //Felder in Y Richtung durchtickern
65
        {
66
            if(rand()%100 >= 99)
67
            {
68
                (Hasenliste_Pointer+Hasenzaehler)->Geschlecht = rand()%2;   //Geschlecht 0 = männlich 1 = weiblich
69
                (Hasenliste_Pointer+Hasenzaehler)->Alter = rand()%(365*20); //Nach 20 Jahren is aus
70
                (Hasenliste_Pointer+Hasenzaehler)->PositionX = x;
71
                (Hasenliste_Pointer+Hasenzaehler)->PositionY = y;
72
                
73
                Hasenzaehler++;
74
                Hasenliste_Pointer = (sHase*)realloc( Hasenliste_Pointer, size_sHase+(Hasenzaehler*size_sHase) );
75
                
76
            }
77
            y++;
78
        }
79
        y = 0;
80
        x++;
81
    }
82
    x = 0;
83
    Hasenherdengroesse = Hasenzaehler;
84
    Hasenzaehler = 0;
85
    
86
    
87
    
88
    while(Hasenzaehler<25)
89
    {
90
        printf("Hase %d ist ", Hasenzaehler);
91
        
92
        if( (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht == 0   )
93
        {
94
            printf("männlich");
95
        }
96
        else
97
        {
98
            printf("weiblich");
99
        }
100
        
101
        printf(", %d Tage alt und auf Position %d X und %d Y.\n\n", (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter, (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionX,(Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionY  );
102
        
103
        
104
        Hasenzaehler++;
105
    }
106
    
107
    Hasenzaehler = 0;
108
    
109
        while(Hasenzaehler<25)
110
    {
111
        printf("Hase %d ist ", Hasenzaehler);
112
        
113
        if( (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht == 0   )
114
        {
115
            printf("männlich ");
116
        }
117
        else
118
        {
119
            printf("weiblich ");
120
        }
121
        
122
        printf("und %d Tage alt \n\n", (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter  );
123
        Hasenzaehler++;
124
    }
125
    
126
    
127
    return 0;

P.S.
ich seh grad, ich hab beim realloc wieder die Fehlerbehandlung 
vergessen.

P.P.S.
Und so muss ich die toten Hasen mit rumschleppen, damit die Liste 
konsistent bleibt... auch noch suboptimal

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Ich hab jetzt mal versucht, das Hasenerzeugen in eine Funktion 
auszulagern. Damit hatte ich irgendwie schon immer Probleme. Ich 
übergebe der Funktion den Hasenlistenpointer und nen Pointer auf die 
Hasenherdengröße, ansonsten ist die Hasenerzeugung, die schon 
funktioniert, eins zu eins rüberkopiert.

Wenn ich den Funktionsaufruf auskommentiere und die "zu Fuß" Variante in 
der main nutze, bekomme ich meine ersten 25 Hasen aufgelistet. 
Kommentiere ich die "zu Fuß" Variante aus und nutze den 
Funktionsaufrauf, wird ohne Warnungen/Fehler kompiliert, das Programm 
läuft und gibt 0 zurück, aber es gibt nur die ersten drei printf aus. 
Die Fehler/Go-Behandlung vom malloc erscheint gar nicht mehr.

Was läuft da falsch?

Hier nochmal der jetzige Code:
1
/******************************************************************************
2
3
Welcome to GDB Online.
4
GDB online is an online compiler and debugger tool for C, C++, Python, PHP, Ruby, 
5
C#, VB, Perl, Swift, Prolog, Javascript, Pascal, HTML, CSS, JS
6
Code, Compile, Run and Debug online from anywhere in world.
7
8
*******************************************************************************/
9
#include <stdio.h>
10
#include <stdlib.h>
11
#include <math.h>
12
#include <time.h>
13
14
#define SpielfeldgroesseX 256
15
#define SpielfeldgroesseY 256
16
17
18
19
typedef struct 
20
{
21
    unsigned Geschlecht;
22
    unsigned Alter;
23
    unsigned Hunger;
24
  unsigned PositionX;
25
  unsigned PositionY;
26
}sHase;
27
28
typedef struct
29
{
30
    unsigned Rasen;
31
    unsigned ZeitSeitAbgefressen;
32
}sFeld;
33
34
sHase* HasenErzeugen(sHase *Hasenliste_Pointer, unsigned *Herdengroesse);
35
36
int main()
37
{
38
    sHase *Hasenliste_Pointer = NULL;
39
    sHase *Hase_Pointer = NULL;
40
    unsigned size_sHase = sizeof(sHase);
41
    unsigned Hasenzaehler = 0;
42
    unsigned Hasenherdengroesse = 0;
43
    
44
    unsigned x = 0;
45
    unsigned y = 0;
46
    unsigned *p = &x;
47
    
48
    /* Intializes random number generator */
49
    srand(time(NULL));
50
    
51
    printf("Ein unsigned ist %d byte groß\n\n", (int)sizeof(x));
52
    
53
    printf("Ein Pointer auf ein unsigned ist %d byte groß\n\n", (int)sizeof(p));
54
    
55
    printf("Ein Struct vom Typ sHase ist %d byte groß\n\n", size_sHase);
56
    
57
    //ersten Platz auf der Hasenliste erschaffen
58
    Hasenliste_Pointer = (sHase*)malloc(size_sHase);  
59
    if(Hasenliste_Pointer != NULL)
60
    {
61
        printf("Speicher für Hasenliste erschaffen");
62
    }
63
    else
64
    {
65
        printf("Kein Speicher verfügbar");
66
        return 1;
67
    }
68
    
69
70
//    Hasenliste_Pointer = HasenErzeugen(Hasenliste_Pointer, &Hasenherdengroesse);
71
    
72
     //Hasen erzeugen
73
    while(x<SpielfeldgroesseX)    //Felder in X Richtung durchtickern      
74
    {
75
        while(y<SpielfeldgroesseY)  //Felder in Y Richtung durchtickern
76
        {
77
            if(rand()%100 >= 99)
78
            {
79
                (Hasenliste_Pointer+Hasenzaehler)->Geschlecht = rand()%2;   //Geschlecht 0 = männlich 1 = weiblich
80
                (Hasenliste_Pointer+Hasenzaehler)->Alter = rand()%(365*20); //Nach 20 Jahren is aus
81
                (Hasenliste_Pointer+Hasenzaehler)->PositionX = x;
82
                (Hasenliste_Pointer+Hasenzaehler)->PositionY = y;
83
                
84
                Hasenzaehler++;
85
                Hasenliste_Pointer = (sHase*)realloc( Hasenliste_Pointer, size_sHase+(Hasenzaehler*size_sHase) );
86
                if (Hasenliste_Pointer == NULL)
87
                {
88
                    printf("kein Speicher mehr da");
89
                }
90
                
91
            }
92
            y++;
93
        }
94
        y = 0;
95
        x++;
96
    }
97
    x = 0;
98
    Hasenherdengroesse = Hasenzaehler;
99
    Hasenzaehler = 0;
100
    
101
    
102
    
103
    while(Hasenzaehler<25)
104
    {
105
        printf("Hase %d ist ", Hasenzaehler);
106
        
107
        if( (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht == 0   )
108
        {
109
            printf("männlich");
110
        }
111
        else
112
        {
113
            printf("weiblich");
114
        }
115
        
116
        printf(", %d Tage alt und auf Position %d X und %d Y.\n\n", (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter, (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionX,(Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionY  );
117
        
118
        
119
        Hasenzaehler++;
120
    }
121
    
122
    Hasenzaehler = 0;
123
    
124
        while(Hasenzaehler<25)
125
    {
126
        printf("Hase %d ist ", Hasenzaehler);
127
        
128
        if( (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht == 0   )
129
        {
130
            printf("männlich ");
131
        }
132
        else
133
        {
134
            printf("weiblich ");
135
        }
136
        
137
        printf("und %d Tage alt \n\n", (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter  );
138
        Hasenzaehler++;
139
    }
140
    
141
    
142
    return 0;
143
}
144
145
146
147
sHase* HasenErzeugen(sHase *Hasenliste_Pointer, unsigned *Herdengroesse)
148
{
149
    unsigned size_sHase = sizeof(sHase);
150
    unsigned Hasenzaehler = 0;
151
    
152
    unsigned x = 0;
153
    unsigned y = 0;
154
        //Hasen erzeugen
155
    while(x<SpielfeldgroesseX)    //Felder in X Richtung durchtickern      
156
    {
157
        while(y<SpielfeldgroesseY)  //Felder in Y Richtung durchtickern
158
        {
159
            if(rand()%100 >= 99)
160
            {
161
                (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht = rand()%2;   //Geschlecht 0 = männlich 1 = weiblich
162
                (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter = rand()%(365*20); //Nach 20 Jahren is aus
163
                (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionX = x;
164
                (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->PositionY = y;
165
                
166
                Hasenzaehler++;
167
                Hasenliste_Pointer = (sHase*)realloc( Hasenliste_Pointer, size_sHase+(Hasenzaehler*size_sHase) );
168
                if (Hasenliste_Pointer == NULL)
169
                {
170
                    printf("kein Speicher mehr da");
171
                }                
172
            }
173
            y++;
174
        }
175
        y = 0;
176
        x++;
177
    }
178
    x = 0;
179
    *Herdengroesse = Hasenzaehler;
180
    Hasenzaehler = 0;
181
    return Hasenliste_Pointer;
182
}

von J. T. (chaoskind)


Lesenswert?

Wenn ich die Spielfeldgröße auf 25² statt 256² stelle, dann geht es auch 
als Funktionsaufruf....

aber ab Hase 6 haben alle Werte jeweils den Wert 0.....

Wenn ich mit dem Debugger durchsteppe, kommt irgendwann in der 
"Hasenerzeugenschleife" ein Segmentationerror. Als ich auf 25² 
Spielfeldgröße runtergestellt hat, hat meine Geduld gelangt, 25 mal den 
Brakepoint in der äusseren Schleife anzuspringen und ich stellte mit 
erstaunen fest, dass es plötzlich geht.
Auf 256 fehlt mir die Geduld. Und irgendwie weiß ich nicht, wie ich den 
debugger dazu bekomme, mir den Durchlauf bei dem der Segmentationserror 
kommt, auszugeben.

P.S.
Es ist noch wirrer. Wenn ich die Größe auf 25² stelle, dann haben auch 
in der zu Fuß Variante ALLE Hasen die Werte 0.
Wenn ich wieder groß Stelle haben die Hasen plausible Werte.

: Bearbeitet durch User
von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> ansonsten ist die Hasenerzeugung, die schon
> funktioniert, eins zu eins rüberkopiert.

Nein. Du hast da die +sizeof-Version behalten.

Zu realloc habe ich ja schon Alles gesagt.

von J. T. (chaoskind)


Lesenswert?

A. S. schrieb:
> Nein. Du hast da die +sizeof-Version behalten.

Sorry, ich versteh nicht, worauf du hinauswillst?

In der Funktion erzeuge ich mir nur die Variablen die aus der main 
fehlen, und dann kommt doch genau das gleiche, wie in der Main-schleife? 
oder bin ich nu völlig betriebsblind? Dann übergebe ich der Funktion den 
Pointer aus der main, der wegen dem malloc wohin auch immer zeigt. 
Zusätzlich noch den Pointer auf die Herdengröße die ich wissen will.
Ansonsten muss in der Schleife doch das +sizeof? sein

J. T. schrieb:
> (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht = rand()%2;
> //Geschlecht 0 = männlich 1 = weiblich

meinst du überhaupt diese Stelle?

von J. T. (chaoskind)


Lesenswert?

Ich mein ich hab 16GB RAM, da sollten sich doch 1,3 zusammenhängende MB 
für im Extremfall 256*256Hasen zu 20byte je Hase finden lassen?

von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> J. T. schrieb:
>> (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht = rand()%2;
>> //Geschlecht 0 = männlich 1 = weiblich
>
> meinst du überhaupt diese Stelle?

ja. Im Original (und richtig) ist es

J. T. schrieb:
> (Hasenliste_Pointer+Hasenzaehler)->Geschlecht =
> rand()%2;

Genauso gut ginge auch
1
Hasenliste_Pointer[Hasenzaehler].Geschlecht = rand()%2;

Wenn Du Deine Namen/Bezeichner auf die Hälfte einkürzest, läs es sich 
leichter. HasenPtr, HasenN, Weib z.B., oder pHasen, nHasen, Sex.

von Experte (Gast)


Lesenswert?

Ein paar Anmerkungen:

  - Teile und herrsche: Kleine Funktionen die einen Teil erledigen.
  - Wenn ein Fehler auftritt, Programm sofort beenden ist einfach.

Viel Spaß:
1
#include <stdlib.h>
2
#include <stdio.h>
3
4
struct Hase
5
{
6
  int ich_bin_ein_hase;
7
};
8
9
struct HasenArray
10
{
11
  size_t platz;
12
  size_t anzahl;
13
  struct Hase **hasen;
14
};
15
16
const int INIT_HASEN_ARRAY_PLATZ = 10;
17
18
void exit_with_error(const char *msg)
19
{
20
  puts(msg);
21
  exit(1);
22
}
23
24
void init_array(struct HasenArray *ha)
25
{
26
  if (!ha)
27
    exit_with_error("init_array() mit NULL-Zeiger aufgerufen");
28
29
  ha->anzahl = 0;
30
  ha->platz = INIT_HASEN_ARRAY_PLATZ;
31
  ha->hasen = malloc(ha->platz * sizeof(struct Hase *));
32
33
  if (!ha->hasen)
34
    exit_with_error("Kein Speicher für init_array()");
35
}
36
37
void resize_array(struct HasenArray *ha)
38
{
39
  if (!ha)
40
    exit_with_error("resize_array() mit NULL-Zeiger aufgerufen");
41
42
  ha->platz *= 2;
43
  ha->hasen = realloc(ha->hasen, ha->platz * sizeof(struct Hase *));
44
45
  if (!ha->hasen)
46
    exit_with_error("Kein Speicher für resize_array()");
47
}
48
49
void append_to_array(struct HasenArray *ha, struct Hase *hase)
50
{
51
  if (!ha || !hase)
52
    exit_with_error("append_to_array() mit NULL-Zeiger aufgerufen");
53
54
  if (ha->anzahl == ha->platz)
55
    resize_array(ha);
56
57
  ha->hasen[ha->anzahl++] = hase;
58
}
59
60
struct Hase *create_hase()
61
{
62
  struct Hase *hase = malloc(sizeof(struct Hase));
63
  if (!hase)
64
    exit_with_error("Kein Speicher für malloc_hase()");
65
66
  return hase;
67
}
68
69
struct HasenArray alle_hasen;
70
71
int main()
72
{
73
  // Einmal dynamisches Array initialisieren
74
  init_array(&alle_hasen);
75
76
  // Ein paar Hasen erzeugen und ins Array speichern
77
  for (int i = 0; i < 42; i++)
78
  {
79
    struct Hase *hase = create_hase();
80
    hase->ich_bin_ein_hase = i * 123 + 17;
81
82
    append_to_array(&alle_hasen, hase);
83
  }
84
85
  // Alle gespeicherten Hasen ausgeben
86
  for (int i = 0; i < alle_hasen.anzahl; i++)
87
  {
88
    struct Hase *hase = alle_hasen.hasen[i];
89
    printf("Hase %d: ich_bin_ein_hase = %d\n", i, hase->ich_bin_ein_hase);
90
  }
91
}

von Klaus W. (mfgkw)


Lesenswert?

Ich blicke noch nicht ganz, wie das Ding arbeiten soll.
Aber so geht es sicher nicht...

Erstens solltest du mit möglichst vielen Warnungen kompilieren und die 
auch beachten.
Bspw. gibst du mit falschen Formatanweisungen in printf() aus (%d für 
unsigned), das kann man vermeiden.
Zumindest -Wall -Wextra.

Zweitens wäre ein ordentlich formatierter besser lesbar.

Drittens müsstest du wirklich mal Grundlagen lernen.
Eine der Grundlagen in C ist Zeigerarithmetik.
1
...
2
        if( (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Geschlecht == 0   )
3
...
4
        printf("und %d Tage alt \n\n", (Hasenliste_Pointer+(Hasenzaehler*size_sHase))->Alter  );
5
...
Wenn du in C zu einem Zeiger etwas addierst, dann wird das implizit mit 
der Größe des Typs multipliziert, auf das der Zeiger zeigt gemäß seiner 
Deklaration.
Deine Multiplikation mit der Größe der Rammler ist also falsch.

Weiterhin reicht es nicht, einfach nur etwas auszugeben und einfach 
weiter zu machen, wenn realloc() fehlschlägt.

Auch sehe ich nicht, wieso du die Hasen bis 25 benutzt, ohne zu wissen 
wieviele es sind. Aber wie gesagt wirklich verstanden habe ich das 
Programm nicht...
Aber daß es so nicht klappt, ist schon zu sehen.

von J. T. (chaoskind)


Lesenswert?

Ich hab das ganze jetzt erst mal ohne malloc/realloc gemacht.

Klaus W. schrieb:
> Auch sehe ich nicht, wieso du die Hasen bis 25 benutzt, ohne zu wissen
> wieviele es sind.

Das hatte ich gemacht, um zu sehen, ob überhaupt mehr als ein Hase 
erzeugt und gespeichert wird, ganz zu Anfang hatte ich mir nur den 
ersten Hasen ausgeben lassen, und das klappte. Aber trotzdem ging es 
nicht. Also hab ich mir mehr Hasen ausgeben lassen...

Klaus W. schrieb:
> Aber wie gesagt wirklich verstanden habe ich das
> Programm nicht...

Das ist, so wie es ist, auch noch nicht zu verstehen, da völlig 
unfertig. Das ist noch nicht einmal die Initialsierung der Welt.

Da ich die Initialisierung der Welt nun aber zum laufen bekomme 
habe(noch ohne malloc/realloc), und gerne "etwas sehen" würde, hab ich 
mich dunkel an Allegro erinnert. Flugs CodeBlocks runtergeladen und 
Allegro5. CodeBlocks installiert, mich soweit durch die ganzen 
Einstellungen gefriemelt, bis er endlich nicht mehr gemeckert hat, es 
gäbe keine "allegro.h".
Aber dann scheitert er schon daran, die Funktion al_init() zu finden 
beim compilieren, obwohl mir die Funktion explizit vorgeschlagen wurde, 
vom Autofill.
Hier und da etwas gelesen, DevC++ mit seinem PacketManager wurde öfters 
lobend erwähnt, also flugs mal den installiert. Der PacketManager hat 
dann auch Allegro installiert. Aber DevC++ findet dann wieder nicht 
einmal die allegro.h....

Naja ich denke ich werd dafür mal nen neuen Thread aufmachen, ist ja 
doch recht OT

: Bearbeitet durch User
von J. T. (chaoskind)


Angehängte Dateien:

Lesenswert?

So ich hatte mal wieder ein wenig Zeit, weiter zu tüfteln.

Wen das Spiel nicht interessiert, die eigentlich Frage kommt ca in der 
Mitte vom Post.

Im Anhang mal 2 "Mitschnitte" von Runden als .cvs-Datei. Der erste Wert 
steht jeweils für die Anzahl an Hasen, der zweite Wert steht für die 
Anzahl an Füchsen und der dritte Wert ist der Rundenzähler. Leider hab 
ich keinen Durchschnittswert der Grashöhe (quasi wieviel Futter den 
Hasen auf dem jeweiligen Feld zur Verfügung steht) mit dazugetan, das 
ist in der grafischen Ausgabe ganz hübsch anzusehen.

Die spannende Runde war in so fern spannend, dass um Runde 4250 herum 
nur noch ein Fuchs am Leben war, zum Glück, oder Pech für die Hasen, war 
es ein trächtiges Weibchen. Und es hat wohl nen Männchen bekommen, 
ziemlich inzestuöser Haufen, diese Füchse :D.

Die andere Runde hab ich mal ohne Grafikausgabe laufen lassen. (Ich hab 
das Allegro immer noch nur in ner alten Version und ziemlich rudimentär 
zum laufen bekommen. Daher muss ich jeden Pixel einzeln zeichnen, 
irgendwie funktionieren die Grafikprimitive nicht. Mit grafischer 
Ausgabe komm ich auf ca eine zehntel Sekunde pro Runde, und ca 20% 
CPU-Last. Ohne waren die 50000 Runden bis die Füchse tot waren so 
schnell rum, dass ich nur kurz weg war, 100000 Runden um waren als ich 
wiederkam, nach ca 10 sek oder so. Der Taskmanager sagte 7.4% CPU-Last.) 
Nachdem nach den ca 50000 Runden dann keine Füchse mehr da waren, 
schwankte die Hasenzahl um die 800 herum.

Zur Zeit ist das ganze noch recht primitiv, die Hasen fressen bis das 
Feld leer ist, gucken sich dann im Radius X um welches Feld das höchste 
Gras hat und gehen da hin. 50 Ticks nach dem letzten angefressen worden 
wächst das Gras um jeweils 1 nach, bis es die maximale Länge (z Zt 10) 
erreicht hat.Hat der Hase ne Zeit lang nichts gefressen, steigt der 
Hunger, ist der Hunger zu groß, wird der Hase schwächer. Ist der Hase zu 
schwach, ist der Hase tot. Ist der Hase älter als x Ticks, ist der Hase 
tot. Wird der Hase gefressen, ist der Hase tot. Hat der Hase keinen 
Hunger und ist stark genug, schaut er sich im Radius Y nach ner 
nicht-trächtigen Häsin um, und macht sie trächtig. Die gute alte 
Steinzeit mit der Keule-Methode :D.

Die Paarung bei den Füchsen läuft nach dem selben Schema ab, auch das 
Fressen ist ähnlich, nur dass sie sich nach nem Hasen umsehen, und 
diesen dann mit der Chance NochnX erledigen.

Bei der aktuellen Spielfeldgröße von 60 mal 80 Feldern haben sich 
20Prozent als ganz gut erhausgestellt. Damit kommt es zu den sich 
gegenseitig bedingenden Minima und Maxima, die mich auf die Idee 
brachten, das ganze zu programmieren.

Auch die "Grafik" ist aufgrund der Einschränkungen mit den Pixeln noch 
maximal primitiv. Ein Feld ist ein Rechteck, in Abhängikeit von der 
Grashöhe unterschiedlich stark grün ist. Ein Hase ist ein stärkeabhängig 
blaues Rechteck im oberen linken Quadranten vom Feld auf dem Spielfeld, 
ein Fuchs ein stärkeabhängig blaues Rechteck, um unteren rechten 
Quadranten. Man hätte aufgrund der Quadranten noch die anderen beiden 
Farbkanäle für weitere Information, aber Farbenunterscheiden ist keine, 
zumindest meiner, Stärken.

Gerne würde ich nun eine Art Genetik mit in die Paarungsgeschichten 
eingehen lassen, auch weitere Ideen was man passieren lassen könnte, 
sind herzlich willkommen.

Über Hinweise auf eine einfach zu installierende/nutzende Grafiklibrary 
würde ich mich auch freuen.

Und hauptsächlich wollte ich nun, nachdem ich das Programm erstmal rund 
laufend habe, wie empfohlen wurde, und nach einigen Stolperfallen aus 
denen ich aber noch selbst herausfand, gerne wissen, wie das nun mit dem 
malloc/realloc funktioniert, bzw warum es bei mir nicht funktionierte.

Experte schrieb:
> Du hast das Problem nicht gelöst, sondern nur "verschoben". Also:
>
> Wenn Du 5 Hasen mit malloc() besorgt hast, hast Du 5 Speicherblöcke und
> zusätzlich 5 unterschiedliche Zeiger auf diese Speicherblöcke. Diese
> Zeiger musst Du irgendwo speichern. Am besten in einer Tabelle.

Ich weiß inzwischen, bei malloc soll man keine Annahmen machen. Ich mach 
aber mal folgende: Es hat sich gezeigt, dass das Spielfeld nicht mehr 
als einen Hasen pro Feld versorgen kann, wenn keine Füchse da sind. Um 
auf Nummer Sicher zu gehen, rechnet man mit 2 Hasen pro Feld.
1
typedef struct
2
{
3
    unsigned bli;
4
    unsigned bla;
5
    unsigned blub;
6
}sHase;
7
8
sHase Hasenliste[2 x FeldX x FeldY]
Man macht ein (statisches) Array von Pointern auf Hasen. Ein Pointer auf 
ein struct ist doch immer 8byte groß, egal wie groß das struct ist?

Das wäre also ein statischer Speicherverbrauch von 8 x 2 x FeldX x FeldY 
byte? Dazu käme dann dynamisch: Anzahl lebende Hasen x Größe vom 
Hasenstruct.

Die Liste brauch ich in meiner statischen Version auch, aber dazu kommt 
noch noch 8 x 2 x FeldX x FeldY x Größe vom Hasenstruct.

Ob sich das lohnt? Ich weiß es nicht.

Zumindest verstehe ich nicht, warum es mit malloc/realloc nicht 
funktioniert hat. Bekomme aber irgendwie auch nicht so recht den Punkt 
gefasst, wo es mit dem Verständnis hapert. Darum ist es wohl irgendwie 
auch ziemlich viel Text geworden, ich hab irgendwie mal die Gedanken 
fließen lassen, ich hoffe die Sprünge sind nicht allzu 
unnachvollziehbar. Es soll ja noch Leute geben, die gerne lesen ;-)

MfG
Chaos

von bunny (Gast)


Lesenswert?

J. T. schrieb:
> sHase Hasenliste[2 x FeldX x FeldY]
> Man macht ein (statisches) Array von Pointern auf Hasen.

das ist kein Array von Pointern.

von bunny (Gast)


Lesenswert?

ach, das sind noch keine Pointer. Die Pointer sollen später kommen.

von Markus (Gast)


Lesenswert?

> von J. T. (chaoskind)

Kleiner Tipp zur Forumsformatierung: Nimm mal den C-Code Tag statt des 
reinen Code-Tags, dann wird der Code auch richtig dargestellt.

von Markus (Gast)


Lesenswert?

Ich nehm's zurück: Du hast es im letzten Post ja schon korrigiert.

von W.S. (Gast)


Lesenswert?

J. T. schrieb:
> Als erstes erzeuge ich ein struct Feld...

Tja, deine Herangehensweise hat sich nicht geändert. Zuerst etwas machen 
und dann erst sich Gedanken um die Folgen machen. Ich würde dir eher 
vorschlagen, zuerst dein Spielfeld zu konstruieren. Das hat einzelne 
Felder, wo Gras wachsen kann, entweder grad abgefressen oder mehr oder 
weniger nachgewachsen. Es mag auch sein, daß in so einem Feld ein Hase 
sich befindet, lebendig oder tot, Hase oder Häsin, bei Häsin entweder 
schwanger oder nicht und wenn, wie lange schon. Obendrein kann sich in 
einem Feld ein Fuchs befinden, hungrig oder nicht.

Das sind alles mögliche Eigenschaften eines Feldes und sie benötigen 
kein Reservieren oder Zurückgeben von Platz auf dem Heap. Das Einzige, 
was du allerdings nur einmal zu machen brauchst, ist die Konstruktion 
des Spielfeldes. Dessen Felder sollen ja wohl nicht zu klein, aber auch 
nicht zu groß sein, sondern nur so groß, daß man darauf erkennen kann, 
was für einen Zustand das Feld hat: abgefressen oder nachgewachsen, 
Hase/Fuchs drauf usw.

Wenn du schon ein Spiel basteln willst, dann kläre zu allererst die 
generellen Dinge ab. Die Realisierung der Details kommt viel später.

W.S.

von J. T. (chaoskind)


Lesenswert?

W.S. schrieb:
> Als erstes erzeuge ich ein struct Feld...

Das waren doch nur Gedankenstümpfe wieder im Zusammenhang mit malloc.

W.S. schrieb:
> Das hat einzelne Felder, wo Gras wachsen kann, entweder grad abgefressen
> oder mehr oder weniger nachgewachse...

Genauso mache ich es doch. Schau dir den angehängten Quelltext an.

von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> Zumindest verstehe ich nicht, warum es mit malloc/realloc nicht
> funktioniert hat. Bekomme aber irgendwie auch nicht so recht den Punkt
> gefasst, wo es mit dem Verständnis hapert.

Vergiss realloc. Du verbeisst Dich da, wie schon gesagt:

A. S. schrieb:
> (Und ja, es gibt sogar einen Befehl, mit dem Du genau das machen
> könntest. Aber auch der führt ins Chaos im jetzigen Projekt, also
> sprechen wir nicht drüber)

Dein Problem mit Malloc: Malloc ist dafür da, den konkreten Speicher für 
einen (oder n) Hasen in einem Feld zu erzeugen. Das macht nur Sinn, wenn 
Du z.B. in den Feldern n Pointer für Hasen vorhälst, z.B. 5 oder 10. Die 
sind dann 0 (kein Hase) oder zeigen zu einem mit malloc reservierten und 
später mit free gekillten Hasen.

Also nochmal: Malloc ist dafür da, einzelne Hasen zu erzeugen, die nicht 
in einer globalen Liste stehen! Sondern je per ptr referenziert werden.

Generell erzeugt man mit Malloc eigentlich einzelne Instanzen, die über 
"in der Instanz bereitgehaltene" Ptr verkettet sind. Sogenannte linked 
lists oder verkettete Listen. Also der "Next"-Ptr in der Instanz zeigt 
auf den nächsten. Man hat dann nur einen Ptr "ErsteInstanz", die 0 ist 
solange keine existiert. Und wenn die erste Erzeut wird, wird deren 
Adresse ErsteInstanz zugewiesen. Und wenn die zweite erzeugt wird, dann 
ErsteInstanz->Next. Und dann ErsteInstanz->Next->Next usw. Aber 
natürlich iterativ.

Natürlich kannst Du auch mit malloc und realloc eine Gesamtliste 
pflegen, doch dann kannst Du besser (wie empfohlen und umgesetzt) 
statisch agieren.

Und natürlich kannst Du eine Gesamtliste der erzeugten Hasen pflegen, 
(z.B. wenn Dein Spielfeld größtenteils leer ist), aber dann z.B. mit 
einer doppelt verketten List.

Das Problem ist, dass a) nicht klar wird, was Du schon kennst und Du b) 
nicht bereit bist, die Basics (Ptr-Handling, Malloc) an einfachen 
Beispielen zu erforschen.

von Einer (Gast)


Lesenswert?

W.S. schrieb:
> Das sind alles mögliche Eigenschaften eines Feldes und sie benötigen
> kein Reservieren oder Zurückgeben von Platz auf dem Heap. Das Einzige,
> was du allerdings nur einmal zu machen brauchst, ist die Konstruktion
> des Spielfeldes.

Naja, es gibt halt (mindestens) zwei Blickwinkel auf das Spiel:

a.) In jeder Parzelle ist Platz für einen möglichen Hasen. Dann müssen
    alle Hasen auf dem Spielfeld bei Bedarf zusammengesucht werden.

b.) Es gibt eine Liste mit Hasen, und bei jedem Hase in dieser Liste
    steht, auf welcher Position (Parzelle) des Spielfelds er gerade
    steht.

Es kommt halt auf das ursprüngliche Problem drauf an, welche 
Organisation am Besten ist. Die Zwischenform(en), dass in jeder Parzelle 
zwischen 0 und N Hasen gespeichert werden können, gibt's ja auch noch...

Ein Klassiker: Welche Datenstruktur wähle ich für das Problem.

Die passende Wahl einer Datenstruktur für ein Problem, ist meistens über 
50% der Lösung.

von cppbert (Gast)


Lesenswert?

Ein paar Tips mit denen du die Lesbarkeit deines Codes stark verbessern 
könntests

1. mehr Funktionen - auch für sowas triviales wie

rand()%10
rand()%2
und ( (unsigned)(rand()%10 - 5) )

du verwendet sie mehrfach mit der gleichen Bedeutung - steckt die in 
Einzeiler-Funktionen mit sinnvollem Namen - z.B. Geburtenrate oder 
Grashoehe usw.

2. lass das mit den while-Schleifen und diesem ++x,y=0 irgendwo 
Kilometer weiter drunter - das ist total unleserlich - nutze 
for-Schleifen - Bitte!!!

Deins:
1
void WeltAendern()
2
{
3
    unsigned x = 0;
4
    unsigned y = 0;
5
6
    while(x < SpielfeldgroesseX)
7
    {
8
        while(y < SpielfeldgroesseY)
9
        {
10
            if(SF[x][y].ZSA>9 && SF[x][y].ZSA%Graswuchsrythmus == 0)
11
            {
12
                SF[x][y].GH++;
13
                if(SF[x][y].GH >= 10)
14
                {
15
                    SF[x][y].GH = 10;
16
                }
17
            }
18
            SF[x][y].ZSA++;
19
            y++;
20
        }
21
        y = 0;
22
        x++;
23
    }
24
    x = 0;
25
}
26
[c]
27
28
Besser - weniger komplex - auf den 1. Blick ohne rauf/runter schaue zu erkennen was die Schleifen machen
29
30
[c]
31
void WeltAendern()
32
{
33
  unsigned x = 0;
34
  unsigned y = 0;
35
  sFeld* aktFeld = 0;
36
37
  while(x = 0; x < SpielfeldgroesseX; ++x)
38
  {
39
    while(y = 0; y < SpielfeldgroesseY; ++y)
40
    {
41
      sFeld* aktFeld = &SF[x][y];
42
  
43
      if((aktFeld.ZSA > 9) && (aktFeld.ZSA % Graswuchsrythmus) == 0)
44
      {
45
          aktFeld->GH++;
46
          if(aktFeld->GH > 10)
47
          {
48
              aktFeld->GH = 10;
49
          }
50
      }
51
      aktFeld->ZSA++;
52
    }
53
  }
54
}
55
[c]
56
57
3. du machst 1 Mio mal solche re-Indizierungen - das ist visuell super strssig und hilft nur dabei Fehler zu machen
58
59
Deins:
60
61
[c]
62
...
63
if(SF[x][y].GH > 0)              //Wenn Gras da ist, fressen,
64
{
65
    SF[x][y].GH--;
66
    SF[x][y].ZSA = 0;
67
    if(HList[i].Hunger > 0)
68
    {
69
        HList[i].Hunger--;
70
    }
71
    HList[i].ZoF = 0;
72
73
    if(HList[i].Hunger == 0)            //Wenn kein Hunger mehr, Stärke erhöhen
74
    {
75
        HList[i].Staerke++;
76
        if(HList[i].Staerke >= 10)
77
        {
78
            HList[i].Staerke = 10;
79
        }
80
    }
81
}

Besser - viel geringere visuelle komplexität:
1
...
2
sFeld* aktFeld = &SF[x][y];
3
sHase* aktHase = &HList[i];
4
5
if(aktFeld->GH > 0)              //Wenn Gras da ist, fressen,
6
{
7
    aktFeld->GH--;
8
    aktFeld->ZSA = 0;
9
    if(aktHase->Hunger > 0)
10
    {
11
        aktHase->Hunger--;
12
    }
13
    aktHase->ZoF = 0;
14
15
    if(aktHase->Hunger == 0)            //Wenn kein Hunger mehr, Stärke erhöhen
16
    {
17
        aktHase->Staerke++;
18
        if(aktHase->Staerke > 10)
19
        {
20
            aktHase->Staerke = 10;
21
        }
22
    }
23
}

das würde schon viel ausmachen

5. einen Header machen in dem deine Konstante und ALLE Funktionen drin 
sind
ist nur dann sinnvoll wenn du eine Library daraus machst und auch alles 
öffentlich Verwendung findet - ansonsten
so viel Implementierungsdetails in der C-Datei verstecken wie möglich - 
alles andere wirkt so als glaube man das wäre professionell

diese #define im Header macht nur ganz ganz ganz alte Hasen - aber ich 
verstehe warum das die Einsteiger so gerne kopieren - die Bücher und 
Tutorial sind voll mit solchen Beispielen






die Kritik der anderen verstehe ich - aber das wird schon über die Zeit 
besser

von A. S. (Gast)


Lesenswert?

cppbert schrieb:
> ansonsten
> so viel Implementierungsdetails in der C-Datei verstecken wie möglich -
> alles andere wirkt so als glaube man das wäre professionell

Die 5 Punkte kann ich alle unterschreiben! (Den 4. durch Deduktion)

von J. T. (chaoskind)


Lesenswert?

cppbert schrieb:
> mehr Funktionen - auch für sowas triviales wie

Das hab ich mir auch schon überlegt und für die nächste Session 
vorgenommen, wenn ich mal wieder ein-zwei zusammenhängende Stunden 
finde.

cppbert schrieb:
> lass das mit den while-Schleifen und diesem ++x,y=0 irgendwo Kilometer
> weiter drunter - das ist total unleserlich - nutze for-Schleifen -
> Bitte!!!

Das wird mir schwer fallen, das mach ich schon immer so, das steckt tief 
drin. Und ich finde es ehrlichgesagt irgendwie logischer. Erst das 
abhandeln, bei dem der Zähler auf Null ist, dann den Zähler erhöhen. 
Eingeschlichen hat sich das ganze übrigens weil ich irgendwann mal das 
Gefühl hatte, die for-schleife würde erst den Zähler erhöhen. und dann 
den Krams abarbeiten. Das fand ich doof, es brannte sich ein, der Fehler 
lag dann aber doch woanders.
In deiner Version zu 2 scheint sich aber ein Fehler eingeschlichen zu 
haben? Du schreibst while und in die Klammer dann for-Syntax. Soll dass 
so, oder hattest du vorher nur zu oft ans while denken müssen, weil du 
es mir austreiben willst? :D

Dein 3tens gefällt, das werde ich versuchen mir anzugewöhnen. Wobei ich 
nicht genau weiß, was du mit den Reindizierungen meinst.

cppbert schrieb:
> diese #define im Header macht nur ganz ganz ganz alte Hasen -

Also meinen ersten Kontakte mit C waren irgendwann Mitte Ende der 
neunziger.  Aber dann gab es auch immer wieder laaange Strecken, in 
denen ich nichts gemacht hab.


Irgendwie sehe ich mich auch nicht wirklich als den großen 
Programmierer, der seinen Krams irgendwann veröffentlichen will, sondern 
schreib das ursprünglich nur für mich. Denke daher nur wenig an 
Konventionen, und mach viel nach "Irgendwie geht's schon".
Ist dann natürlich doof, wenn man mal Hilfe braucht. :D


Ich danke dir recht herzlich, für deinen durchdachten und 
wohlformulierten Beitrag, der ganz ohne Gehässigkeiten und Beleidigungen 
auskommt. Davon sollten sich einige Teilnehmer dieses Forums mal eine 
Scheibe abschneiden

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Einer schrieb:
> Naja, es gibt halt (mindestens) zwei Blickwinkel auf das Spiel:

Ich hab dann b genommen. Hatte deinen Beitrag eben übersehen.

von W.S. (Gast)


Lesenswert?

J. T. schrieb:
> W.S. schrieb:
>> Das hat einzelne Felder, wo Gras wachsen kann, entweder grad abgefressen
>> oder mehr oder weniger nachgewachse...
>
> Genauso mache ich es doch. Schau dir den angehängten Quelltext an.

Und wozu dann die ganze Herumeierei mit Pointern, Heap, Allocation usw. 
?
Nein, aus deinem Quelltext geht nicht hervor, wie du dein Vorhaben 
eigentlich anpacken willst. Und dort lange herumzusuchen ist mir zu 
mühsam.

W.S.

von cppbert (Gast)


Lesenswert?

W.S. schrieb:
> Und wozu dann die ganze Herumeierei mit Pointern, Heap, Allocation usw.
> ?
> Nein, aus deinem Quelltext geht nicht hervor, wie du dein Vorhaben
> eigentlich anpacken willst. Und dort lange herumzusuchen ist mir zu
> mühsam.

er hat in der Folge der Kommunikation ja gesagt das er auf malloc 
erstmal verzichtet weil ihm geraten wurde das erstmal ohne zu 
implementieren

von J. T. (chaoskind)


Lesenswert?

W.S. schrieb:
> Nein, aus deinem Quelltext geht nicht hervor, wie du dein Vorhaben
> eigentlich anpacken willst.

Da das Programm genau tut, was ich mir gedacht hab, und es lustigerweise 
auch so im Quelltext steht, würde dass schon daraus hervorgehen, wenn du 
dich damit befassen würdest. Möchtest du nicht, ist ja auch ok, aber 
dann halte dich doch bitte mit Behauptungen zurück.

cppbert schrieb:
> er hat in der Folge der Kommunikation ja gesagt das er auf malloc
> erstmal verzichtet weil ihm geraten wurde das erstmal ohne zu
> implementieren

Danke

von A. S. (Gast)


Lesenswert?

J. T. schrieb:
> cppbert schrieb:
>> er hat in der Folge der Kommunikation ja gesagt das er auf malloc
>> erstmal verzichtet weil ihm geraten wurde das erstmal ohne zu
>> implementieren
>
> Danke

Du musst dann aber auch dabei sagen, dass Du Dich bisher strikt 
geweigert hast, Dich mit den Konzepten von malloc und Zeigern 
auseinander zu setzen.

Du hattest (und hast?) Dein Bild von einer Liste, deren Größe Du mit 
Malloc erweiterst bzw. mit Realloc vergrößerst.

Das ist so ungefähr so sinnvoll, wie eine for-Schleife durch while 
nachzubauen, nur weil Syntax und Funktion von for zu komplex ist.

Zudem hast Du mehrfach Pointer und Datenfeld (Also Referenz und Inhalt) 
verwechselt bzw. einfache Ptr-Operationen (wie ptr++ statt 
ptr+=sizeof(*ptr) ) noch nicht verinnerlicht. Das wäre nicht schlimm, 
wenn Du das dann nicht in ein komplexes System einflechten möchtest und 
am Ende fragst: Warum geht das nur manchmal?

von Tobias .. (bitfehler)


Lesenswert?

J. T. schrieb:
> Ich versuche ein Game of Life zu schreiben, das "mehr Möglichkeiten" als
> Conways bietet, und erhoffe mir dadurch mehr Komplexität und
> Lebendigkeit reinzukriegen.

Nur als zusätzliche Info und vielleicht Hilfe für andere:
Du implementierst hier Wator (https://de.wikipedia.org/wiki/Wator) nur 
mit Hasen / Füchsen anstatt Fische \ Haie.

: Bearbeitet durch User
von J. T. (chaoskind)


Lesenswert?

Tobias .. schrieb:
> Nur als zusätzliche Info und vielleicht Hilfe für andere:
> Du implementierst hier Wator (https://de.wikipedia.org/wiki/Wator) nur
> mit Hasen / Füchsen anstatt Fische \ Haie

Oh, danke für den Hinweis, das kannte ich noch nicht.

von J. T. (chaoskind)


Lesenswert?

Es fallen mir aber auch gleich ein paar Unterschiede auf. Bei Wator ist 
die Nahrungsquelle für die Herbivoren unbegrenzt, bei mir wächst auch 
das Gras begrenzt nach. Und die haben es so implementiert, das auf einem 
Feld nur ein Viech sein kann, das Feld sich also quasi merkt, ob es nen 
Viech auf sich hat oder nicht. Bei mir ist es genau andersrum, das Viech 
merkt sich auf welchem Feld es ist. Davon ab sind sich die beiden schon 
sehr ähnlich.

Warum fallen mir eigentlich immer nur Dinge ein, die es schon gibt :D

: Bearbeitet durch User
von Tobias .. (bitfehler)


Lesenswert?

J. T. schrieb:
> Es fallen mir aber auch gleich ein paar Unterschiede auf.

Ich muss gestehen, ich hab den Thread hier nur schnell überflogen ob so 
ein Hinweis schon gab.
Dein Eingangsposting hatte schon sehr Ähnlichkeiten damit, daher die 
Verlinkung. ;)

von J. T. (chaoskind)


Lesenswert?

Tobias .. schrieb:
> Dein Eingangsposting hatte schon sehr Ähnlichkeiten damit, daher die
> Verlinkung. ;)

Jo, sagte ich dann ja auch, die beiden sind sich schon sehr ähnlich, und 
mein Einwand mit Erwähnung der Unterschiede war auch keinesfalls als 
Abwehr oder so gedacht. Im Gegenteil, ich freue mich immer über solche 
Hinweise, vor allem, wenn sie wie von dir einfach als Einwurf gegeben 
werden. Und nicht ein implizites "du bescheuerter Idiot" mitschwingt. 
Daher alles gut =)

von W.S. (Gast)


Lesenswert?

J. T. schrieb:
> Und die haben es so implementiert, das auf einem
> Feld nur ein Viech sein kann, das Feld sich also quasi merkt, ob es nen
> Viech auf sich hat oder nicht. Bei mir ist es genau andersrum, das Viech
> merkt sich auf welchem Feld es ist.

Eben weil du mit dem Kopf durch die Wand willst, indem du nicht die 
Karnickel als einfach zu managendes Feld der Gras-Parzellen deines 
Spielfeldes betrachten willst, sondern umgekehrt.

So ein Hase kann sich vermehren oder auch gefressen werden, die 
Gras-Parzelle kann schlimmstenfalls leergefressen sein und braucht Zeit 
um nachzuwachsen, also ist die Parzelle etwas, das du statisch anlegen 
kannst und nicht im Spielverlauf löschen oder neu kreieren mußt, bei den 
Hasen und Füchsen hingegen ist das allzeit erforderlich.

W.S.

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.