1000DotS Posted April 10, 2013 Report Posted April 10, 2013 (edited) Salutare RST!Am o mare problema...dupa cum spune si titlul, nu pot intelege nicicum structurile astea...Si in liceu am avut probleme cu structurile...si nici pana in ziua de azi nu le-am inteles...Se poate uita cineva peste programul asta, si sa imi explice de ce nu merge?...Am o structura a unui produs (cod, nume, unitate de masura), si vreau sa introduc in fisier aceste valori.Introduc codul, numele, iar dupa ce introduc si unitatea imi da eroare la program...Am pus comentariu la partea de introducere char (nume, unitate) si imi merge...totusi, chiar daca acele secvente sunt comentate, dupa ce introduc codul, nu se termina executia...mai vrea niste caractere introduse...si in fisier imi baga doar codul...Daca aveti nelamuriri spuneti...poate nu m-am exprimat destul de coerent...#include<stdio.h>#include<stdlib.h>void adaugare(){ struct produse{ long cod; char nume[100]; char unitate[20]; }; typedef struct produse PRODUS; PRODUS *p; FILE *f=fopen("produse.txt","wt"); if(f==NULL) { printf("\n Eroare, fisierul nu exista!"); return 0; } printf("\n Introduceti: Cod Produs, Nume, Unitate de masura \n"); scanf("%ld ",&p->cod); fprintf(f,"%ld ",p->cod); fflush(stdin); gets(p->nume); fputc(f,p->nume); fflush(stdin); gets(p->unitate); fputc(f,p->unitate); fclose(f);} Edited April 10, 2013 by 1000DotS Quote
M2G Posted April 10, 2013 Report Posted April 10, 2013 1. Functia ta "adaugare" este de tipul void si tu incerci sa returnezi un int in momentul in care exista o eroare de deschidere a fisierului. Solutie: foloseste exit(1) pentru a iesi din program cu cod de eroare.2. fputc are definitia: int fputc ( int character, FILE * stream );. Tu le-ai pus invers. Fa un cast explicit la int, adica: "(int)pp->nume"3. PRODUS *p; este un pointer neinitializat.Solutie: PRODUS p; // initializezi o structura p.PRODUS *pp = &p; // faci un pointer care sa pointeze la adresa structurii. In continure folosesti pp in loc de p.4. Sa nu mai folosesti fflush(stdin) pentru ca ajungi in undefined behaviour.Codul complet:void adaugare(){ struct produse{ long cod; char nume[100]; char unitate[20]; }; typedef struct produse PRODUS; PRODUS p; PRODUS *pp = &p; FILE *f=fopen("produse.txt","wt"); if(f==NULL) { printf("\n Eroare, fisierul nu exista!"); exit(1); } printf("\n Introduceti: Cod Produs, Nume, Unitate de masura \n"); scanf("%ld ",&pp->cod); fprintf(f,"%ld ",pp->cod); gets(pp->nume); fputc((int)pp->nume, f); gets(pp->unitate); fputc((int)pp->unitate, f); fclose(f);} Quote
1000DotS Posted April 10, 2013 Author Report Posted April 10, 2013 (edited) @Geckointroduc toate chestiile alea, si asteapta sa mai introduc ceva, dupa care imi da eroare@M2GAcuma nu imi mai da eroare...totusi, in fisier imi afiseaza codul, iar pentru nume si unitate imi afiseaza "pÔ"...cred ca inainte de a introduce caracterele, trebuie sa curatam buffer-ul...daca zici ca fflush(stdin) nu e ok..flushall() nu imi merge..nu stiu..trebuie o librarie ceva la el?Edit: in loc de fputc, am folosit fputs si imi merge...multumesc foarte mult Gecko si M2G...sigur o sa mai revin cu ceva probleme, pt ca inca nu am inteles cum lucreaza structurile...Multumesc! Edited April 10, 2013 by 1000DotS Quote
M2G Posted April 10, 2013 Report Posted April 10, 2013 Poate sunt ceva erori din cauza castului la int.Foloseste fprintf pentru a scrie in fisier si merge ok.void adaugare(){ struct produse{ long cod; char nume[100]; char unitate[20]; }; typedef struct produse PRODUS; PRODUS p; PRODUS *pp = &p; FILE *f=fopen("produse.txt","wt"); if(f==NULL) { printf("\n Eroare, fisierul nu exista!"); exit(1); } printf("\n Introduceti: Cod Produs, Nume, Unitate de masura \n"); scanf("%ld ",&pp->cod); fprintf(f,"%ld ",pp->cod); gets(pp->nume); fputc((int)pp->nume, f); gets(pp->unitate); fprintf(f,"%s ",pp->unitate); fclose(f);} Quote
1000DotS Posted April 10, 2013 Author Report Posted April 10, 2013 -- Written by 1000DotSEdit: in loc de fputc, am folosit fputs si imi merge...multumesc foarte mult Gecko si M2G...sigur o sa mai revin cu ceva probleme, pt ca inca nu am inteles cum lucreaza structurile...Da, merge si cu fprintf, si cu puts...Multumesc mult pentru timpul acordat! Quote
1000DotS Posted April 10, 2013 Author Report Posted April 10, 2013 Stai sa vad daca inteleg despre ce vorbesti tu...ca nu prea am idee...Chestia aia, care ia codul linie cu linie si il executa? Ca sa vad eu ce si cum sta treaba in cod? Quote
1000DotS Posted April 10, 2013 Author Report Posted April 10, 2013 Ok, multumesc...Pe multi am vazut ca folosesc debugger-ul, dar nu m-a interesat...o sa ma uit... Quote
M2G Posted April 10, 2013 Report Posted April 10, 2013 Inca cateva chestii:Am uitat, fputc iti scrie doar un caracter. fputs iti scrie un string.Lucrul cu structurile este usor. Poti sa te gandesti la o structura ca si la o clasa de lucruri. Si pe care o definesti ca pe o variabila.Daca luam exemplul tau cu produsul, ai avea un concept produs catre trebuie descris. Pentru a face aste te gandesti la ce proprietati are un produs si ajungi la concluzia ca are un cod de produs, un nume si o unitate de masura(litri, kg etc).In C nu ai tipuri de variabile pentru tot ce exista pe aceasta lume, din cauza asta trebuie sa iti definesti tu tipul.Deci ai o structura care iti defineste produsul. Daca ne gandim la cele 3 proprietati identificate pe rand avem asa: codul de produs este un numar, deci o sa ai un int. Dupa asta te gandesti ca acel cod poate sa fie foarte mare asa ca poti sa faci acest atribut long. numele produsului este un text, deci ai facut un array de 100 caractere care formeaza numele prodului unitatea de masura poate sa fie orice de la kg, litru, metrii etc asa ca pentru simplitate si pentru a nu defini fiecare tip, poti sa faci si acest atribut ca si string.Deci ti-ai definit o variabila de tip produs cu caracteristicle descoperite mai susstruct produse{ long cod; char nume[100]; char unitate[20]; };Dupa asta ai zis ca vrei sa folosesti ace structura ca pe orice alta variabila(primitiva). Cum este int, char etc...typedef struct produse PRODUS;Dupa asta ai initializat variabila:PRODUS p;Pentru ca multe functii iti cer un pointer la tipul de date, ai creat un pointer catre variabila PRODUS si ai zis ca sa pointeze catre adresa lui PRODUS p astfel ca accesezi variabila p prin intermediul pointerului care reprezinta adresa la care se gaseste p in memorie.PRODUS *pp = &p // pointer la tipul PRODUS este egal cu adresa variabilei p;Dupa asta ai accesat campurile structurii, asta o faci ca si lucrul cu orice alta variabila:Exemplu:pp->cod = 542; este acelasi lucru ca si cum ai asigna o valoare unui long. long cod = 542La fel si cu celelalte variabile de tip char.Atentie!Daca ai un pointer cum este pp trebuie sa accesezi campurile structurii PRODUS prin ->Adica: pp->numeDaca nu ai pointer la structura si vrei sa o folosesti in mod normal, trebuie sa accesezi campurile cu .Adica: p.numeIntotdeauna folosesti -> pentru pointeri si . pentru variabile care nu sunt pointeri.De ce sunt utile structurile?Structurile sunt utile pentru ca daca ai de exemplu o functie care ia ca si argumente un Angajat si sa zicem un departament pe care este angajat, este mult mai simplu de folosit decat in cazul in care ar trebui sa pui variabila pentru fiecare atribut ale acestor doua concepte.Exemplu:struct Angajat{ long cod; char[100] nume; char[100] adresa; float salar;};struct Departament{ long cod; char[100] nume; char[100] sef; char[100] locatie;};//ai functia:void arataDetaliiAngajat(Angajat a, Departament d);Sau daca nu ai folosi structuri si ai vrea sa faci aceasi functie, ar arata ceva de genul:void arataDetaliiAngajat(long cod_angajat, char *nume_angajat, char *adresa_angajat, float salar_angajat, long cod_departament, char *nume_departament, char *sef_departament, char *locatie_departament) Care dintre cele doua exemple de functii ti se pare mai usor de folosit?Ce s-ar intampla daca Angajat si Departament ar avea si alte atribute mai complexe? Cum ar arata atunci functia daca nu ai folosi structuri ci doar variabile primitive cum sunt int, long, char etc... ?Daca nu ai inteles si mai ai intrebari posteaza si incercam sa te ajutam.Bafta! 2 Quote
1000DotS Posted April 10, 2013 Author Report Posted April 10, 2013 (edited) @M2GPoi daca nu inteleg nici din tutorialul asta, chiar sunt prost Da, foarte bine explicate, deja m-am luminat putin...Daca as putea sa te rasplatesc, as face-o fara ezitare...dar nu stiu cum (poate imi dai o idee)Multumesc mult de tot!+rep pentru efortul depus Later edit:Totusi, revin cu o intrebare....de ce nu este recomandat sa folosesc fflush(stdin)?...Si profu meu foloseste asta...si cand introduc caractere, din cate stiu este recomandat sa curat buffer-ul inainte de introducere.... Edited April 11, 2013 by 1000DotS Quote
M2G Posted April 11, 2013 Report Posted April 11, 2013 Asa spun alti baieti pe forumuri. Depinde de compilator, in cel de la microsoft cica merge, in altele e posibil sa nu mearga pentru ca nu este un standard ansi C. Deci comportamentul sau e undefined.Uite niste referinte: fflush(stdin)c++ - Using fflush(stdin) - Stack OverflowSimple: this is undefined behavior, since fflush is meant to be called on an output stream. This is an excerpt from the C standard: int fflush(FILE *ostream); ostream points to an output stream or an update stream in which the most recent operation was not input, the fflush function causes any unwritten data for that stream to be delivered to the host environment to be written to the file; otherwise, the behavior is undefined.So it's not a question of "how bad" this is. fflush(stdin) is plainly wrong, and you mustn't use it, ever.According to the standard, fflush can only be used with output buffers, and obviously stdin isn't one. However, some compilers provide the use of fflush(stdin) as an extension. In that case you can use it, but it will affect portability, so you will no longer be able to use any standards-compliant compiler on earth and expect the same results.Poate ar trebui sa ii arati astea profesorului tau sau sa-i dai adresa forumului sa isi faca cont. Quote
1000DotS Posted April 11, 2013 Author Report Posted April 11, 2013 Chiar nu stiu ce sa spun...de ce spun asta...La o problema, aveam de introdus niste siruri de caractere in fisier...Imi mergea, dar imi mai introducea ceva caractere in plus...nu era locul lor acolo...Inainte de gets am pus fflush(stdin), si problema a disparut!In fine, problema asta e mult prea mica OFF: am avut azi laboratorul cu structuri, si am inteles mult mai bine... Quote
M2G Posted April 11, 2013 Report Posted April 11, 2013 Probabil ca iti suporta compilatorul si de asta merge dar nu este un standard pentru asta.Cei care fac compilatoarele trebuie sa urmeze anumite standarde, daca asta nu este specificat in standardul C++ nu poti zice ca e ceva valid doar pentru ca merge pe compilatorul x cand pe altele k poate sa nu mearga.Oricum, nici scanf nu prea ar mai trebui sa fie folosit.Mai multe aici: Things to Avoid in C/C++ -- fflush(stdin), Part 2 - GIDNetworkFAQ > Flush the input buffer - Cprogramming.comAi aici un macro care face flush la input stream. how to properly flush the input stream (stdin) | DaniWeb#define FLUSH_STDIN(x) {if(x[strlen(x)-1]!='\n'){do fgets(Junk,16,stdin);while(Junk[strlen(Junk)-1]!='\n');}else x[strlen(x)-1]='\0';}apelezi cu:FLUSH_STDIN(Variabila_pe_care_o_vrei_curatata);Am mai vazut ca unii mai folosesc si:fseek(stdin,0,SEEK_END); Quote
1000DotS Posted April 13, 2013 Author Report Posted April 13, 2013 (edited) Din nou revin, cu o alta problema:Backup la fisier...void backup(PRODUS s){ FILE* f=fopen("test","rb"); FILE* ff=fopen("backup","ab"); while(fread(&s,sizeof(PRODUS),1,f)>0) fwrite(&s,sizeof(PRODUS),1,ff); printf("\n Backup realizat cu succes!"); fclose(ff);}Aici, backup-ul se realizeaza corect si bine...dar vreau sa am o versiune mai avansata, unde sa cer numele fisierului sursa, si numele fisierului in care sa puna backup.char numeFisierSursa;char numeFisierBackup; printf("\n Dati numele fisierului sursa: "); scanf("%s",&numeFisierSursa); FILE* f=fopen(numeFisierSursa,"rb"); printf("\n Dati numele fisierului in care faceti backup: "); scanf("%s",&numeFisierBackup); FILE* ff=fopen(numeFisierBackup,"ab"); while(fread(&s,sizeof(PRODUS),1,f)>0) fwrite(&s,sizeof(PRODUS),1,ff); printf("\n Backup realizat cu succes!"); fclose(ff);Dupa ce introduc numele fisierului sursa, primesc eroarea asta:Incerc sa inteleg unde e greseala, dar ma depaseste...Off: Nu ma inteleg nicicum cu C-ul...nu le am chiar asa de bine...daca e greseala de noob, sa nu radeti de mine Edited April 13, 2013 by 1000DotS Quote
noVaLue Posted April 13, 2013 Report Posted April 13, 2013 char numeFisierSursa; => inseamna un singur caracterTu nu faci verificari pt f si ff, verificand daca fisierul a fost deschis (f != NULL) ori (ff != NULL) bac Quote
1000DotS Posted April 13, 2013 Author Report Posted April 13, 2013 (edited) char numeFisierSursa; => inseamna un singur caracterTu nu faci verificari pt f si ff, verificand daca fisierul a fost deschis (f != NULL) ori (ff != NULL) bacfaza cu caracterul...bine zici, nici nu mi-am dat seama ...da,acuma mergeVerificare:De obicei fac...data asta mi-am spus sa trec peste asta, ma grabeamMultumesc! Edited April 13, 2013 by 1000DotS Quote