Kirjautuminen

Haku

Tehtävät

Keskustelu: Ohjelmointikysymykset: C++: Segmenttivirhe tyhjässä silmukassa

sqwiik [10.11.2004 18:14:27]

#

Törmäsin tässä Erkkiä koodatessani outoon ongelmaan. For-silmukka, jossa asettelen esineet varastoon antaa segmenttivirheen (SIGSEGV - SIGnal: SEGment Violation). Asettelin silmukkaan ja sen ympärille tulosteita että pystyin seuraamaan missä virhe esiintyy; ja kas kummaa, se tulee juuri kun silmukkaa pitäisi lähteä suorittamaan :P
Käytössä siis DJGPP (eli kääntäjänä gcc), DOS-ympäristö. Koodi ei kaadu aina, vaan aina jotenkin satunnaisin käynnistyskerroin (koodi ei aiheuta kaatumista myöskään kesken pelin, vaikka sitä kutsutaan siinä usein).

Koodi on seuraava (aputulosteet paikoillaan). Virheetön suoritus tulostaa seuraavan rivin (b on asetettu 3:ksi):

[3 (...)(...)(...).]

...mutta kaatumatapauksessa, tulostuu vain seuraava:

[3

eikä mitään muuta, eli suoritus pääsee riville printf("%i", b); asti mutta ei sen jälkeen alkavaan for-silmukkaan. Missä olisi vikaa? Varsinkin kun kaatuminen ei todellakaan tapahdu joka kerran.

signed int a, b = rand()%6;
printf("[");
NullItemList(varasto); //resetoidaan varasto
printf("%i ", b);
for(a = 0; a < b; a++){
  printf("(");
  esine.mika_esine = Esine_Raha;
  while(esine.mika_esine==Esine_Raha)RandomEsine(&esine, (float)(rand()%100)/99.0);
  printf(".");
  esine.kunto |= Item_D_Tieto;
  // Ei kirottuja eikä myrkytettyjä (juomia) kauppaan.
  if(esine.kunto & Item_D_Kirous)esine.kunto ^= Item_D_Kirous;
  printf(".");
  if(esine.mika_esine == Esine_Juoma && (esine.kunto & Item_D_Myrkky))esine.kunto ^= Item_D_Myrkky;
  printf(".");
  ERKKI_copy_in_inventory(varasto, a, &esine);
  printf(")");
}
printf(".");
UnSpaceInventory(varasto);
printf("]");

Meitsi [10.11.2004 18:52:32]

#

En nyt oikein ole varma, mutta johtuisiko se tästä:

signed int a, b = rand()%6;

Ilmeisesti ohjelma kaatuu jollakin tietyllä b:n arvolla.

sqwiik [10.11.2004 19:04:20]

#

Kuten jo sanoin, b on testauksessa sidottu 3:ksi eli sen arvo ei ole vaikuttanut. Kun kaatuminen tapahtuu, silmukkaa ei suoriteta milloinkaan ainuttakaan kertaa oli b mikä hyvänsä vaan silmukan aloittaminen kaataa ohjelman.

FooBat [10.11.2004 19:07:43]

#

Tarkemmin muuttujien alustuksia ja funktioiden toimintaa tuntematta veikkaisin, että RandomEsine kirjoittaa esineeseen jotain virheellistä.

printf() debuggaukseen ei muuten kannata luottaa ellet käytä jokaisen printf metodin jälkeen rivinvaihtoa. Yleensä teksti kirjoitetaan ruudulle vasta rivinvaihdon yhteydessä, vaikka kyseessä olisi useita eri printf-käskyjä.

sqwiik [10.11.2004 19:18:42]

#

FooBat kirjoitti:

printf() debuggaukseen ei muuten kannata luottaa ellet käytä jokaisen printf metodin jälkeen rivinvaihtoa. Yleensä teksti kirjoitetaan ruudulle vasta rivinvaihdon yhteydessä, vaikka kyseessä olisi useita eri printf-käskyjä.

Kenties useimmiten, mutta ainakin minulla niin ei tapahdu (printf:llä kirjoitettu teksti tulee näkyviin oli siinä rivinvaihtoja eli ei). Ja RandomEsine-funktiossa on mahdotonta tapahtua segmenttivirhettä* (ehdoton min-max-tarkkailu indeksien kanssa). Eli silmukka ei pääse koskaan edes alkamaan, vaan tapahtuu jotain muuta häikkää :/

*Testasin randomEsine-funktiota, 2000 kertaa silmukassa, ei segmenttivirhettä.

EDIT - Hail FooBat, virhe olikin RandomEsine-funktiossa. Ilmeisesti ajatuskatkos (varmistin oli tehty puoleenväliin... kommenttinakin oli 'kesken'). Kenteis joskus opin jopa lukemaan omia kommenttejani :P

Meitsi [10.11.2004 19:21:38]

#

Laitappa debuggerin läpi menemään ohjelma ja katso mitä se näyttää muuttujien arvoista kun se ohjelma kaatuu.

FooBat [10.11.2004 23:19:59]

#

sqwiik kirjoitti:

FooBat kirjoitti:

printf() debuggaukseen ei muuten kannata luottaa ellet käytä jokaisen printf metodin jälkeen rivinvaihtoa. Yleensä teksti kirjoitetaan ruudulle vasta rivinvaihdon yhteydessä, vaikka kyseessä olisi useita eri printf-käskyjä.

Kenties useimmiten, mutta ainakin minulla niin ei tapahdu (printf:llä kirjoitettu teksti tulee näkyviin oli siinä rivinvaihtoja eli ei). Ja RandomEsine-funktiossa on mahdotonta tapahtua segmenttivirhettä* (ehdoton min-max-tarkkailu indeksien kanssa). Eli silmukka ei pääse koskaan edes alkamaan, vaan tapahtuu jotain muuta häikkää :/

No esimerkiksi tässäkin tapauksessa oli kyse siitä, että "{" kirjoitettiin stdout puskuriin, mutta sitä ei ehditty flushata ruudulle, joten se ei tullut näkyviin. Rivinvaihto pakottaa flushaamaan stdout puskurin samantien näytölle eikä puskuri jää odottamaan lisää tavaraa tai odottamaan muuten sopivaa hetkeä. Itse aikoinaan ihmettelin miksi yhtään debug tulostusta ei näkynyt ohjelman suorituksen aikana, vaan kaikki tulostui vasta suorituksen loputtua. Syy oli tietenkin se, että missään ei ollut rivinvaihtoa eikä ohjelma nähnyt syytä tulostella tavaraa, kun sillä oli muutakin tekemistä.

Edit: stdin -> stdout ;)

Vastaus

Aihe on jo aika vanha, joten et voi enää vastata siihen.

Tietoa sivustosta