Jump to content
1000DotS

Structuri & fisiere C

Recommended Posts

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 by 1000DotS
Link to comment
Share on other sites

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);
}

Link to comment
Share on other sites

@Gecko

introduc toate chestiile alea, si asteapta sa mai introduc ceva, dupa care imi da eroare

@M2G

Acuma 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 by 1000DotS
Link to comment
Share on other sites

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);
}

Link to comment
Share on other sites

-- Written by 1000DotS

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...

Da, merge si cu fprintf, si cu puts...

Multumesc mult pentru timpul acordat!

Link to comment
Share on other sites

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 sus

struct 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 = 542

La 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->nume

Daca nu ai pointer la structura si vrei sa o folosesti in mod normal, trebuie sa accesezi campurile cu .

Adica: p.nume

Intotdeauna 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!

  • Upvote 2
Link to comment
Share on other sites

@M2G

Poi 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 by 1000DotS
Link to comment
Share on other sites

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 Overflow

Simple: 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. :))

Link to comment
Share on other sites

:)

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 :P

OFF: am avut azi laboratorul cu structuri, si am inteles mult mai bine...

Link to comment
Share on other sites

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 - GIDNetwork

FAQ > Flush the input buffer - Cprogramming.com

Ai 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);

Link to comment
Share on other sites

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:

42061946.png

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 :P

Edited by 1000DotS
Link to comment
Share on other sites

char numeFisierSursa; => inseamna un singur caracter

Tu nu faci verificari pt f si ff, verificand daca fisierul a fost deschis (f != NULL) ori (ff != NULL)

bac

faza cu caracterul...bine zici, nici nu mi-am dat seama :))...da,acuma merge

Verificare:

De obicei fac...data asta mi-am spus sa trec peste asta, ma grabeam

Multumesc!

Edited by 1000DotS
Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.



×
×
  • Create New...