void Random(Piece *piece) { int random1; int random2; do { random1 = 1 + rand() % 3; random2 = 1 + rand() % 3; } while (!kaytetty[random1][random2]); kaytetty[random1][random2] = 1; piece->blockx = random1; piece->blocky = random2; }
tuon funktion ansiosta ohjelma kaatuu heti käynnistämisen jälkeen. voi toki olla, että jossain muualla koodissa esiintyy virhe ja heijastuu tähän, mutta toivotaan, että se vika löytyy tästä. jos poistan tämän funktion ja kaikki paikat, jossa tätä kutsutaan, ohjelma toimii moitteettomasti.
EDIT: Kutsuminen tapahtuu tällälailla:
Random(pic[x][y]);
Kääntämisen aikaisia ongelmia ei ole.
Onko 'kaytetty'-taulukko alustettu tai edes luotu ennen tuota funktiota?
Käytäpä kooditageja, kiitos.
Olisi myös kiva tietää, miten on määritelty:
pic
kaytetty
Veikkaisin että vika on seuraava: Jos taulukko on esim:
Piece palat[3];
niin alkioita ovat 0, 1 ja 2. Tuolla näyttäisi olevan "1 + rand() % 3", josta tulee 1, 2 tai 3.
FooBat: Alustamisellahan ei tuossa ole käytännön merkitystä, ja jos sitä ei olisi luotu, kääntäjä ilmoittaisi asiasta. Oletan siis että luominen tapahtuu jo määrittelyssä ("bool kaytetty[3][3];" , ei "bool **kaytetty;")
int kaytetty[3][3];
alustettu globaaliksi.
Piece *pic[3][3]; for (x = 1;x<5;x++){ for (int y;y<5;y++){ Random(pic[x][y]); } }
Kooditagi:
[koodic] Koodia Koodia Koodia [/koodic]
Ongelma on juuri tuo, jonka äsken mainitsin: Taulukon alkiot ovat 0, 1 ja 2, mutta satunnaislukusi on väliltä 1 - 3, jolloin voidaan osoittaa taulukon ulkopuolelle.
Tämä on siis ratkaisu:
Muuta tämä:
random1 = 1 + rand() % 3; random2 = 1 + rand() % 3;
Tällaiseksi:
random1 = rand() % 3; random2 = rand() % 3;
Alustamisella on se merkitys, että C-kääntäjä ei takaa, että uudet taulukot sisältäisivät vain nollaa. Usein asia on aivan päinvastoin. Ei se kyllä ohjelmaa tuossa tapauksessa saisi kaatumaan, mutta silmukka keskeytyisi ennen aikojaan.
Tässä tapauksessa ongelma tosiaa taitaa olla se, että indeksit alkavat C:ssa nollasta.
Piece *pic[3][3]; for (x = 1;x<5;x++){ for (int y;y<5;y++){ Random(pic[x][y]);
Y:ltä puuttuu alustus ja eikös tuossa täytetä [0..2][0..2] taulukkon [1..4][?..4] kohdat?
Nyt olen muuttanut ohjelman taulukot oikein, mutta se kaatuu vieläkin. (vähän erilailla)
koko koodi on tässä:
#include <SDL/SDL.h> #include <stdio.h> #include <stdlib.h> #include <time.h> SDL_Surface *back; SDL_Surface *image; SDL_Surface *screen; int picx = 80; int picy = 140; int resx = 200; int resy = 200; int x_maara = 4; int y_maara = 4; int kaytetty[4][4]; int xpos = 1; int ypos = 1; int placex[4]; int placey[4]; //liikaa globaaleja muuttujia... class Piece { public: Piece(int homeblockx, int homeblocky) {homex = homeblockx; homey = homeblocky;} int blockx; int blocky; int homex; int homey; }; void DrawIMG(SDL_Surface *img, int x, int y) { SDL_Rect dest; dest.x = x; dest.y = y; SDL_BlitSurface(img, NULL, screen, &dest); } void DrawIMG(SDL_Surface *img, int x, int y, int w, int h, int x2, int y2) { SDL_Rect dest; dest.x = x; dest.y = y; SDL_Rect dest2; dest2.x = x2; dest2.y = y2; dest2.w = w; dest2.h = h; SDL_BlitSurface(img, &dest2, screen, &dest); } int SDL_BlitSurface(SDL_Surface *src, SDL_Rect *srcrect, SDL_Surface *dst, SDL_Rect *dstrect); void DrawScene() { DrawIMG(back, 0, 0); DrawIMG(image, picx, picy); SDL_Flip(screen); } void Random(Piece *piece) { int random1; int random2; do { random1 = rand() % 3; random2 = rand() % 3; } while (!kaytetty[random1][random2]); kaytetty[random1][random2] = 1; piece->blockx = random1; piece->blocky = random2; } int main(int argc, char *argv[]) { if (SDL_Init(SDL_INIT_VIDEO|SDL_INIT_AUDIO) < 0) { printf("Error to Init yms.. %s\n", SDL_GetError()); exit(1); } atexit(SDL_Quit); screen = SDL_SetVideoMode(640, 480, 32, SDL_HWSURFACE|SDL_DOUBLEBUF); if (screen == NULL) { printf("Unable to set video mode.. sry .. &s\n", SDL_GetError()); exit(1); } back = SDL_LoadBMP("bg.bmp"); image = SDL_LoadBMP("image.bmp"); Piece *pic[4][4]; for (int i=0;i<4;i++){ for (int ii=0;ii<4;ii++){ Random(pic[i][ii]); } } for (i=0;i<x_maara;i++) placex[i] = picx+i*(resx/4); for (i=0;i<y_maara;i++) placey[i] = picy+i*(resy/4); DrawIMG(back, 0, 0); DrawIMG(image, picx, picy); SDL_Flip(screen); Uint8* keys; int done=0; while(done == 0) { SDL_Event event; while ( SDL_PollEvent(&event) ) { if ( event.type == SDL_QUIT ) { done = 1; } if ( event.type == SDL_KEYDOWN ) { if ( event.key.keysym.sym == SDLK_ESCAPE ) { done = 1; } } } keys = SDL_GetKeyState(NULL); if ( keys[SDLK_UP] && ypos != 0 ) { ypos -= 1; } if ( keys[SDLK_DOWN] && ypos != y_maara-1 ) { ypos += 1; } if ( keys[SDLK_LEFT] && xpos != 0 ) { xpos -= 1; } if ( keys[SDLK_RIGHT] && xpos != x_maara-1 ) { xpos += 1; } if ( keys[SDLK_RETURN] || keys[SDLK_SPACE] ) {done = 1;} DrawScene(); } return 0; }
ja binääri (kuvien kera): http://zux.sjr.fi/moks/Col.game.zip
voiko se johtua Piece*:n alustamisesta?
Olisit heti sanonut että se jumittuu; se on aivan eri asia kuin kaatuminen.
Tässä ongelmasi:
for (int i=0;i<4;i++) { for (int ii=0;ii<4;ii++) { Random(pic[i][ii]); } }
Kutsut tuossa Randomia 16 kertaa (0, 1, 2, 3 moolemmilla muuttujilla) mutta Randomin sisäinen arvonta voi antaa 3 * 3 = 9 erilaista arvoa, jolloin 10. kerralla kaikki mahdolliset arvot on käytetty ja kaytetty[random1][random2] on aina tosi. Tässä siis ohjelmasi jumittuu.
Noihin siis kolmosen paikalle nelonen Random-funktiossa:
random1 = rand() % 4; random2 = rand() % 4;
Se silti jumittuu. (ennen se kaatu ja nyt jumittaa)
void Random(Piece *piece) { int random1; int random2; do { random1 = rand() % 4; random2 = rand() % 4; } while (!kaytetty[random1][random2]); kaytetty[random1][random2] = 1; piece->blockx = random1; piece->blocky = random2; }
muuten täysin sama ohjelma, kuin edellä mainittu.
Mitäpä jos opettelisit hieman perusasioita kuten kääntäjän käyttöä? Sitten voisit laittaa tuonne Breakpointteja ja katsoa, mihin ohjelma jumittuu.
Ja nytten huomasin sen virheenkin: "while (!kaytetty[random1][random2])": ota tuo huutomerkki pois. Nyt nimittäin toistat looppia niin pitkään kuin valittu kohta ei ole käytetty.
Tai käytä klassista printf-debuggausta :)
Kirjoita
printf("foo X\n");
vähän joka väliin mikä voi mennä pieleen.
Tuolla pitäisi pystyä haarukoimaan paikka mihin
ohjelma jää jumiin tai kaatuu.
FooBat: On parempi käyttää Breakpointteja, koska silloin voi (ainakin kunnon kääntäjissä) valvoa muuttujien arvoja. Voihan sellaisen toki laittaa printtautumaan ruudullekin, mutta se on yksinkertaisesti huonompi tapa. Sitä paitsi, graafisissa ohjelmissa ei ole kovin mukavaa printtailla ruudulle ylimääräistä tavaraa.
Metabolix: En sanonutkaan, että se olisi parempi tapa (Siitä syystä se hymiö). Se nyt vaan sattuu olemaan tapa, jota harvinaisen moni ohjelmoija käyttää selvittäessään yksinkertaisia ongelmatapauksia.
Jos ohjelmoi linuksilla kannatta kokeilla Valgrind:ia tai vastaavaa ohjelmaa, jotka löytävät virheelliset muistiviittaukset ja alustamattomat muuttujat hetkessä.
Itsellänikin on tapana etsiä ohjelmista virheitä juuri välitulostusten avulla. Se on helppo ja tehokas tapa ja toimii ohjelmointiympäristöstä riippumatta.
Minäkin olin käyttänyt tuota tapaa ainakin QB:llä, kun en vielä tiennyt, mikä kumma se Immediate on. :)
Käytän kyllä tuota tapaa edelleenkin melko usein. Se tuntuu jotenkin luontevammalta.
No joo... Onhan se ihan käyttökelpoinen joissakin tilanteissa; riippuu täysin, minkä asteista debuggausta tarvitsee. Itselläni on yleensä niin monta asiaa, joita pitää seurata, että ei niitä saa mitenkään iskettyä ruudulle; vaihtoehdot ovat joko yksi breakpointti tai hyvin mutkikas muuttujajärjestelmä jotta saan arvot esille vielä ruudun piirtovaiheessakin. Vielä kun nämä arvot muuttuvat jatkuvasti, on mukavampi tietää ne tietyllä hetkellä.
Kyllä kunnollinen debuggaus on opettelun arvoinen asia :) Tuosta voisi kirjoittaa vaikka oppaan. Breakpointit, single-step-mahdollisuus ja watchit yms. löytyvät muuten myös mm. QBasicistä.
Metabolix: breakpointit (tai muuttujien arvojen seuraaminen) ei kylläkään ole kääntäjäkohtainen juttu, vaan debuggerikohtainen :) Toisinsanoen, kun vain työntää binääriin oikeanlaiset debuggausinfot, niin debuggerina voi käyttää sitä mikä itseään eniten miellyttää.
Windowsilla muistiongelmien löytämiseen voi käyttää NuMegan BoundsCheckeriä, tosin se on maksullinen.
Itse teen yleensä niin että laitan monirivisen kommenttialun johonkin kohtaan, ja sitä ennen tulostan jonkun muuttujan arvon. Loppuun en jaksa laittaa kommentin lopetusta, vaikka PHP siitä valittaakin, tosin vain yhden kerran (outoa muuten...)
Tämänkin olisi toki voinut tehdä käyttämällä avuksi die() funktiota, mutta minusta tuo kommenttijuttu tuntuu jotenkin turvallisemmalta :) (ja helpommalta)
fawkz kirjoitti:
lainaus:
- - ei kylläkään ole kääntäjäkohtainen juttu, vaan debuggerikohtainen - -
No ruvetaanpa nyt saivartelemaan. Siinä vaiheessa kun käyttää kunnollista kääntäjää, esim. VC++, ei ole debuggerissa yleensä mitään vikaa, jonka takia sitä pitäisi vaihtaa. Muutenkin, tuskin kovinkaan monella riittää intressejä vääntää Debug Infoaan toiseen debuggeriin.
Jep. Jotkut vaan ei älkkää kun ne käyttää huonompia(mielipide, ei nyt siitä sitten aleta jauhamaan...) ilmais kääntäjiä. Itse ainakin koen tuon VC++:n debug systeemin hyödylliseksi koska sillä on helppo paikantaa vaikkapa jumiutuminen jos ei syntaksivirhettä koodista löydy.
Metabolix kirjoitti:
Muutenkin, tuskin kovinkaan monella riittää intressejä vääntää Debug Infoaan toiseen debuggeriin.
Miten niin ei? :) Ei debuggausinfon sisällyttäminen binääriin vaadi yleensä kuin muutamaa lisävalitsinta kääntäjälle ja näin voidaan esim. MASM:lla assembloituja hommia debugata paljon kätevämmin. Monesta kääntäjäpaketista kunnollinen debuggeri puuttuu, eihän sitä löydy esim. MSVC++:n ilmaisistakaan versioista.
Aihe on jo aika vanha, joten et voi enää vastata siihen.