Am o intrebare legata de structures in c++.
Am atasat 2 imagini in care este un program simplu (in coltul dreapta-sus este ce afiseaza programul).
Jucandu-ma putin cu structurile de date in c++ am observat in programul asta ca, daca declar 'book1, book2, book3' imediat dupa 'struct book', programul merge bine.
Dar daca declar 'book1, book2, book3' in functia main() ex: Book book1, book2, book3;
In rezultatul final apar niste caractere in plus, dar nu la toate book-urile.
Poate sa imi spuna cineva de ce se intampla chestia asta?
La fel se intampla daca folosesc 'typedef struct'.
Răspunsuri la întrebare
Nu bag mana in foc ca asta e explicatia, ar putea sa depinda de compilator, sau sa fiu total pe langa cu ea, dar ma dau cu parerea. Cand declari variabile globale (poza 1), variabilele sunt alocate static in segmentul de date in memorie (zona de memorie se numeste Text/Global, alaturi de Heap si Stack). Desi nu sunt sigur de asta, si NU cred ca e asa, dar e posibil sa fie cazul aici, memoria din Global este goala, plina cu zerouri, asadar stringurile tale initial vor fi goale. Cand copiezi stringul tau in autor si in ce mai copiezi tu, la final oricum va fi pun un null terminator ('\0') care indica finalul stringului si asta va face la afisare sa stie cand sa se opreasca cu afisarea din memorie. Ca regula generala, nu e frumos sa declari variabile globale decat daca e strict nevoie. Functia ta de copiere a stringului nu cred ca e bine facuta, eu cand copiam stringuri in C copiam strlen() caractere, nu sizeof, dar nici eu nu sunt zeu in programare.
Cand declari o variabila locala (poza a doua), se aloca memoria in Stack, care nu este golita inainte de rulare. Ce se gaseste acolo, dumnezeu cu mila. Stringurile tale vor fi copiate, dar nu cred ca pui bine acel null terminator pe pozitia aia, ti-am zis, eu l-as pune pe strlen-1. La afisare o sa afisezi pana cand gasesti un null terminator, care era inainte in memorie. Pana la acel null terminator, pot fi o groaza de biti veniti din alte parti pe care calculatorul la runtime ii interpreteaza fortat ca si caractere si incearca sa ii afiseze. Sfatul meu este sa folosesti strlen. Si chiar sa inveti sa folosesti strcpy. Si memcpy. Si invata sa folosesti pointeri.
Problema este in ce sectiune se gasesc variabilele in memorie.
Aici sunt doua posibilitati: sunt variabile declarate intr-o functie(locale) si se gasesc in stack sau sunt variabile globale si se gasesc in sectiunea ".data".
In cazul in care sunt variabile globale, toti bytii din alcatuirea interna sunt initializati cu 0 (deci daca copiezi ceva aici, restul caracterelor vor fi egale cu zero), si cand vei apela operatorul << din cout cu acestea, se va opri la primul caracter nul.
Pe de alta parte, daca sunt declarate in stack, nu au valori exacte, ci doar valori reziduale din memorie care se intamplau sa fie aici, astfel vezi niste caractere(sau semne de intrebare daca nu sunt afisabile), pana cand ajunge la un caracter 0(la fel, rezidual) sau pana incearca sa acceseze o adresa nepermisa, care duce la SIGSEGV.
Problema apare de la faptul ca functia copyString nu primeste marimea corecta a sirului pe care il copiaza, ci marimea alocata sirului in care se copiaza(32 pentru autor si 64 pentru titlu), astfel conditia i < n-1 va fi mereu adevarata(si nu va pune caracterul nul unde trebuie).
Problema asta se rezolva doar prin linia:
n = s.length();
inainte de for.
Acum caracterul nul va ajunge in locul in care trebuie si nu vor mai fi afisate caracterele reziduale din memoria alocata.
Eu recomand sa folosesti
n = min(s.length(), n);
pentru a nu corupe din greseala memoria daca sirul s este mai lung decat ce a fost alocat.