Suhteellisen simppeli ongelma varmaan mutta ensimmäistä kertaa tälläiseen törmään. Eli allaolevassa funktiossa parsedText[0]:n arvo("ss2.jpg" tässä tapauksessa) katoaa ja tilalle jää tyhjä rivi. Tämä tapahtuu debuggerissa seuratessani dbPositionObject funktiokutsun tienoilla. Kuten koodissa näkyy ei siinä siis edes käytetä(saati muokata) kyseistä muuttujaa. Seuraava koodiosio näyttää parseLine funktion.
Ja jotta homma menisi viellä mystisemmäksi toisaalla(kolmas koodiosio) tämä toimii hyvin eikä mikään nollaannu keskenkaiken. Mikä ero näissä on ja miten tämän voisi korvata? parseLine funktiossa jotain vikaa joka tekee koodista epästabiilin?
void scenario::createScenario(char *scenarioName) { char **parsedText; //Background parsedText=parseLine(scenarioName, 1,1); dbMakeObjectSphere ( BACKGROUND, -2000 ); dbPositionObject (BACKGROUND,0,0,0 ); dbScaleObject ( BACKGROUND, 100 , 100 , 100 ); dbSetObjectSpecularPower ( BACKGROUND, 255 ); dbSetObjectAmbient ( BACKGROUND, 0 ); dbLoadImage(parsedText[0], 2); dbTextureObject(BACKGROUND,2); //jatkuu eri asioiden tiimoilla
char** parseLine(char *datafile, int lineNumber, int numberOfEntries) { char **returnText; char textLine[256]; char * pch=new char[256]; FILE *theFile; int currentEntry=1, currentLine=0; pch="test"; returnText=new char*[numberOfEntries]; for (int i=0; i<numberOfEntries;i++) { returnText[i]=new char[256]; } theFile=fopen(datafile, "r"); if(theFile==NULL) { sprintf(textLine, "File %s does not exists. Closing now...", datafile); dbExitPrompt(textLine, "Critical error"); } do { fgets(textLine, 256, theFile); currentLine++; } while(currentLine<=lineNumber); dbText ( 0, 20, textLine ); returnText[0]=strtok(textLine, ";"); while (pch != NULL) { pch = strtok (NULL, ";"); returnText[currentEntry]=pch; currentEntry++; } return returnText; }
player::player(int new_id, int new_type) { char **parsedText; id=new_id; type=new_type; speed=0; parsedText=parseLine("ships.dat", type, 7); maxSpeed=atoi(parsedText[0]); turnSpeed=atoi(parsedText[1]); maxHull=atoi(parsedText[2]); maxFrontShields=atoi(parsedText[3]); maxRearShields=atoi(parsedText[4]); maxSystems=atoi(parsedText[5]); }
Kannattaa kyllä nyt katsoa se merkkijonojen käsittely jostakin oppaasta ihan uudestaan. Eli ihan päin mäntyä menee.
Vinkkinä: C-merkkijonoja täytyy joskus kopioida, ja dynaamisesti varattu muisti kuuluu vapauttaa. Osoittimia väliaikaisiin muuttujiin tai taulukoihin (textLine
) ei koskaan palauteta. C++-kielessä merkkijonojen käsittelyyn käytetään string-olioita.
Dodiih. Sehän tepsi. Kiitos!
Jatketaanpa vähän eri ongelman parissa.
FILE *theFile; theFile=fopen(datafile, "r"); if(theFile==NULL) { sprintf(textLine, "File %s does not exists. Closing now...", datafile); dbExitPrompt(textLine, "Critical error"); } for(int i=0;i<lineNumber;i++) { fgets(textLine, 256, theFile); } fclose( theFile);
Eli jälleen ensin toimii ja sitten ei. Ensimmäisen kerran kun mainittuun funktioon tullaan homma toimii. Seuraavan kerran kun tullaan(datafile muuttujalla sama arvo. Vain rivinumero ja rivillä olevien alkioiden määrät vaihtuvat) tiedoston avausyritys johtaa bad pointeriin. Yritys avata sama tiedosto siis epäonnistuu?
(ja kaupanpäälle tuo virheennappaus rutiinikaan ei ole moksiskaan vaan koodi jatkaa menoaan ja kaatuu mukkelis makkelis)
Mikäköhän mahtaa tiedostonkäsittelyssäni olla pielessä?
Oletko ihan varma, että muisinkäsittelysi on kunnossa? Tuossa koodissa ei pitäisi olla mitään vikaa, mutta jos datafile
on vapautettu, sen päälle on kirjoitettu tai se osoittaa muuten vain mihin sattuu, niin ohjelma ei toimi.
Edellisessä esimerkissäsi oli niin paljon muisti- ja pointterivirheitä, että vika on luultavasti edelleen siellä. C-tyylistä muistin- ja merkkijonojenkäsittelyä käyttäessä pitää olla todella huolellinen. Kääntäjä ei huomaa suurinta osaa virheistä ja ohjelma voi jopa "toimia" jonkin aikaa ennen kuin ohjelma kaatuu omiin virheisiinsä tai käyttöjärjestelmä/debuggeri viheltää pelin poikki. Virheitä on joskus todella vaikea jäljittää.
Tämän takia C++:ssa kannattaa käyttää standardikirjaston valmiita säiliöolioita aina kun mahdollista (esimerkiksi tässä tapauksessa). Ne eivät käytännössä vaikuta negatiivisesti ohjelman tehokkuuteen.
Aihe on jo aika vanha, joten et voi enää vastata siihen.