Forum: Compiler & IDEs c code sauberer structurieren, Pointer , Rekursion


von imperator (Gast)


Lesenswert?

Servus,
ich möchte eine minimax Funktion erstellen. Es funktioniert auch aber 
irgendwie finde ich die Lösung nicht befriedigend.

Ein array ist global definiert:
1
uint8_t field [ROW][COL];

Dieses muss in der minimax Funktion copiert werden. Das Problem hierbei 
ist, dass ich dann bei jeder Methode den neuen Pointer des arrays 
mitübertragen muss.
1
uint32_t move(uint8_t col, uint8_t *arr);
2
uint32_t get_score(uint8_t player, uint8_t *arr);
3
        
4
uint32_t minimax(uint8_t player, uint8_t *field, uint8_t d){
5
    
6
   for(....) //rekursiv
7
   uint8_t n [ROW][COL];
8
   copy_field(&n, field);
9
   minimax(player, &n, 2);
10
}

Das sind noch mehr Funktionen, welche ich ändern muss. Der Code stammt 
aus java. Dort hat man nur n.move() geschrieben. Voila.

Kann man eine Funktion schreiben, indem man den globalen field 
array/Pointer ändert und wieder rückgängig macht? Was ist sicherer?

von einfach, oder? (Gast)


Lesenswert?


von Jobst Q. (joquis)


Lesenswert?

Deine Frage ist jedenfalls schon mal nicht sauber strukturiert. Es ist 
völlig unklar, worum es dir überhaupt geht.

von KI-Besitzer (Gast)


Lesenswert?

imperator schrieb:

> Kann man eine Funktion schreiben, indem man den globalen field
> array/Pointer ändert und wieder rückgängig macht?

Man kann. Aber kannst Du das?

Und hinter n.move() steckt auch nur etwas unbefriedigendes.

von imperator (Gast)


Lesenswert?

Danke erstmal für die Antworten.

Um das Problem klarer zu beschreiben. Es ist ein globales array 
definiert. "field[][]". Viele Funktionen greifen auf diese globale 
Variable zu allerdings ohne Parameter field.

In einer Funktion muss diese globale array lokal iterativ kopiert 
werden. Dadurch müssen viele Funktionen geändert werden. Man muss immer 
dieses field Parameter dazuschreiben.

Vielleicht ist es bei c auch der richtige Weg um so vorzugehen.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

imperator schrieb:
> Es ist ein globales array definiert. "field[][]". Viele Funktionen
> greifen auf diese globale Variable zu allerdings ohne Parameter field.

Das ist halt ein lausiges Design.

von imperator (Gast)


Lesenswert?

Bei java macht man n.move(q). Ich belasse es so und schreibe halt 
move(n,q).

von imperator (Gast)


Lesenswert?

Rufus Τ. F. schrieb:
> Das ist halt ein lausiges Design.

Deswegen frage ich ja nach. Wie sollte es besser ausehen?

von A. S. (Gast)


Lesenswert?

Wie sieht es denn jetzt aus?

von Nop (Gast)


Lesenswert?

Du kopierst in dieser Anwendung das Spielfeld normalerweise gar nicht, 
sondern Du machst in der Interationsschleife über die Züge einfach jeden 
Zug in diesem Feld, so wie es Deiner minimax-Methode übergeben wird, und 
machst ihn dann wieder rückgängig.

Eventuall brauchst Du dazu noch einen Zustands-Stack, weil z.B. bei 
Schach ein Königszug das Recht auf Rochade verwirken kann - das siehst 
Du bei der reinen Rücknahme dem Zug selber aber nicht mehr an.

von imperator (Gast)


Lesenswert?

Achim S. schrieb:
> Wie sieht es denn jetzt aus?

Lausig laut Admin.

Ich mache das hier ja nur aus Spaß.

Ist schon interessant bei der minimax Funktion in die "Zukunft" zu gehen 
und alle möglichen Züge zu bewerten und das Beste rauszupicken. Dabei 
sollte aber das Programm nicht zusammenfallen. Ich melde mich dann noch, 
falls ich nichtweiter komme. Danke an für die rege Beteiligung.

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

imperator schrieb:
> Deswegen frage ich ja nach. Wie sollte es besser ausehen?

