Differences

This shows you the differences between two versions of the page.

Link to this comparison view

programare:laboratoare:lab11 [2017/01/06 02:17]
darius.neatu [Noţiuni teoretice]
programare:laboratoare:lab11 [2022/12/12 17:12] (current)
robert.stoica2205 [Noţiuni teoretice]
Line 1: Line 1:
-===== Operatii cu fişiere. Aplicaţii folosind fişiere. ​=====+===== Structuri. Uniuni. Aplicaţie: Matrice rare =====
  
-**Responsabil:**  +**Resposabili:​****Responsabili:** 
-  * [[neatudarius@gmail.com|Darius Neațu (2016)]] +  * [[ion_dorinel.filip@cti.pub.ro|Dorinel Filip (CA 2016-2020)]] 
-  * [[mihaela.vasile@gmail.com|Mihaela Vasile ​(2015)]]+  * [[neatudarius@gmail.com|Darius Neațu (CA 2019-2020)]] 
 +  * [[mihaela.vasile@gmail.com|Mihaela Vasile]]
  
-**Ultima modificare:​** **11.12.2016** 
 ==== Obiective ==== ==== Obiective ====
  
 În urma parcurgerii acestui laborator studentul va fi capabil să: În urma parcurgerii acestui laborator studentul va fi capabil să:
-  * lucreze cu fişiere text (deschidere,​ închidere, citire, scriere) +  * organizeze datele din rezolvarea unei probleme complexe în structuri ​şi uniuni
-  * înteleaga un fişier binar şi să lucreze cu el+  * optimizeze scrierea funcţiilor prin minimizarea numărului de parametri şi prin utilizarea structurilor ca parametri returnaţi de funcţie
-  * să se poziţioneze in interiorul unui fişier+  * distingă diferenţa dintre o structură ​şi o uniune
-  * poată determina poziţia în cadrul unui fişier+  * evite utilizarea greşită a structurilor.
-  * înteleagă diferenţîntre organizarea internă a fişierelor pe sistemele de operare Linux şi Windows.+
  
 ==== Noţiuni teoretice ==== ==== Noţiuni teoretice ====
  
-=== Introducere ​===+=== Structuri ​=== 
 +Structurile sunt tipuri de date în care putem grupa mai multe variabile eventual de tipuri diferite (spre deosebire de vectori, care conţin numai date de acelasi tip). O structură se poate defini astfel:
  
