Miksi tää koodi ei tallenna mitään?
void Asiakas::Valikko() //VALIKKO { int valinta=0, ind=0; Asiakas *asiakkaat[5] = {NULL}; fstream tiedosto; int lue=ios_base::in|ios_base::binary; tiedosto.clear();//virhebittien poisto tiedosto.open ("Asiakkaat.dat", lue);//Luetaan tiedosto taulukkoon if (tiedosto.is_open()) { ind = 0; while (tiedosto.peek() != EOF && ind < 5) { asiakkaat[ind] = new Asiakas; asiakkaat[ind] -> Lataa(tiedosto); ind++; } tiedosto.close(); } cout<<"Asiakas tiedostoa ei ole"<<endl; do { cout<<"--ASIAKKAAT--\n\n"; cout<<"1) Lisaa\n"; cout<<"2) Tulosta\n"; cout<<"3) Poista\n"; cout<<"0) Lopeta\n\n"; cout<<"Valinta: "; cin>>ws>>valinta; if (valinta==1) asiakkaat[ind]->Lisaa(); else if (valinta==2) asiakkaat[ind]->Tulosta(); else if (valinta==3) asiakkaat[ind]->Poista(); } while (valinta!=0); fstream tallenna("Asiakkaat.dat", ios_base::out|ios_base::app|ios_base::binary);//Tallennetaan lopetettaessa taulukon käyttö if (tallenna.is_open()) { int ind = 0; while (ind < 5 && asiakkaat[ind] != NULL) { asiakkaat[ind]->Talleta(tallenna); ind++; } tallenna.close(); } cout<<"Tallennus ei onnistunut\n"; for (ind = 0; ind < 5 && asiakkaat[ind] != NULL; ind++) delete asiakkaat[ind]; }
Voisi kuvitella että vika on Talleta()-funktiossa.
void Asiakas::Talleta(fstream &tdsto)const { tdsto.write((char *)nimi_, sizeof nimi_); tdsto.write((char *)&astunnus_, sizeof (int)); }
tässä Talleta funktio
void Lataa(fstream &); void Talleta(fstream &)const;
ja tässä headeri
Oletko muistanut avata fstream-muuttujan tallenna, jota käytät tallentamiseen?
sqwiik,
en oikein ymmärrä mitä tarkoitat tuolla
fstream-muuttujan avaamisella?
ehkä jo alkaa väsy painaan!!!
Eikun hups, kyllähän se tiedosto avataan. Koodista kysyttävää: miten Asiakas-luokan muuttujat nimi_ ja astunnus_ on esitelty?
void Asiakas::Talleta(fstream &tdsto)const{ // Tallennat pointterin lukuarvon, et merkkijonoa. tdsto.write((char *)nimi_, sizeof nimi_); // Castaat (ilmeisesti) int-muuttujan char-pointteriksi? tdsto.write((char *)&astunnus_, sizeof (int)); // Olisiko näin parempi? tdsto.write(nimi_, strlen(nimi_)); tdsto.write(&astunnus_, sizeof (int)); }
char nimi_[31]; int astunnus_;
tässä muuttujien esittely
tdsto.write(&astunnus_, sizeof (int)); //valittaa tästä rivistä ainakin
cannot convert parameter 1 from 'const int *' to 'const char *'
Ah, aivan... sen sijaan että käyttäisit pelkkää fstream.write():ia (jota siis käytetään vain TEKSTIN kirjoittamiseen), kirjoita ensin astunnus_ väliaikaiseen merkkijonoon ja kirjoita se:
char tmp[7]; /* int:n max-arvo vie 5-6 merkkiä. */ sprintf(tmp, "%i", astunnus_); tdsto.write(tmp, strlen(tmp));
Tiedoston lukemisessa pitääkin sitten taas kikkailla...
Vinkkinä: sscanf()
class Asiakas { private: static Asiakas *asiakkaat[3]; int apu; int tunnus; public: int Tunnus(int); }; Asiakas Olio; void Asiakas::Kysy() { apu=100001; tunnus=Olio.Tunnus(apu); } int Asiakas::Tunnus(int apu) { int ind=0; while (ind < 3 && asiakkaat[ind] != NULL) { if (asiakkaat[ind]->tunnus != apu) ind++; else apu++; } ind++; return apu; }
Tarkoitus olisi, että ohjelma generoisi aina uuden asiakastunnuksen alkaen 100001, 100002, 100003... jne.
mutta tällä koodilla tulee aina sama tunnus jokaiselle asiakkaalle (100001)
Koodissani on myös muodostimia ja kopiointimuodostimia sekä
sijoitusoperaattoreita.
Pitäiskö olla jotenkin static määritelty toi tunnus muuttuja? Miksi ei mene tonne else lauseeseen kasvattamaan apu- muuttujaa?
saisko apua mun c++ ongelmaan???
Noh, tallennat nykyisen asiakastunnuksen tekstitiedostoon ja kun tarvitset uuden luet vanhan tunnuksen tiedostosta ja kasvatat sitä yhdellä ja tallennat tiedostoon.
Ei hirveän toimiva "oikeissa" ohjelmissa, jos tiedosto hajoaa tai poistataan...
Asiakas *asiakkaat[3] = {NULL}; char apu3[31]; int ind=0; cout<<"minka nimen haluat muuttaa? "<<endl; cin>>ws; cin.getline(apu3, 30); while(ind < 3 && asiakkaat[ind]->nimi_ != apu3) ind++; if (asiakkaat[ind]->nimi_ == apu3) //etsitty löytyi { cout<<"Nimi: "<<asiakkaat[ind]->nimi_; } else cout<<"Nimea ei loytynyt";
Nyt tarvis saada apua siihen kun pitäis pystyä
muuttamaan dynaamisessa taulukossa olevaa tietoa, esim
asikkaan nimi ym. kaikki perustiedot.
tää koodi menee suoraan tohon että Nimeä ei löytynyt
Merkkijonojen vertaaminen ei onnistu == -vertailulla (se vertaa vain tällöin osoitteita). Käytä strcmp(char*,char*)-funktiota, palauttaa 0 jos merkkijonot ovat samat.
if( strcmp(asiakkaat[ind]->nimi_, apu3) == 0){ cout<<"Nimi: "<<asiakkaat[ind]->nimi_; }else ...
Kiitti, mut kun laitoin sen noin niin ohjelman testauksessa
ohjelma kaatuu aina just tohon kohtaan!!!!
Koodissasi on räikeä virhe. Tuossa kohtaa.
while(ind < 3 && asiakkaat[ind]->nimi_ != apu3) ind++;
Tämän koodirivikaksikon jälkeen ind:n arvo on aina 3. Ja kun sen jälkeen vertaat sitä, tapahtuu muistin ylivuoto (eli viittaat muistialueen ulkopuolelle).
Korjaa: laita kaikki while-silmukkaan kuuluva aaltosulkeisiin.
Moi,
voi olla että on vieläkin räikeitä virheitä koodissani, mutta sitä vartenhan täällä on osaavia henkilöitä antamassa neuvoa meille "tumpeloille" elikkä
toi koodi kaatuu aina tohon kun yritän hakea muutettavaa nimeä!!!
kuinka yleensäkkin tapahtuu muistissa yksittäisen tiedon poisto tiedostosta ja kuinka se sit saadaan korvaamaan vanha tieto. Esim Nimi: Matti Mattila ---> muuta sukuni Pennaseksi --> Matti Pennanen
olen jo kokeilut kikkailua tiedostonkin kaa, mut tarkoitus olis toimia niin, että tiedot ladataan ohjelman käynnistäessä koneen muistiin ja sit sitä muistia vaan "räplätään"!!!
onko mahdollista ja kumpi teidän osaajien mielestä parempi vaihtoehto?
Mitäpä, jos selvittäisit, mihin koodi kaatuu? Hyvä tapa on esimerkiksi Debuggerin käyttö, mahdollisen virheilmoituksen lukeminen ja se, että tarkkailet muuttujien arvoja tulostamalla ne aina silloin tällöin ruudulle. Jos koodisi kuitenkin on suunnilleen tuo, joka löytyy pari viestiä ylempää, voi syynä hyvinkin olla tämä:
Asiakas *asiakkaat[3] = {NULL}
Eli niitä asiakkaita ei ole. Jonkinlaisten perusasioiden tarkkaileminen olisi hyväksi.
Kokeilepa lisätä jokaiseen vertailuun, jossa vertaat kohtaa asiakkaat[ind]->nimi_
johonkin, ensin tarkistus siitä, onko asiakkaat[ind] != NULL
ja asiakkaat[ind]->nimi_ != NULL
, niin et yritä lukea olemattoman asiakkaan olemattomia tietoja.
Tiedosta kiinnostunut!
onko mahdollista käyttää useampaa tietuetta(struct) samassa
ohjelmassa ja kuinka se oikein tapahtuu?
Onko samanlainen rakenne kuin Luokillakin?
Tarkoitus olisi, että olisi vain yksi main() ja 3-4 tietuetta
samassa ohjelmassa.
turpo16 kirjoitti:
onko mahdollista käyttää useampaa tietuetta(struct) samassa ohjelmassa ja kuinka se oikein tapahtuu?
Määrittelet vain useampia structeja.
lainaus:
Onko samanlainen rakenne kuin Luokillakin?
Kyllä, C++:ssa erona on vain se, että classit sisältävät oletuksena private
a tietoa ja structit public
ia.
tuleeko jokaiselle tietueelle oma cpp tiedosto vai tuleeko kaikki samaan main() tiedostoon?
esim.
3 tietuetta Otsikkotiedostoina
1 main()--- valikot siihen
3 cpp tiedostoa
- asiakkaat.cpp------> asiakkaat.dat
- tilaukset.cpp------> tilaukset.dat
- tuotteet.cpp ------> tuotteet.dat
onnistuuko näin?
Siis, simppelit kolme tietuetta:
struct Asdf { int a, s, d, f; }; struct Qwerty { char q, w, e, r, t, y; }; struct FooBarBaz { bool foo, bar, baz; }; int main(int argc, char ** argv) { Asdf asdf; Qwerty qwerty; FooBarBaz foobarbaz; asdf.a = asdf.s = asdf.d = asdf.f = 1234; qwerty.q = qwerty.w = qwerty.e /* jne */ = '\r'; foobarbaz.foo = foobarbaz.bar = foobarbaz.baz = true; return 0; }
Tietueet saa tunkea ihan minne haluaa, kunhan vain määrittelee ne ennen kuin käyttää niitä muuttujamäärittelyissä. Samaan tiedostoon laittaisin, jos noista ei tule kovin isoja (satojen tai tuhansien koodirivien mittaisia).
Aihe on jo aika vanha, joten et voi enää vastata siihen.