Keine globalen Variablen verwenden, sondern alle Funktionen so 
schreiben, daß alle relevanten Informationen (Adresse des Arrays und 
Größeninformationen) den Funktionen übergeben werden. In den Funktionen 
selbst sollten keinerlei Informationen verwendet werden, die nicht in 
ihrer Argumentenliste stehen.

Dann kann man die Funktionen problemlos wiederverwenden, dann könnte man 
auch ein verändertes Programm mit zwei oder mehreren zu bearbeitenden 
Arrays schreiben und müsste nur beim Aufruf der Funktionen das konkret 
zu nutzende Array angeben.

von Jobst Q. (joquis)


Lesenswert?

Rufus Τ. F. schrieb:
> Keine globalen Variablen verwenden, sondern alle Funktionen so
> schreiben, daß alle relevanten Informationen (Adresse des Arrays und
> Größeninformationen) den Funktionen übergeben werden. In den Funktionen
> selbst sollten keinerlei Informationen verwendet werden, die nicht in
> ihrer Argumentenliste stehen.

Riesige Argumentenlisten sind aber nicht gerade guter Stil, 
unübersichtlich und leicht fehleranfällig. Vermeiden lässt sich das 
durch geeignete Strukturen und jeweils einem Pointer auf diese Struktur, 
der übergeben wird.

Das ist dann Objektorientierung zu Fuß.

von Bernd K. (prof7bit)


Lesenswert?

Jobst Q. schrieb:
> Das ist dann Objektorientierung zu Fuß.

Das ist dann Objektorientierung.

(Ich hab den Tippfehler mal korrigiert)

von Rufus Τ. F. (rufus) Benutzerseite


Lesenswert?

Auf welche Art und Weise die Parameter übergeben werden, ist natürlich 
eine Frage der Übersichtlichkeit, sie aber in eine Struktur zu verpacken 
und das dann "Objektorientiert" zu nennen, ist ein bisschen arg 
hochtrabend.

Entscheidend aber ist das auch dann erreichte Ziel, keine globalen 
Variablen zu verwenden, und alle relevanten Informationen den jeweiligen 
Funktionen zu übergeben.

von imperator (Gast)


Lesenswert?

Servus,
Danke erstmal. Ich versuche mit Strukturen als Pointer Übergabe Herr zu 
werden.

Ich bin heute auswärts und habe gestern abends noch mit 
Harddefaulthandler zu tun. Aufgrund der Rekursion bekomme an 2. Ebene 
diesen Fehler beim return.

Wie muss man die Variablen in der rekursiven Funktion deklarieren? Ich 
habe heap und Stack großzügig erhöht. Beim cortex m3 dürfte ich keine 
Ressourcen Probleme bekommen. Ich benutze embitz.

Wie kann ich anhand der map Datei eine mögliche Kollision erkennen? 
Sollte man beim Aufruf alle Interrupts deaktivieren?

von Nop (Gast)


Lesenswert?

imperator schrieb:
> Aufgrund der Rekursion bekomme an 2. Ebene
> diesen Fehler beim return.

Du mußt natürlich dafür sorgen, daß die Rekursion auch terminiert!

Typischerweise bekommt die minimax-Funktion einen Parameter für die 
Tiefe und prüft ganz zuerst, ob die übergebene Tiefe <= 0 ist. Falls dem 
so ist, ruft sie eine Art statischer Stellungsbewertung auf und gibt 
deren Wert zurück.

Falls die übergebene Tiefe > 0 ist, ruft minimax beim rekursiven Aufruf 
sich selbst auf, aber mit Tiefe um 1 weniger als das, was ihr übergeben 
wurde.

Wenn ich mir die Deklaration Deiner Funktion ansehe, dann ist da kein 
Parameter für die Tiefe. Daher vermute ich, daß Deine Rekursion nicht 
terminiert, sondern solange tiefer geht, bis Dein Stack überläuft - egal 
wie groß Du den machst.

von imperator (Gast)


Lesenswert?

Servus,
Danke erstmal für die tollen Tipps. Der Fehler bei lag an einer flachen 
Kopie. Mit memcpy() wird in der 2. Ebene die Rücksprungaddresse vom 1. 
Pointer überschrieben. Bei structs kann man eine tiefe Kopie einfach mit 
den Zuweisungoperator bewerkstelligen.

Hier die Quelle zum nachlesen:
http://blog.zhangliaoyuan.com/blog/2013/01/28/structure-assignment-and-its-pitfall-in-C-language/

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.