-Un fişier este o structură dinamică, situată în memoria secundară (pe disk-uri). Limbajul C permite operarea cu fişiere: ​ 
-  * de **tip text** - un astfel de fişier conţine o succesiune de **linii**, separate prin new line ('​\n'​) ​ 
-  * de **tip binar** - un astfel de fişier conţine o succesiune de octeti, **fără nici o structură**. 
- 
-Prelucrarea unui fişier presupune asocierea acestuia cu un canal de I/E (numit flux sau stream). Există trei canale predefinite,​ care se deschid automat la lansarea unui program: ​ 
-  * **stdin** - fişier de intrare, text, este intrarea standard - tastatura ​ 
-  * **stdout** - fişier de iesire, text, este ieşirea standard - ecranul monitorului. 
-  * **stderr** – fişier de iesire, text, este ieşirea standard unde sunt scris mesajele de eroare - ecran. 
- 
-Pentru a prelucra un fişier, trebuie parcurse următoarele etape: ​ 
-  * **se defineşte** o variabilă de tip **FILE*** pentru accesarea fişierului;​ **FILE** este un tip structură definit în <​stdio.h>,​ care conţine informaţii referitoare la fişier şi la tamponul de transfer de date între memoria centrală şi fişier (adresa, lungimea tamponului, modul de utilizare a fişierului,​ indicator de sfârsit, de poziţie în fişier). Puteți citi mai multe [[http://​stackoverflow.com/​questions/​5672746/​what-exactly-is-the-file-keyword-in-c | aici ]]. 
-  * **se deschide fişieru**l pentru un anumit **mod de acces**, folosind funcţia de bibliotecă **fopen**, care realizează şi asocierea între variabila fişier şi numele extern al fişierului ​ 
-  * **se prelucrează fişierul** în citire/​scriere cu **funcţiile specifice** ​ 
-  * **se închide fişierul** folosind funcţia de bibliotecă **fclose** ​ 
- 
-=== Funcții === 
-Mai jos se prezintă restul funcţiilor de prelucrare a fişierelor. Pentru documentația oficială puteți citi [[http://​www.cplusplus.com/​reference/​cstdio/​ | aici]]. 
- 
-== fopen == 
 <code c> <code c>
-FILE *fopen(const char *filename, const char *mod);+struct nume_structura { 
 +  declaratii_de_variabile 
 +};
 </​code>​ </​code>​
  
-deschide ​fişierul cu numele **filename** pentru acces de tip **mod**. ​+Definiția unei structuri poate fi urmată imediat ​de declararea de variabile de acel tip, forma cea mai generală fiind: 
 +<code c> 
 +struct [structure tag] {
  
-Returnează **pointer la fişier** sau **NULL** dacă fişierul nu poate fi deschisvaloarea returnată este memorată în variabila fişier, care a fost declarată pentru accesarea lui.  +   ​member definition
- +   member definition; 
-Modul de deschidere poate fi: +   ... 
-  * "​**r**"​ - **readonly** , este permisă doar citirea dintr-un fişier existent +   member definition; 
-  * "​**w**"​ - **write**, crează un nou fişier, sau dacă există deja, distruge vechiul continut ​ +} [one or more structure variables]; ​ 
-  * "​**a**"​ - **append**, deschide pentru scriere un fişier existent ( scrierea se va face în continuarea  +</​code>​
- informaţiei deja existente în fişier, deci pointerul ​ de acces se plasează la sfârşitul fişierului )  +
-  * "​**+**"​ - permite scrierea şi citirea - **actualizare** (ex: "​r+",​ "​w+",​ "​a+"​). O citire nu poate fi direct urmată  +
- de o scriere şi reciproc. Întâi trebuie repoziţionat cursorul de acces printr-un apel la **fseek**. ​+
  
-  * "​**b**"​ - specifică fişier de tip **binar**  +Unde între ​''​[]''​ se află câmpurile opționale.
-  * "​**t**"​ - specifică fişier de tip **text** (implicit), la care se face automat conversia CR-LF("​\n\f"​) în sau din CR ('\n')+
  
-== fclose ==+Exemple:
 <code c> <code c>
-int fclose(FILE *pFile);+struct student { 
 +  char nume[40]; 
 +  ​int an; 
 +  float medie; 
 +};
 </​code>​ </​code>​
  
-**închide fişierul** asociat cu variabila **pFile** şi eliberează zona tampon; returnează 0 la succes, EOF (end of file) la eroare ​+Variabilele declarate in interiorul structurii se numesc "​campurile"​ structurii:​ 
 +  ​*nume; 
 +  ​*an; 
 +  ​*medie.
  
-== fseek == 
 <code c> <code c>
-int fseek(FILE ​*pFile, long offset, int whence);+struct complex { /pentru memorarea unui număr complex cu dublă precizie */ 
 +  double re; 
 +  double im; 
 +};
 </​code>​ </​code>​
  
-**repoziţionează pointerul** asociat fişierului **pFile**; offset - numărul de octeţîntre poziţia dată de whence şi noua poziţie.  +Declararea ​şi iniţializarea unor variabile ​de tip structură se poate face astfel:
- +
-whence - are una din cele trei valori posibile:  +
-  * SEEK_SET ​ = 0 - Căutarea ​se face de la începutul fişierului  +
-  * SEEK_CUR = 1 - Căutare din poziţia curentă  +
-  * SEEK_END = 2 - Căutare de la sfârşitul fişierului  +
- +
-== ftell ==+
 <code c> <code c>
-long ftell(FILE *pFile);+struct student s1 = {"​Popescu Ionel",​ 3, 9.25}; 
 +struct complex c1, c2; 
 +struct complex v[10];
 </​code>​ </​code>​
  
-**întoarce poziţia curentă** în cadrul fișierului asociat cu pFile. +Pentru simplificarea declaraţiilor, putem asocia unei structuri un nume de tip de date:
- +
-== fgetpos ==+
 <code c> <code c>
-int fgetpos(FILE *pFilefpos_t *ptr);+typedef struct student Student; 
 +... 
 +Student s1s2, s3;
 </​code>​ </​code>​
  
-această funcţie **memorează poziţia curentă** ​în variabila ptr în cadrul fişierului asociat cu pFile (ptr va putea fi folosit ulterior cu funcţia fsetpos).+Redenumirea de tip de mai sus poate fi inclusă și în definirea structurii, caz în care putem folosi - din prima - atât ''​struct Student''​ cât și tipul de date rezultat din typedef:
  
-== fsetpos == 
 <code c> <code c>
-int fsetpos(FILE *pFile, const fpos_t *ptr)+typedef struct student { 
-</​code>​ +  char nume[40]; 
-această funcţie **setează poziţia curentă** în fişierul asociat cu pFile la valoarea ptr, obţinută anterior prin funcţia fgetpos.+  ​int an
 +  float medie; 
 +} Student;
  
-== feof == +int main() 
-<code c> +   /* Ambele declaratii de mai jos sunt valide */ 
-int feof(FILE *fis);+   ​struct student s1; 
 +   ​Student s2; 
 +}
 </​code>​ </​code>​
-returnează 0 dacă nu s-a detectat **sfârşit de fişier** la ultima operaţie de citire, respectiv o valoare nenulă (adevărată) pentru sfârşit de fişier. ​ 
  
-== freopen ==+ 
 +Accesul la membrii unei structuri se face prin operatorul "​.":​
 <code c> <code c>
-FILE* freopen(const char *filename, const char *mode, FILE *fp);+s1.an = 3;
 </​code>​ </​code>​
-se închide fişierul fp, se deschide fişierul cu numele filename în modul mode şi acesta se asociază la fp; se întoarce fp sau NULL în caz de eroare. 
  
-== fflush ==+În cazul pointerilor la structuri, accesul la membri se poate face astfel:
 <code c> <code c>
-int fflush(FILE *fp);+Student *stud = (Student ​*)malloc(sizeof(Student));​ 
 +(*stud).medie = 9.31; 
 +/* altă modalitate mai simplă şi mai des folosită: */ 
 +stud->​medie = 9.31;
 </​code>​ </​code>​
-Această funcţie se utilizează pentru fişierele deschise pentru scriere şi are ca efect scrierea în fişier a datelor din bufferul asociat acestuia, care înca nu au fost puse în fişier. 
- 
-=== Citirea şi scrierea în/din fişiere === 
- 
-Citirea/​scrierea în fişiere se poate face în două moduri (în funcție de tipul fişierului):​ în mod text sau în mod binar. Principalele diferenţe dintre cele două moduri sunt: 
-  * în modul text, la sfarsitul fişierului se pune un caracter suplimentar,​ care indică sfârşitul de fişier. În DOS şi Windows se utilizează caracterul cu codul ASCII 26 (Ctrl-Z), iar în Unix se utilizează caracterul cu codul ASCII 4. Dacă citim un fişier în mod text, citirea se va opri la intâlnirea acestui caracter, chiar dacă mai există şi alte caractere după el. În modul binar nu există caracter de sfârşit de fişier (mai precis, caracterul cu codul 26, respectiv 4, este tratat la fel ca şi celelalte caractere). 
-  * în DOS şi Windows, în modul text, sfârşitul de linie este reprezentat prin două caractere, CR (Carriage Return, cod ASCII 13) şi LF (Line Feed, cod ASCII 10). Atunci când în modul text scriem un caracter '​\n'​ (LF) în fişier, acesta va fi convertit într-o secventă de 2 caractere CR şi LF. Când citim în mod text dintr-un fişier, secvenţa CR, LF este convertită într-un '​\n'​ (LF). În Unix, sfârşitul de linie este reprezentat doar prin caracterul LF. În mod binar, atât în DOS-Windows cât şi în Unix, sfârşitul de linie este reprezentat doar prin caracterul LF. 
- 
-Modul binar se utilizează de obicei pentru a scrie în fişier datele exact aşa cum sunt reprezentate în memorie (cu functiile **fread**, **fwrite**) - de exemplu pentru un număr intreg se va scrie reprezentarea internă a acestuia, pe 2 sau pe 4 octeti. 
- 
-Modul text este utilizat mai ales pentru scrierea cu format (cu funcţiile fprintf, fscanf) - în cazul acesta pentru un număr întreg se vor scrie caracterele ASCII utilizate pentru a reprezenta cifrele acestuia (adică un şir de caractere cum ar fi "​1"​ sau "​542"​). ​ 
- 
-=== Citire/​scriere cu format === 
  
 +Atribuirile de structuri se pot face astfel:
 <code c> <code c>
-int fprintf(FILE *fpconst char *format, ...)+struct complex n1n2
-int fscanf(FILE *fp, const char *format, ​...);+... 
 +n2 = n1;
 </​code>​ </​code>​
  
-Funcţiile sunt utilizate pentru citire/​scriere în mod text şi sunt asemănătoare cu printf/​scanf (diferenţfiind că trebuie dat pointerul la fişier ca prim parametru). +Prin această atribuire se realizează o copiere bit cu bit elementelor lui n1 în n2.
- +
-== Exemplu 1 ==  +
-Să presupunem că avem următorul fișier care pe prima linie conține un număr natural nenul n, iar pe a doua linie se află n numere întregi reprezentând elementele unui vector. Se cere citirea vectorului, dublarea fiecarui element, apoi salvarea rezultatelor ​în fișierul "​gigel.out"​.+
  
 +Alt exemplu de utilizare: După cum se vede mai jos trebuie facută diferenta când definim un tip şi cand declaram o variabila de tip struct sau typedef struct.
 <code c> <code c>
-gigel.in +typedef struct { 
-5 +  int data; 
-1 3 -1 6 7 +  int text; 
-</code>+} S1; // este un typedef pentru S1, functional in C si C++
  
-Rulați și înțelegeți următorul cod C. +struct S2 { 
-<code c> +  int data; 
-#include <​stdio.h>​ +  int text; 
-#define NMAX 100+}; // este un typedef pentru struct S2
  
-int main() { 
-    // numele fisierului de intrare 
-    char input_filename[] = "​gigel.in";​ 
  
-    ​// deschidere fisier ​de intrare pentru +struct { 
-    // citire (r) in modul text (t) +  int data; 
-    FILE *in = fopen(input_filename,​ "​rt"​);​+  int text; 
 +} S3; 
 +// este o declaratie a lui S3, variabila ​de tip struct nu defineste un tip 
 +// spune compilatorului sa aloce memorie pentru variablia S3
  
-    // verific daca fisierul a fost deschis cu succes +typedef struct S4 
-    // altfel opresc executia (in cazul acestei probleme) +  int data
-    if (in == NULL) +  int text
-        ​fprintf(stderr,​ "​ERROR:​ Can't open file %s", input_filename)+S4; // este un typedef atât pentru struct S4, cât și pentru S4
-        ​return -1+
-    }+
  
-    int n, v[NMAX], i; // numarul de elemente && vectorul 
  
-    ​// citesc n din fisier +int main() { 
-    fscanf(in"​%d"​&n)+  ​// ce se intampla la declarare variabile de tip S1,S2,S3 
-    //citesc tabloul +  S1 mine1// este un typedef si va merge 
-    for (i = 0i < n; ++i) { +  ​struct S2 mine2; ​// este un typedef si va merge 
-        ​fscanf(in,​ "​%d",​ &v[i]); +  S2 mine22// S2 NU este un typedef si NU va merge 
-    } +  S3 mine3; // nu va merge pt ca S3 nu este un typedef. 
- +  ​struct S4 mine4; ​// este un typedef și va merge 
-    ​// deoarece stiu sigur ca nu mai am nimic de citit +  S4 mine4; // este un typedef șva merge 
-    // pot inchide fisierul de intrare +   
-    ​fclose(in); +  // ce se intampla la utilizarea ca variabile ​S1,S2,S3 
- +  S1.data 5; // da eroare deoarece S1 este numai un typedef. 
-    ​// dublez elementele din vector +  ​struct S2.data ​5; // da eroare deoarece S2 este numai un typedef. 
-    for (= 0; i < n; ++i) { +  ​S3.data ​5; // merge doarece S3 e o variabila 
-        v[i] <<= 1; +  return 0;
-    } +
- +
-    // deschid fisierul pentru ​scrie rezultatele +
-    char output_filename[] = "gigel.out";​ +
-    // deschid pentru scriere (w) in modul text (t) +
-    FILE *out fopen(output_filename,​ "​wt"​); +
- +
-    ​// verific daca fisierul a fost deschis cu succes +
-    // altfel opresc executia (in cazul acestei probleme) +
-    if (out == NULL) { +
-        fprintf(stderr,​ "​ERROR:​ Can't open file %s", output_filename); +
-        return -1; +
-    } +
- +
-    ​// scriu n si vectorul in fisier +
-    ​fprintf(out,​ "​%d\n",​ n); +
-    for (i 0i < n; ++i) { +
-        fprintf(out,​ "%d ", v[i]); +
-    } +
-    fprintf(out,​ "​\n"​);​ +
- +
-    ​// inchid fisierul de iesire +
-    fclose(out);​ +
- +
-    return 0;+
 } }
 </​code>​ </​code>​
  
-Pentru exemplul ​de fișier de intrare ​de mai susrezultatul este următorul. +<​note>​Dacă declaraţi pointeri la structuri, nu uitaţi să alocaţi memorie pentru aceştia înainte ​de a accesa câmpurile structurii. Nu uitaţi să alocaţi şi câmpurile structurii, care sunt pointeri, înainte ​de utilizaredacă este cazulDe asemenea fiţi atenţi şi la modul de accesare al câmpurilor
-<code c> +</note>
-gigel.out +
-+
-2 6 -2 12 14  +
-</code>+
  
-== Exemplu 2 =+=== Diferenţa dintre copierea structurilor şcopierea pointerilor ===
-Fie un fișier text cu un nume dat. Scriețo funcție care calculează numărul de bytes (dimensiune fișierului).+
  
 +Pentru exemplificarea diferenţei dintre copierea structurilor şi copierea pointerilor să considerăm urmatorul exemplu:
 <code c> <code c>
-#include <​stdio.h>​ +struct exemplu ​
- +  int n
-int sizeof_file(char *filename) ​+  char *s;
-    // deschidere fisier de intrare pentru +
-    // citire (r) in modul text (t) +
-    FILE *file = fopen(filename,​ "​rt"​);​ +
- +
-    // verific daca fisierul a fost deschis cu succes +
-    // altfel opresc executia +
-    if (file == NULL) { +
-        return -1; // nu am putut calcula dimensiunea +
-    } +
- +
-    // ma pozitionez la sfarsit +
-    fseek(file, 0, SEEK_END);​ +
-    // acum cursorul este dupa ultimul caracter +
-    // deci ftell imi va spune pozitia, care este echivalenta cu numarul de bytes +
-    ​int bytes_count = ftell(file)+
- +
-    // inchid fisierul +
-    fclose(file);​ +
- +
-    return bytes_count;+
 } }
 +struct exemplu s1, s2;
 +char *litere = "​abcdef";​
 +s1.n = 5;
 +s1.s = strdup(litere);​
 +s2 = s1;
 +s2.s[1]='​x';​
 +</​code>​
  
