This shows you the differences between two versions of the page.
programare:coding-style [2020/10/07 17:21] dorinel.filip Added memory leaks and files |
programare:coding-style [2024/11/05 16:33] (current) darius.neatu [Convenție] |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ===== Coding style CA ===== | + | ===== Coding style example ===== |
**Responsabili:** | **Responsabili:** | ||
- | * [[neatudarius@gmail.com|Darius Neațu ]] (2018-2020) | + | * [[neatudarius@gmail.com|Darius Neațu ]] (2018-2024) |
- | * [[ion_dorinel.filip@cti.pub.ro|Dorinel Filip]] (2018-2020) | + | * [[ion_dorinel.filip@cti.pub.ro|Dorinel Filip]] (2018-2024) |
Line 145: | Line 145: | ||
== functions == | == functions == | ||
+ | |||
Analizați exemplele de funcții de mai jos și observați că. | Analizați exemplele de funcții de mai jos și observați că. | ||
* numele funcțiilor e sugestiv | * numele funcțiilor e sugestiv | ||
Line 154: | Line 155: | ||
<code c> | <code c> | ||
- | void clean_display() | + | void clean_display(void) |
{ | { | ||
... | ... | ||
Line 189: | Line 190: | ||
== programs == | == programs == | ||
+ | |||
Fie următorul șablon de program. Analizați: | Fie următorul șablon de program. Analizați: | ||
- | * cum scriem în fișier mai multe funcții | + | * cum scriem în fișier mai multe funcții |
- | * care e structura generală a unui program | + | * care e structura generală a unui program |
<code c> | <code c> | ||
Line 199: | Line 201: | ||
#define NMAX 100 // nu vom declara tablouri cu int v[100]; ci vom folosi un macro pentru dimensiune | #define NMAX 100 // nu vom declara tablouri cu int v[100]; ci vom folosi un macro pentru dimensiune | ||
// linie goala | // linie goala | ||
- | void dummy() | + | void dummy(void) |
{ | { | ||
} | } | ||
Line 208: | Line 210: | ||
} | } | ||
// lasam o linie goala intre functii | // lasam o linie goala intre functii | ||
- | int main() | + | int main(void) |
{ | { | ||
... | ... | ||
Line 217: | Line 219: | ||
<note> | <note> | ||
- | Evident ca atunci cand fișirul 'main.c' devine prea mare, este nevoie să grupăm componentele după logică și să le mutăm în alte fișiere sursă C/headere. | + | Evident ca atunci când fișierul 'main.c' devine prea mare, este nevoie să grupăm componentele după logică și să le mutăm în alte fișiere sursă C/headere. |
</note> | </note> | ||
- | === Coding Style checker === | + | |
- | Pentru a vă ajuta la teme și a evita eventualele depunctări pentru chestii standard, echipa vă pune la dispoziție scriptul *cs.sh*. Acesta va fi folosit la teme pentru a depuncta în mod automat cele mai frecvente erori de coding style. | + | === Seria CA - Coding Style checker === |
+ | Pentru a vă ajuta la teme și a evita eventualele depunctări pentru chestii standard, echipa vă pune la dispoziție scriptul *cs.sh*. Acesta va fi folosit la teme pentru a depuncta în mod automat cele mai frecvente erori de coding style la seria CA. | ||
<note> | <note> | ||
Line 228: | Line 231: | ||
<note> | <note> | ||
- | Checkerul de coding style se găsește la adresa [[https://cutt.ly/pc20-cs|https://cutt.ly/pc20-cs]]. | + | Checkerul de coding style se găsește la adresa [[https://cutt.ly/PCLP1-CA-CS-2024]]. |
</note> | </note> | ||
Line 235: | Line 238: | ||
</note> | </note> | ||
- | === Alocarea de memorie și lucrul cu fișiere === | ||
- | |||
- | Alocarea de memorie este un subiect care pune probleme multora atunci când fac primii pași în utilizarea limbajului C. În această secțiune, atragem atenția asupra unor elemente importante referitoare la alocarea de memorie și lucrul cu fișiere. | ||
- | |||
- | <note>Recomandăm citirea acestei secțiuni după parcurgerea laboratoarelor de ''Alocare dinamică de memorie'', respectiv ''Fișiere''.</note> | ||
- | |||
- | == Memory leaks == | ||
- | |||
- | Memory leak-urile reprezintă o eroare de programare, în ceea ce privește alocarea dinamică de memorie, reprezentată de situația în care memoria nefolosită rămâne alocată. | ||
- | |||
- | <note warning>Atunci când folosim memorie alocată dinamic (cu ''malloc(...)'', ''calloc(...)'' etc.) trebuie să avem în vedere să și dealocăm memoria atunci când nu o mai folosim!</note> | ||
- | |||
- | Prin utilizarea utilitarului [[https://valgrind.org|Valgrind]] checker-ul folosit la notarea automată a temelor poate descoperi execuțiile care lasă memorie nedealocată, iar acest lucru va fi depunctat, conform enunțului temei repective. | ||
- | |||
- | == Neînchiderea fișierelor == | ||
- | |||
- | O problemă foarte similară Memory Leak-urilor o reprezintă neînchiderea fișierelor. | ||
- | |||
- | <note warning>**Lucrul corect cu fișiere trebuie să includă:** | ||
- | - deschiderea fișierului în modul corect; | ||
- | - verificarea reușitei operației de deschidere; | ||
- | - procesarea conținutului fișierului (operațiile efective de citire/scriere/salt); | ||
- | - închiderea fișierului. | ||
- | </note> | ||
- | |||
- | == Utilizarea tipului nepotrivit de alocare de memorie == | ||
- | |||
- | O altă problemă frecventă referitoare la alocarea de memorie o reprezintă utilizarea tipului nepotrivit de alocare de memorie. | ||
- | |||
- | În continuare vom exemplifica doar câteva astfel de erori: | ||
- | |||
- | ---- | ||
- | |||
- | **Folosirea alocării dinamice pentru situații în care cantitatea de memorie ce urmează să fie alocată este cunoscută anterior și se dealocă în același context.** | ||
- | |||
- | <code C> | ||
- | #define VECTOR_SIZE 9 | ||
- | |||
- | void asa_nu() { // Exemplu de utilizare nerecomandata | ||
- | int *v = malloc(VECTOR_SIZE * sizeof(int)); | ||
- | |||
- | // lucru cu vectorul v[] | ||
- | ... | ||
- | |||
- | free(v); | ||
- | } | ||
- | |||
- | void asa_da() { | ||
- | int v[VECTOR_SIZE]; | ||
- | |||
- | // lucru cu vectorul v | ||
- | ... | ||
- | |||
- | } | ||
- | </code> | ||
- | |||
- | O excepție de la această regulă se face atunci când dorim să alocăm cantități mari de mamorie, deoarece alocarea dinamică permite tratarea situației de [[https://en.wikipedia.org/wiki/Out_of_memory|OOM (Out of Memory)]] și în multe cazuri permite alocarea unor zone mult mai mari de memorie. | ||
- | |||
- | ---- | ||
- | |||
- | **Utilizarea Variable Length Arrays pentru alocarea de vectori mari sau cu dimensiune provenită din calcule fără limită superioară sau din input-ul utilizatorului** | ||
- | |||
- | În cele mai recente versiuni, limbajul C permite alocarea de vectori folosind ca dimensiune variabile de tip întreg. Deși acest lucru permite utilizarea eficientă a spațiului de memorie de pe stivă funcției, utilizarea necorespunzătoare a acestei opțiuni poate duce la apariția unor erori la execuție (''segmentation fault'' sau ''stack smashed'') ce nu pot fi tratate. | ||
- | |||
- | O eroare comună o reprezintă utilizarea input-ului (neverificat) al utilizatorului ca dimensiune de alocare: | ||
- | |||
- | <code C> | ||
- | void asa_nu() { // Exemplu de utilizare nerecomandata | ||
- | int n; | ||
- | scanf("%d", &n); | ||
- | |||
- | int v[n]; // dacă utilizatorul introduce un număr foarte mare sau negativ putem avea eroare la execuție | ||
- | |||
- | ... | ||
- | } | ||
- | </code> | ||
- | |||
- | În continuare, vom prezenta 2 variante de tratare corectă a acestei situații: | ||
- | - Validarea faptului că avem un număr pozitiv și limitarea dimensiunii alocabile; | ||
- | - Folosirea alocării dinamice. | ||
- | |||
- | <code C> | ||
- | #define MAX_SIZE 10000 | ||
- | |||
- | void asa_da_1() { | ||
- | int n; | ||
- | scanf("%d", &n); | ||
- | |||
- | while(n < 0 || n > MAX_SIZE) { | ||
- | printf("Numarul este prea mare, te rog introdu un nr. din [0, %d]\n", MAX_SIZE); | ||
- | scanf("%d", &n); | ||
- | } | ||
- | |||
- | // Prelucrare vector v | ||
- | ... | ||
- | |||
- | } | ||
- | |||
- | |||
- | void asa_da_2() { | ||
- | int n; | ||
- | int *v; | ||
- | |||
- | scanf("%d", &n); | ||
- | |||
- | while(n < 0) { | ||
- | printf("n trebuie sa fie un numar pozitiv. Reincearca!\n"); | ||
- | scanf("%d", &n); | ||
- | } | ||
- | |||
- | v = malloc(n * sizeof(int)); | ||
- | if(v == NULL) { | ||
- | fprintf(stderr, "Nu am putut aloca memorie.\n"); | ||
- | exit(-1); | ||
- | } | ||
- | |||
- | // Prelucrare vector v | ||
- | ... | ||
- | |||
- | // Dealocare memorie pentru v | ||
- | free(v); | ||
- | } | ||
- | </code> | ||
- | |||
- | Pentru soluția 1 se observă că pune în responsabilitatea programatorului determinarea lui 'MAX_SIZE', care poate interveni ca o limitare nejustificată a funcționalității programului. | ||
- | |||
- | Un cititor al soluției 2 poate reclama contradicțiecu recomandarea de a folosi memorie alocată static dacă dealocarea se va face în același context și dimensiunea alocată nu este mare. Totuși, codul nu garantează că n este un număr mic. | ||
- | |||
- | <note>**Nu** este recomandată combinarea (pe cazuri) a celor 2 soluții, deoarece complică foarte mult codul, iar plusul de performanță este rareori semnificativ. | ||
- | |||
- | Eventual, am putea face 2 versiuni ale funcției (pentru valori mari respectiv mici ale lui ''n''), dacă ne așteptăm ca funcția pentru valori mici să fie apelată de **mii/milioane de ori pe secundă** pentru ca timpul, mai mare, necesar pentru ''malloc(...)'' să conteze. | ||
- | </note> | ||
- | |||
- | === Concluzie - seria CA=== | ||
- | Este foarte important să avem un coding style OK. Această pagină vine în ajutorul vostru. | ||
- | |||
- | <note warning> | ||
- | Scriptul prezentat pe această pagină va fi folosit pentru verificarea automată a temelor de la **seria CA**a coding style-ului la teme. În caz ca apar erori se va penaliza conform mentiunilor din enunt. | ||
- | |||
- | </note> |