seltsame access violation
-
also ich hab hier ein progamm, das an sich eine der aufgaben der ersten runde des bw informatik lösen soll und dies die meiste zeit auch tut. es soll halt einen würfel schweitzer käse auf wasserdurchlässigkeit hin überprüfen (genaueres entnehme man der aufgabenbeschreibung des bw informatik www.bwinf.de)
das macht es halt so hübsch rekursiv anhand eines mehrdimensionalen arrays (im heap wohlgemerkt... es hat also funktioniert [s. "arrays im heap"]). naja als ich das mit der tollen autorenversion vc++6 kompiliert hab lief es ohne zu meckern, also hab ichs mal vom mingw kompilieren lassen und der hat da meine fehler nicht so kaschiert. wenn man nur eine geringe anzahl von wiederholungen eingibt (unsigned short int oft; ) geht alles gut, wenn man die anzahl jedoch erhöht (so auf 50) kommt es zu einem/r seltsamen access violation.
das programm läuft einwandfrei bis es die schleife abgearbeitet hat und sein ergebnis ausgeben soll, jetzt hängt es davon ab, ob man es mit dem mingw kompiliert hat, dann gibt es als letztes "Bei einer Käsewahrscheinlichkeit von " aus und stürzt ab, mit dem vc++ kommt noch das ganze letzte cout raus bevor es dann beendet wird (allerdings ohne auffälliges popup). Es hilft auch nichts das letzte cout wegzulassen oder überhaupt alles nach der letzten schleife wegzulassen, es kommt trotzdem zu diesem fehler.
ich kann mir das gar nicht erklären. ich hatte vorher auch schon reichlich access violations aber das lag daran das ich nicht aufgepasst hab beim zugreifen auf wuerfel und über die arraygrenzen geschrieben hab. aber das ist ist ja an einer so abnormen stelle das ich nicht mal den hauch einer idee hab woran das liegen kann...interessanterweise (vielleicht auch nicht...) ist die addresse immer die selbe auch wenn man das programm neu startet.
wenn man genauer hinkuckt merkt im übrigen auch vc++ das da was faul ist.
so. und damit ihr es euch mal ankucken könnt (merke: auch wenn in der ersten runde gruppenarbeit noch erlaubt ist, hätt ich doch gern credits wenn ihr euch meine lösung zumindest teilweise klaut):
#include <iostream> #include <stdlib.h> #include <ctime> using namespace std; void fillcube (unsigned char(* wuerfel)[19][19], unsigned short int p); bool pourwater(unsigned char(* wuerfel)[19][19], unsigned char x, unsigned char y, unsigned char z); int main() { unsigned char (* wuerfel)[19][19] = new unsigned char [19][19][19]; //repräsentation eines 20*20*20 käsewürfels srand ( (unsigned) time(NULL)); cout << "Gib die Wahrscheinlichkeit für Käse in Prozent ein: \n"; unsigned short int p; cin >> p; cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cout << "Gib ein, wie oft mit dieser Wahrscheinlichkeit der Durchlässigkeitstest gemacht werden soll: \n"; unsigned short int oft; cin >> oft; cout << "Danke\n"; unsigned short int durchlaessig=0; for (short int i=oft; i>0; i--) { cout <<"."; fillcube(wuerfel, p); cout << "Wuerfel "<< i << endl; cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.ignore(); if (pourwater(wuerfel, 0,0,0)) {durchlaessig++;} } cout << endl; cout << "Bei einer Käsewahrscheinlichkeit von " << p << "% waren "<< durchlaessig << " " << (double)durchlaessig*100/(double)oft << "% wasserdurchlässig \n"; delete [] wuerfel; cin.clear(); cin.ignore(cin.rdbuf()->in_avail()); cin.ignore(); return 0; } void fillcube (unsigned char(* wuerfel)[19][19], unsigned short int p) { for (int i=0; i<19;i++) { for (int i2=0;i2<19;i2++) { for (int i3=0;i3<19;i3++) { if (((double)rand()/((double)RAND_MAX+1))<=(double)p/100) {wuerfel[i3][i2][i]=1;} //is käse drin else {wuerfel[i3][i2][i]=0;} //is kein käse drin //cout << (int) wuerfel[i3][i2][i]; } //cout << endl; } //cout << endl; } } bool pourwater(unsigned char(* wuerfel)[19][19], unsigned char x, unsigned char y, unsigned char z) { static int schritte; schritte++; //cout <<(int) x << " " <<(int) y << " " <<(int) z << " " << schritte << endl; if (z==18) { if(wuerfel[x][y][z+1]==0) // wenn wir in den vorletzten ebene sind und der quader drunter leer, die sache beenden {schritte=0; return true;} } for(y; y<=19; y++) { for (x; x<=19;x++) { if (wuerfel[x][y][z]==0) { wuerfel[x][y][z]=3; // diesen quader als durchsucht merken um zirkel zu vermeiden if (z<19) if (wuerfel[x][y][z+1]==0) if (pourwater(wuerfel,x,y,z+1)) return true; if (z>0) if (wuerfel[x][y][z-1]==0) if (pourwater(wuerfel,x,y,z-1)) return true; if (x>0) if (wuerfel[x-1][y][z]==0) if (pourwater(wuerfel,x-1,y,z)) return true; if (x<19) if (wuerfel[x+1][y][z]==0) if (pourwater(wuerfel,x+1,y,z)) return true; if (y>0) if (wuerfel[x][y-1][z]==0) if (pourwater(wuerfel,x,y-1,z)) return true; if (y<19) if (wuerfel[x][y+1][z]==0) if (pourwater(wuerfel,x,y+1,z)) return true; } } } return false; }
-
unsigned char (* wuerfel)[19][19] = new unsigned char [19][19][19]; //repräsentation eines 20*20*20 käsewürfels
Nein, es repräsentiert einen 19*19*19 Würfel (Indices von 0-18).
-
sorry, ich hab mir weder Aufgabenstellung durchgelesen noch bin ich deinen Code durchgegangen, aber
muhkuhmasta schrieb:
unsigned char (* wuerfel)[19][19] = new unsigned char [19][19][19]; //repräsentation eines 20*20*20 käsewürfels
Das ist ein 19x19x19 Wuerfel, kein 20x20x20
-
hm... gut
naja trotzdem... sinds halt nur 19 (kann man ja leicht ändern). der fehler bleibt.
merke das ich glaubte es ginge von 0-19 wenn ich 19 schreibe...
-
muhkuhmasta schrieb:
for(y; y<=19; y++) { for (x; x<=19;x++) {
Nochmal ganz langsam, du musst bei Arrays immer zwischen Dimension und Indexierung unterscheiden. Bei einem n-dimensionalen Array ist es dir nur erlaubt, mit Index 0 bis n-1 zu indexieren. Ansonsten gibts Zugriffsverletzungen und damit UB.
btw:
In C++ nimmt man cstdlib und nicht stdlib.h.
-
also wenn ich int foo[5] schreibe darf ich nur auf foo[4] zugreifen... das ist ja sehr selbsterläuternd gestaltet :D... ok... ich werds mal ändern und kucken obs weg geht... morgen...
-
int foo[5] erstellt 5 Integerwerte welche vom Index her von 0 - 4 gehen
0
1
2
3
4sind wieder die 5 Integerwerten.
-
ich würde hier keine lösung des bwinf mit hinweis darauf, dass es eine lösung fürs bwinf ist hier reinschreiben.
hab grad deine version mit meiner verglichen, imho hatten wir dieselben ideenaber keine bange, ich kopier nix,ist ehrensache
if (((double)rand()/((double)RAND_MAX+1))<=(double)p/100)
kann es sein, dass hier wieder ein fehler drinliegt?
naja egal, ist spät, und ichs teig da jetzt nicht hinter...
ps: mein prog rechnet jetzt schon seit ner halben stunde,ich hoffe aber, dass man mit einer million durchläufe endlich gute statistische werte erreicht-.-
-
wieso denn? rand() liefert werte bis zu rand_max und wenn ich das teile bekomme ich eine zahl zwischen null und eins und wenn die kleiner oder gleich der angegeben wahrscheinlichkeit ist wird das halt gefüllt...
nachdem ich das array größer gemacht hab gehts prima. wieso braucht deins denn so ewig? ich bin der meinung schon mit 1000 durchläufen bekommt man ausgezeichnete ergebnisse (sie unterscheiden sich praktisch nicht von 100 durchläufen, aber...)
ich bastelle grade an so einer tollen commandline version damit ich das ganze in ein batchfile einbinden kann, aber irgendwie liest der die commandozeilenargumente noch nicht richtig... mal sehn ob ich das noch hinbekomme
-
ahh... jetzt geht es.
kann es sein das du vergessen hast die bereits durchsuchten quader zu markieren? mein programm braucht für 1000000 durchläufe weniger als eine minute (für einen prozentssatz versteht sich)
aber seltsamer weise ist (anscheinend) immer einer durchlässig... ich muss irgendwo müll machen mit der durchlässigkeitsvariablen... ich find den fehler schon noch
-
[edit] verdammt doppelt gepostet. löscht das hier mal
ahh... jetzt geht es.
kann es sein das du vergessen hast die bereits durchsuchten quader zu markieren? mein programm braucht für 1000000 durchläufe weniger als eine minute (für einen prozentssatz versteht sich)
aber seltsamer weise ist (anscheinend) immer einer durchlässig... ich muss irgendwo müll machen mit der durchlässigkeitsvariablen... ich find den fehler schon noch
-
ja, lag an ner schleife-.-,atm brauchen 1000 durchläufe ca 3 sekunden, werd das aber nicht emhr weiter optimieren, für geschwindigkeit gibts ja keine punkte^^
btw: wie kommen denn bei dir die werte aus?
hab ingesamt mal 33k durchläufe für verschiedene chancen machen lassen,und das wertbild war dumm, bis 60% fidnet er immer einen wert, zwischen 61 und 75 ist es variabel(mit stark absteigender tendenz) und ab 75 findet er nie einen weghier mal mein code, dann kannste auch vergleichen
bool existWay(Cube& cube,int x,int y,int z){ //zuerst testen wir, ob dieses feld überhaupt noch im würfel enthalten ist //wenn nicht, kann uns dieses feld auch nicht zum Ziel führen if(x<0||x>19||y<0||y>19||z<0||z>19)return false; //testen ob dieses feld überhaupt frei ist, wenn nicht:abbruch(0=frei) //ist es frei, wird getestet, ob das feld ein unteres randfeld ist, //wenn ja, dann haben wir einen weg gefunden if(cube[x][y][z]==1)return false; if(z==19) return true; //das feld ist frei, und kein randfeld,nun müssen wir die funktion //rekursiv erneut aufrufen, um uns weiterzuhangeln //um ein im kreis drehen zu vermeiden, setzen wir dieses feld aber wieder auf 1 cube[x][y][z]=1; //nun testen wir alle 6 felder welche eine seite mit dem feld //welches wir grad testen gemeinsam haben return (existWay(cube,x+1,y,z)||existWay(cube,x-1,y,z)|| existWay(cube,x,y+1,z)||existWay(cube,x,y-1,z)|| existWay(cube,x,y,z+1)||existWay(cube,x,y,z-1)); } bool existWay(Cube& cube){ bool found=false; int x=0; //wir gehen jedes feld der oberen ebene durch, und berechnen für das feld ob es einen weg gibt, wenn ja->schleife abbrechen, wert zurückgeben while(found==false&&x<20){ int y=0; while(found==false&&y<20){ found=existWay(cube,x,y,0); ++y; } ++x; } return found; }
-
meine werte sind ganz ähnlich (auch wenn ich noch nicht alles mal durchgespielt hab sondern noch mit dem program rumteste) ich kann mich auf jeden fall erinnern das bei 70% käse noch 25% durchlässig waren... aber ich mach mal noch ein paar ordentliche durchläufe wenn ich geklärt hab warum er bei 100% käse immer genau 1 durchlässigen findet... lol
-
mal ne frage: du hast da ja ne verschachtelte schleife, die immer die komplette ebene testet,und rekursiv für jede ebene aufgerufen wird, sollte das nicht ein falsches verhalten hervorrufen? dh sollte es dann nicht möglich sein, dass zwar in der ebene ein loch ist, in der ebene darüber aber keine weiterführung existiert(ergo einfach ein loch im käse welches sich nach unten verlängert), und dein programm fälschlicherweise durchlässig zurückgibt?
-
du meinst das es in ebene z(1) kein loch findet und dann in ebene z(2) weitersucht? eigentlich nicht, die einzige möglichkeit in die ebene zu wechseln ist
//hier if (z<19) if (wuerfel[x2][y2][z+1]==0) if (pourwater(wuerfel,x2,y2,z+1)) return true; //oder hier if (z>0) if (wuerfel[x2][y2][z-1]==0) if (pourwater(wuerfel,x2,y2,z-1)) return true;
sonst sucht er nur x und y koordinaten ab
-
ich rede von so einem fall:
legende: 0=frei 1=voll 10111111 10111101 11111101
er würde bei dir durch die schleife in die rechte freie spalte gehen, und am ende durchlässig anzeigen.
erklärung:
er fängt oben links an:
das erste feld ist nicht frei, er spirngt zum 2. feld->frei.
er ruft sich für alle angrenzenden felder selbst auf, und springt somit einen nach unten.
in der 2. zeile sit er nun in feld 2, er prüft->frei, aber alle angrenzenden felder sind voll, die schleife geht weiter nach rechts->voll->voll->voll->voll->frei->selbstaufruf->nach unten springen->ziel.
-
hm... r i c h t i g... verdammt... das wird fix behoben...
-
poste dann die neuen werte
-
ich bin mir jetzt nicht sicher ob es das behoben hat aber
bool pourwater(unsigned char(* wuerfel)[20][20], unsigned char x, unsigned char y, unsigned char z) { if (z==18) { if(wuerfel[x][y][z+1]==0) // wenn wir in den vorletzten ebene sind und der quader drunter leer, die sache beenden {return true;} } for(unsigned char y2=y; y2<=19; y2++) { for (unsigned char x2=x; x2<=19;x2++) { if (wuerfel[x2][y2][z]==0) { wuerfel[x2][y2][z]=3; // diesen quader als durchsucht merken um zirkel zu vermeiden if (z<19) if (wuerfel[x2][y2][z+1]==0) if (pourwater(wuerfel,x2,y2,z+1)) return true; if (x2<19) if (wuerfel[x2+1][y2][z]==0) if (pourwater(wuerfel,x2+1,y2,z)) return true; if (y2>0) if (wuerfel[x2][y2-1][z]==0) if (pourwater(wuerfel,x2,y2-1,z)) return true; if (x2>0) if (wuerfel[x2-1][y2][z]==0) if (pourwater(wuerfel,x2-1,y2,z)) return true; if (y2<19) if (wuerfel[x2][y2+1][z]==0) if (pourwater(wuerfel,x2,y2+1,z)) return true; if (z>0) if (wuerfel[x2][y2][z-1]==0) if (pourwater(wuerfel,x2,y2,z-1)) return true; } // end if if (z!=0) break; } //end x schleifel if (z!=0) break; } //end y schleife return false; }
so schauts jetzt aus. die breaks müssten es daran hindern weiterzusuchen wenn es sich nicht in der obersten ebene befindet. findet es einen durchgang kommt es ja gar nicht so weit... ich hab mal einen probelauf mit 70% gemacht und es kamen bei 1000 würfeln 13,6% raus (wasserdurchlässig). aber ich mach mal nen neuen thread in "rund um die programmierung" auf, denn das hier hat absolut nichts mit access violations zu tun.