-int main() +După atribuirea s2 = s1;, s2.s va avea o valoare identică cu s1.s. Deoarece s este un pointer ​(o adresă de memorie), s2.s va indica aceeaşi adresa ​de memorie ca şi s1.s. Deci, după modificarea celui de-al doilea caracter din s2.s, atat s2.s cât si s1.s vor fi axcdef. De obicei acest efect nu este dorit şi nu se recomandă atribuirea de structuri atunci cand acestea contin pointeri.
-    // numele fisierului ​de intrare +
-    char filename[] = "gigel.in";+
  
-    int sz = sizeof_file(filename)+Totuşi, putem atribui ulterior lui s2.s o altă valoare ​(o altă adresă), iar ca urmare a acestei operaţiistringurile vor fi distincte din nou.
-    if (sz < 0) { +
-        // afisez la stderr +
-        fprintf(stderr"​ERROR:​ Can't open file %s"filename);​ +
-        return -1; +
-    }+
  
-    // afisez la stdout rezultatul +Un alt caz (diferit de cel expus anterioreste cel al atribuirii aceleiaşi structuri către două variabile pointer diferite: 
-    printf("​fisierul %s are %d bytes\n",​ filename, sz); +<code c> 
- +struct exemplu { 
-    // pot folosi tot fprintf pentru a afisa la stdout +  ​int ​n; 
-    ​fprintf(stdout,​ "​fisierul %s are %d bytes\n", filename, sz)+  char * s;
- +
-    return 0;+
 } }
 +struct exemplu s1; 
 +struct exemplu *p1; 
 +struct exemplu *p2; 
 +p1 = &s1; 
 +p2 = &s1;
 </​code>​ </​code>​
  
-=== Citire/​scriere fără conversie ===+În acest caz observăm că din nou p1->s şi p2->s indică către acelaşi şir de caractere, dar aici adresa către şirul de caractere apare memorată o singura dată; spre deosebire de cazul anterior, dacă modificăm adresa din p2->s, ea se va modifica automat şi în p1->s.
  
 +=== Uniuni ===
 +Uniunile sunt asemănătoare structurilor,​ dar lor li se rezervă o zonă de memorie ce poate conţine, la momente de timp diferite, variabile de tipuri diferite. Sunt utilizate pentru a economisi memoria (se refoloseşte aceeaşi zonă de memorie pentru a stoca mai multe variabile).
 +
 +Uniunile se pot declara astfel:
 <code c> <code c>
-size_t fread(void *ptr, size_t size, size_t nrec, FILE *fp)+union numere { 
-size_t fwrite(const void *ptr, size_t size, size_t nrec, FILE *fp);+  int i
 +  float f; 
 +  double v; 
 +};              /se poate utiliza si typedef... ​*
 + 
 +union numere u1, u2;
 </​code>​ </​code>​
  
-Cu aceste funcţii lucrăm cand deschidem fişierul în mod binar; citirea/​scrierea se face fără nici un fel de conversie sau interpretareSe lucrează cu "​înregistrări"​adică zone compacte ​de memorie: funcţia fread citeşte nrec înregistrări începănd de la poziţia curentă din fişierul fpo înregistrare având dimensiunea sizeAcestea sunt depuse în tabloul ptr"​Înregistrările" pot fi asociate cu structurile din C - adică în mod uzual, tabloul ptr este un tablou de structuri (dar în loc de structuri ​putem avea şi tipuri simple de date).+Când scriem ceva într-o uniune (de exemplu când facem o atribuire de genul u1.f = 7.4)ceea ce citim apoi trebuie să fie de acelaşi tip, altfel vom obţine rezultate eronate (adică trebuie să utilizam u1.fnu u1.v sau u1.i). Programatorul trebuie să ţină evidenţa tipului variabilei care este memorată ​în uniune în momentul curent pentru a evita astfel ​de greşeli. Operaţiile care se pot face cu structuri ​se pot face şi cu uniuni; o structura poate conţine uniuni şi o uniune poate conţine structuri.
  
- +Exemplu:
-== Exemplu ​3 == +
-Să reluăm problema de la Exemplul 1. Să presupunem că rezolvăm aceeași problemă, doar ca fișierul de intrare este binarprimii 4 bytes din fișier reprezintă numarul n (numărul de elemente); următorii 4*n bytes reprezintă vectorul. +
- +
-Luăm ca exemplul fișierul text care are conținutul. +
-<code c> +
-gigel.in +
-+
-1 2 3 +
-</​code>​ +
-Fișierul binar echivalent este "​gigel_in.bin"​.  +
-<code c> +
-gigel_in.bin +
-0300 0000 0100 0000 0200 0000 0300 0000 +
-</​code>​ +
-<note warning>​ +
-   * Fișierul poate fi descărcat de [[http://​ocw.cs.pub.ro/​courses/​_media/​programare/​teme_2016/​lab11_gigel_in.zip | aici]]. +
-   * Pentru a putea vizualiza continutul mai usor, acesta poate fi deschis cu [[https://​www.sublimetext.com/​ | Sublime]]. Observați reprezentarea în baza 16 a numerelor. Fiecare grup de câte 2 cifre reprezintă un octet. 4 astfel de grupuri formează un int: "0300 0000" semnifică numărul 3. +
-   * Atenție la [[https://​en.wikipedia.org/​wiki/​Endianness || Endianness]]! +
-</​note>​ +
-Următoarea sursă C citește vectorul din fișierul "​gigel_in.bin",​ dublează elementele și apoi scrie rezultatul în "​gigel_out.bin"​.+
 <code c> <code c>
 #include <​stdio.h>​ #include <​stdio.h>​
-#define NMAX 100+#include <​stdlib.h>​
  
-int sizeof_file(char *filename) ​+typedef union 
-    // deschidere fisier de intrare pentru +  int Wind_Chill; 
-    // citire (r) in modul text (t) +  char Heat_Index; 
-    FILE *file = fopen(filename,​ "​rt"​);+} Condition;
  
-    // verific daca fisierul a fost deschis cu succes +typedef struct ​
-    // altfel opresc executia +  float temp
-    if (file == NULL) +  ​Condition feels_like
-        ​return -1// nu am putut calcula dimensiunea +} Temperature;
-    } +
- +
-    // ma pozitionez la sfarsit +
-    fseek(file, 0, SEEK_END)+
-    // acum cursorul este dupa ultimul caracter +
-    // deci ftell imi va spune pozitia, care este echivalenta cu numarul de bytes +
-    int bytes_count = ftell(file); +
- +
-    // inchid fisierul +
-    fclose(file);​ +
- +
-    return bytes_count;​ +
-}+
  
 int main() { int main() {
-    // numele fisierului de intrare 
-    char input_filename[] = "​gigel_in.bin";​ 
-    FILE *in; 
  
-    // incerc sa dechid pentru citire ​(r) +  Temperature *tmp; 
-    // fisierul in mod binar (b+  tmp = (Temperature *)malloc(sizeof(Temperature)); 
-    ​// observati alt mod de a scrie deschiderea && verificarea +     
-    if ((in fopen(input_filename, "rb"​)) ​== NULL{ +  ​printf("​\nAddress of Temperature ​%u"tmp); 
-        ​fprintf(stderr, ​"Can't open %s", ​input_filename); +  printf("\nAddress of temp = %u, feels_like = %u",  
-        ​return -1; +                 &​(*tmp).temp,&​(*tmp).feels_like); 
-    }+  ​printf("\nWind_Chill = %u, Heat_Index= %u\n", ​ 
 +                 &​((*tmp).feels_like).Wind_Chill,​ 
 +                 &​((*tmp).feels_like).Heat_Index);
  
-    // numarul de elemente, vectorul, variabila de iterare +  ​return 0;
-    int n, v[NMAX], i; +
- +
-    // doresc sa citesc tinand cont de: +
-    // voi stoca in n (deci specific adresa lui n ca la scanf => &n) +
-    // valoarea citita are dimensiunea unui int => sizeof(int) +
-    // citesc o singura variabila => 1 +
-    // voi citi din fisierul asociat cu variabila in +
-    fread(&​n,​ sizeof(int),​ 1, in); +
- +
-    // fread permite citirea unui vector printr-un singur apel +
-    // doresc sa citesc tinand cont de: +
-    // voi stoca in v (care este adresa primul element) +
-    // o valoare citita are dimensiunea unui int => sizeof(int) +
-    // citesc n valori +
-    // voi citi din fisierul asociat cu variabila in +
-    fread(v, sizeof(int),​ n, in); +
- +
-    // pot inchide fisierul +
-    fclose(in);​ +
- +
-     // dublez elementele din vector +
-    for (i = 0; i < n; ++i) { +
-        v[i] <<= 1; +
-    } +
- +
-    // salvez rezultatul in fisierul out +
-     // numele fisierului de intrare +
-    char output_filename[] = "​gigel_out.bin";​ +
-    FILE *out; +
- +
-    // incerc sa dechid pentru scriere (w) +
-    // fisierul in mod binar (b) +
-    // observati alt mod de a scrie deschiderea && verificarea +
-    if ((out = fopen(output_filename,​ "​wb"​)) == NULL) { +
-        fprintf(stderr,​ "​Can'​t open %s", output_filename);​ +
-        return -1; +
-    } +
- +
-    // doresc sa scriu tinand cont de: +
-    // voi scrie valoare de la adresa lui n (&n) +
-    // valoarea scrisa are dimensiunea unui int => sizeof(int) +
-    // scriu o singura variabila => 1 +
-    // voi scrie in fisierul asociat cu variabila out +
-    fwrite(&​n,​ sizeof(int),​ 1, out); +
- +
- +
-    // fwrite permite scrierea unui vector printr-un singur apel +
-    // doresc sa scriu tinand cont de: +
-    // voi scrie elemente incepand de la adresa indicata de v +
-    // o valoare scrisa are dimensiunea unui int => sizeof(int) +
-    // scriu n valori +
-    // voi scrie in fisierul asociat cu variabila out +
-    fwrite(v, sizeof(int),​ n, out); +
- +
-    // inchid fisierul +
-    fclose(out);​ +
- +
-    ​return 0;+
 } }
 </​code>​ </​code>​
-Rezultatul îl putem vizualiza tot cu Sublime. 
-<code c> 
-gigel_out.bin 
-0300 0000 0200 0000 0400 0000 0600 0000 
-</​code>​ 
-<note warning> 
-   * În acest exemplu am pus extensia "​bin"​ pentru a sugera faptul că fișierele sunt binare. Acest lucru este irelevant pentru funcțiile fread și fwrite. 
-</​note>​ 
- 
-=== Citire/​scriere la nivel de caracter === 
  
 +La rulare va afişa:
 <code c> <code c>
-int fgetc(FILE *fp); // întoarce următorul caracter din fişier, EOF la sfârşit de fişier +Address of Temperature = 165496 
-</​code>​ +Address of temp = 165496feels_like = 165500 
- +Wind_Chill = 165500Heat_Index= 165500
-<code c> +
-char* fgets(char *sint n, FILE *fp); // întoarce următoarele n caractere de la pointer sau pâna la sfârşitul de linie +
-</​code>​ +
- +
-<code c> +
-int fputc(int c, FILE *fp); //pune caracterul c in fişier +
-</​code>​ +
- +
-<code c> +
-int ungetc(int cFILE *fp); // pune c în bufferul asociat lui fp (c va fi următorul caracter citit din fp)+
 </​code>​ </​code>​
  
 ===== Exercitii laborator CB/CD ===== ===== Exercitii laborator CB/CD =====
  
-Codul sursa se gaseste [[http://​swarm.cs.pub.ro/​~gmuraru/​PC/​lab11.c|aici]], iar fisierul text necesar rularii programului este [[http://​swarm.cs.pub.ro/​~gmuraru/​PC/​lab11.in|aici]]. +Codul sursa se gaseste [[http://​swarm.cs.pub.ro/​~gmuraru/​PC/​lab10.c|aici]] 
- +Primul exercitiu presupune modificarea/​adaugarea de instructiuni unui cod existent pentru a realiza anumite lucruri. In momentul actual programul ​numara cate persoane au acelasi prenume.
-Primul exercitiu presupune modificarea/​adaugarea de instructiuni unui cod existent pentru a realiza anumite lucruri. In momentul actual programul ​citeste dintr-un fisier text mai multe date si le afiseaza la output.+
  
 Cerinte: Cerinte:
-  *Observati care este diferenta de size intre structuri, daca se foloseste pragma si daca nu se foloseste. +  *Sa se afiseze cate persoane s-au nascut in acelasi an 
-  *Sa se populeze o structura de tipul '​Group'​ folosind fisierul binar de [[http://​swarm.cs.pub.ro/​~gmuraru/​PC/​lab11.bin|aici]],​ iar apoi aceste date sa se scrie intr-un fisier text. Datele se citesc in ordine din fisierul binar (adica prima data numarul de persoane apoi persoanele ​efective).+  *Sa se sorteze ​persoanele ​dupa nume
  
 **Următoarele două probleme vă vor fi date de asistent în cadrul laboratorului.** **Următoarele două probleme vă vor fi date de asistent în cadrul laboratorului.**
 +
 +[[ https://​ocw.cs.pub.ro/​courses/​programare/​checker | Tutorial folosire checker laborator ]]
 +
 <​hidden>​ <​hidden>​
-Link direct către lista completă de probleme: [[https://​docs.google.com/​document/​d/​1_HZEaz83M_H6K-qKDgc061PRKDEjy2fZKoYvWBiQOug/​edit|aici]]+Link direct către lista completă de probleme: [[https://​docs.google.com/​document/​d/​1Q374YAA_JopvxJNv-WG51xA6_bSDJSS3nha63XH1N4I/edit?​usp=sharing|aici]] 
 + 
 +Link catre teste: [[https://​drive.google.com/​drive/​folders/​12WvwMu7Do5QWlbjvnYrmbL_UWb73O-f3?​usp=sharing|aici]]
 </​hidden>​ </​hidden>​
  
  
 +==== Exerciţii de laborator ====
  
-==== Exerciţii de Laborator ====+  - [2p] O matrice rară (cu circa 90% din elemente 0) este păstrată economic sub forma unei structuri, care conţine următoarele câmpuri: 
 +      * int L,C - numărul de linii/​coloane al matricei rare 
 +      * int N - numărul de elemente nenule 
 +      * int LIN[] - vectorul ce păstrează liniile în care se află elemente nenule 
 +      * int COL[] - vectorul ce păstrează coloanele în care se află elemente nenule 
 +      * float X[] - vectorul ce păstrează elementele nenule 
 +  - Să se definească funcţii pentru: 
 +      * [1p] citirea unei matrice rare 
 +      * [1p] afişarea unei matrice rare (ca o matrice, cu tot cu zerouri) 
 +      * [2p] adunarea a două matrice rare.  
 +      * **Observatii** :  
 +      * Vectorii LIN, COL, X vor avea fiecare cate N elemente. 
 +      * Elementul nenul cu valoare X[index] se afla pe linia LIN[index] si coloana COL[index]. 
 +      * Elementele vor fi citite in ordinea crescatoare a liniilor, iar elementele ​de pe aceeasi linie in ordinea crescatoare a coloanelor. 
 +  - Un polinom este reprezentat printr-o structură care conţine gradul polinomului şi tabloul coeficientilor. Să se definească funcţii pentru: 
 +      * [1p] citirea unui polinom 
 +      * [1p] afişarea unui polinom 
 +      * [2p] adunarea/​scăderea a două polinoame
  
-  - [3p] Ştergeţi toate apariţiile unui cuvânt dintr-un fişier text. Numele fișierului și cuvântul ​care se şterge se citesc de la tastatură. Programul vostru trebuie să suprascrie fișierul inițial. +==== Bonus ==== 
-  ​- Rezolvaţi următoarele cerinţe: +1. [3p] În registrul ''​Uni-Struct'',​ fiecărui elev îi corespunde o înregistrare ​care reține: 
-    - [2p] Să se scrie un program pentru crearea unui fişier binar, având articole structuri cu următoarele câmpuri:<​code>​ +  ​* numele acestuia (maxim 50 de caractere), 
- nume depunător +  * clasa în care acesta se află (valoare ​de tipul ''​unsigned ​int''​)
-    şir de maxim 30 de caractere +  * rezultatul obținut la materia cea mai apropaiata (ca semnificație) ​de programare
- data depunerii +  ​ 
-    ​structură având câmpurile ​de tip int: zi,lună,an +Tipul rezultatului diferă în funcție de clasa în care elevul ​se află, astfel: 
- suma depusă  +    ​* elevii ​din clasele primare ​(1-4), primesc ​un calificativ (FB, BS, I) reprezentat ca un șir maxim 9 caractere;​ 
-    o valoare reala, ​de tip float.  +    * elevii din toate celelalte clase primesc note, care vor fi reținute cu ajutorul unui câmp de tip ''​float''​. 
-  ​Observaţie: Articolele sunt grupate pe zile in ordine cronologică. +  
-Datele ​se introduc de la consolă, fiecare pe 3 linii.  +Scrieți ​un program ​care citește ​de la tastatură astfel ​de înregistrări,​ până ​la inserarea șirului ​de caractere ​''​"​stop"​'' ​în locul numelui unuia dintre elevi, apoi afișează toți studenții din registru, alături de toate informațiile despre ei, în ordinea lexicografică a numelor cu care sunt înregistrați. 
-</​code>​ + 
-    ​- [1p] Citiţi ​din fişierul ''​lab11p2.bin'' ​(prezent in {{:​programare:​laboratoare:​lab11.zip|arhiva laboraturlui}}şi afişati rezultatele intr-un fişier texta cărui denumire va fi ''​lab11p2.txt''​. +Folosiți ​un vector ​de structuri pentru a stoca toate informațiile despre eleviFaceți eficient reținerea unei singure valori pentru rezultatul parcurgerii materiei în cadrul structurii. 
-  - [2p] Generati ​un fisier binar care sa contina un numar n de numere intregi. n se va citi de la tastatura si cele n numere se vor genera random. In fisierul ​de output afisati doar cele n numere intregi generate. Numele fisierului generat se va citi de asemenea de la tastatura. + 
-  - Se citeste fisier binar ''​lab11p4.bin'' ​(prezent in {{:​programare:​laboratoare:​lab11.zip|arhiva laboraturlui}}). In cadrul acestuia ​sunt un numar nedeterminat ​de numere intregi+<​file ​bonus.in
-    [1p] Afisati numarul de numere intregi din acest fisier<file   ​Indicatie:​ +Ionut Popescu 
-fseek(file,​0,​SEEK_END);​ +10 
-poz=ftell(file);​ +7.4 
-nrNumereIntregi=poz/?;​+Maria Almasan 
 +
 +FB 
 +Alex Grigorescu 
 +12 
 +10 
 +stop
 </​file>​ </​file>​
-    - [1p] Să se calculeze suma numerelor impare din fişier . 
  
-==== Bonus ==== +<file bonus.out> 
-<hidden>​ +Alex Grigorescu 
-  ​[3p] Să se scrie un program care determină toate secvenţele binare de lungime n, fiecare din ele conţinând nu mai mult de k cifre de 1. +12 
-    - **Intrare**:​ Numerele naturale n, 1<​n<​20,​ şi k, k<=n, se citesc din fişierul in.txt. +10 
-    - **Ieşire**:​ fiecare linie a fişierului text out.txt va conţine câte o secvenţă binară distinctă, ce corespunde condiţiilor din enunţul problemei. +Ionut Popescu 
-</hidden+10 
-  - [3p] Se dau n nume de fișiere citite de la tastatură, fiecare fișier binar conține un vector de numere intregi sortat crescător (nu se cunosc dimensiunile vectorilor). Se cere să salveze în fișierul ''​sortare.out''​ (de tip text) vectorul sortat crescător obținut prin interclasarea celor n vectori. ​ +7.4 
-<​hidden>​ +Maria Almasan 
-  - [2p] Într-un fişier există cuvinte, câte unul pe fiecare rând. Să se verifice dacă cuvintele de pe poziţii consecutive sunt rime. (dacă ultimele p caractere ale celor 2 cuvinte coincid, unde p este prima valoare citită din acelaşi fişier). +3 
-<file - rime.in> ​   2 +FB
-    ferit +
-    ​indraznit +
-    indraznet +
-    istet +
-    descurcaret +
-</​file>​ +
-<file - rime.out> ​   DA +
-    NU +
-    DA +
-    DA+
 </​file>​ </​file>​
-<file >  Explicaţie: ​ + 
-    ​Ultimele 2 litere ale cuvintelor "​ferit"​ si "​indraznit"​ + 
-coincid, pe când "​indraznit"​ cu "​indraznet"​ nu coincid. + 
-</​file>​ + 
-</​hidden>​ +
-==== Arhiva laborator ==== +
-{{:​programare:​laboratoare:​lab11.zip|}}+
 ==== Referinţe ==== ==== Referinţe ====
-  * [[http://​crasseux.com/​books/​ctutorial/​Input-and-output.html#Input%20and%20output|The GNU Programming Tools - Input and Output]]+  * [[http://​crasseux.com/​books/​ctutorial/​/Data-structures.html#Data%20structures|The GNU Programming Tools - Data structure]] 
 +  * [[http://​publications.gbdirect.co.uk/​c_book/​chapter6/​unions.html|The C Book - Unions]]
programare/laboratoare/lab11.1483661839.txt.gz · Last modified: 2017/01/06 02:17 by darius.neatu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0