This shows you the differences between two versions of the page.
programare-cc:laboratoare:08 [2020/11/10 23:26] bogdan.nutu |
programare-cc:laboratoare:08 [2020/12/03 15:06] (current) bogdan.nutu |
||
---|---|---|---|
Line 1: | Line 1: | ||
===== Laboratorul 08 - Alocare dinamică ===== | ===== Laboratorul 08 - Alocare dinamică ===== | ||
- | |||
- | **În acest laborator veţi învăţa să:** | ||
- | |||
- | * Alocaţi dinamic memorie folosind funcţiile malloc, calloc şi realloc | ||
- | * Folosiţi funcţia strdup pentru a clona şiruri de caractere | ||
- | * Eliberaţi memoria alocată folosind funcţia free. | ||
- | |||
- | Funcţii pentru alocarea memoriei (din **stdlib.h**): | ||
- | |||
- | * **malloc** | ||
- | <code c>type* ptr = malloc(size_t size);</code> | ||
- | Unde size_t este un tip întreg fără semn (unsigned), dependent de arhitectură (pentru arhitectura 32bit, acesta este unsigned int). | ||
- | |||
- | Funcţia alocă o zonă continuă de memorie având dimensiunea de size octeţi şi returnează un pointer void* cu adresa de început a zonei de memorie alocată. Pentru a schimba tipul acestui pointer se foloseşte operatorul cast. | ||
- | |||
- | Exemplu: | ||
- | <code c>int *a = malloc( 100 * sizeof(int) );</code> | ||
- | Am alocat o zonă de memorie de 100 de elemente de tip int. Tipului pointerului returnat de funcţie, void*, i se face cast automat în int*. | ||
- | |||
- | Funcţia sizeof(type) returnează numărul de octeţi ocupaţi de tipul type. | ||
- | |||
- | * **calloc** | ||
- | <code c>type* ptr = calloc(size_t num, size_t size);</code> | ||
- | |||
- | Funcţia alocă spaţiu de memorie pentru un vector cu num elemente, fiecare element având dimensiunea size de octeţi şi returnează un pointer void* cu adresa de început a zonei de memorie alocată. **Atenţie!** Toţi biţii din această zonă de memorie sunt setaţi pe 0. | ||
- | |||
- | Exemplu: | ||
- | <code c>int *a = calloc( 100, sizeof(int) );</code> | ||
- | Am alocat o zonă de memorie de 100 de elemente de tip int. Toţi biţii din această zonă de memorie au valoarea 0. | ||
- | |||
- | * **realloc** | ||
- | <code c>type* ptr = realloc(void* old_ptr, size_t size);</code> | ||
- | |||
- | Unde old_ptr este adresa de început a zonei de memorie pe care dorim să o realocăm, size reprezintă noua dimensiune a zonei de memorie (în octeţi), iar ptr este adresa de început a zonei de memorie după realocare. | ||
- | |||
- | Funcţia realizează modificarea dimensiunii zonei de memorie referite de old_ptr. | ||
- | |||
- | Exemplu: | ||
- | <code c> | ||
- | int *a = malloc( 100 * sizeof(int) ); | ||
- | a = realloc( a, 200 * sizeof(int) ); | ||
- | </code> | ||
- | Am alocat o zonă de memorie de 100 de elemente de tip int. Am mărit zona de memorie pentru 200 de elemente întregi. Atenţie! După realocare, cele 100 de numere întregi aflate iniţial în vectorul a au rămas nemodificate. | ||
- | |||
- | * **free** | ||
- | <code c>void free(void* ptr);</code> | ||
- | Unde ptr reprezintă adresa zonei de memorie pe care dorim să o eliberăm. | ||
- | |||
- | * **strdup** | ||
- | <code c>char *strdup( char *s );</code> | ||
- | |||
- | Unde s reprezintă un string (şir de caractere terminat cu '\0'). | ||
- | |||
- | Funcţia alocă o nouă zonă de memroie la care se copiază octeţii şirului s. Se returnează un pointer către începutul zonei de memorie unde s-a făcut copierea. | ||
==== Problemă rezolvată ==== | ==== Problemă rezolvată ==== | ||
Line 185: | Line 131: | ||
^ Intrare ^ Ieşire ^ | ^ Intrare ^ Ieşire ^ | ||
| 6 \\ ana are \\ mere are mere mere | ana 1 \\ are 2 \\ mere 3 | | | 6 \\ ana are \\ mere are mere mere | ana 1 \\ are 2 \\ mere 3 | | ||
+ | |||
+ | === Problema 4 === | ||
+ | ---- | ||
+ | |||
+ | Să considerăm următoarea problemă: dorim să calculăm **C(n,k)** folosind relaţia de recurenţă: | ||
+ | |||
+ | C(n,k) = C(n-1,k) + C(n-1,k-1) | ||
+ | |||
+ | Să considerăm că am ales să rezolvăm problema în următorul mod: definim o matrice c de dimensiuni suficient de mari, în care elementul c[i][j] reprezintă valoarea C(i,j). Vom iniţializa linia 1 a matricei (C(1,0) = C(1,1) = 1) şi vom calcula, pe rând, aplicând relaţia de recurenţă, valorile C(i,j) până când am obţinut valoarea cerută de problemă: C(n,k). | ||
+ | |||
+ | Acest algoritm rezolvă problema, dar prezintă un dezavantaj. Pentru calculul unei valori, trebuie păstrată în memorie o matrice de dimensiuni relativ mari, care ocupă multă memorie. În plus, observăm că pentru a calcula C(i,j), care se va afla pe linia i în matrice, avem nevoie doar de valori de pe linia i-1. Astfel, putem aduce o economie de memorie majoră în program dacă în loc să păstrăm întreaga matrice în memorie, păstrăm doar doi vectori vim1[] şi vi[] care să reprezinte liniile i-1, respectiv i din matrice. | ||
+ | |||
+ | Avem acum două optiuni: | ||
+ | * După terminarea calulului valorilor de pe o linie, în vectorul vi[], putem să le copiem pe toate în vectorul vim1[] şi să continuăm calculul următoarei linii în vi[]. Această metodă, însă, presupune ca după fiecare linie să copiem "n" elemente dintr-un vector în altul, şi introduce un cost de eficienţă inutil (ceea ce am economisit la capitolul memorie, irosim la capitolul rapiditate a programului). | ||
+ | * Metoda mai rapidă şi mai elegantă este ca, în loc să copiem conţinutul lui vi[] în vim1[], să interschimbăm doar variabilele de tip pointer care indică către începutul acestor şiruri. Altfel spus, nu mutăm efectiv valorile prin memorie, ci doar le interschimbăm "rolul". În acest mod, se efectuează în loc de mutarea a "n" elemente, doar cele trei instrucţiuni ale interschimbării de variabilă. | ||
+ | |||
+ | Să se scrie un program care calculează valoarea lui C(n,k) prin metoda descrisă mai sus, reducând matricea la doi vectori, şi schimbând după fiecare pas, rolul jucat de aceşti doi vectori. | ||
+ | |||
+ | == Date de intrare == | ||
+ | ---- | ||
+ | |||
+ | Pe o singura linie se vor afla cele 2 valori **n** si **k**. | ||
+ | |||
+ | == Date de ieşire == | ||
+ | ---- | ||
+ | |||
+ | Pe prima linie din fisierul de iesire se va afisa valoarea **C(n, k)**. | ||
+ | |||
+ | |||
+ | == Restrictii si Precizari == | ||
+ | ---- | ||
+ | |||
+ | * 0 ≤ k ≤ n ≤ 25 | ||
+ | |||
+ | == Exemplu == | ||
+ | |||
+ | ---- | ||
+ | ^ Intrare ^ Ieşire ^ | ||
+ | | 5 3 | 10 | | ||
+ | |||
+ | === Problema 5 === | ||
+ | ---- | ||
+ | |||
+ | Se citesc de la tastatură cuvinte separate prin câte un spatiu alb. Pornind de la cuvintele citite, se construieşte un şir de caractere după următoarele reguli: | ||
+ | * Primul cuvânt citit se adaugă la şirul de caractere; | ||
+ | * Fiecare din următoarele cuvinte citite se adaugă la şirul de caractere dacă ultimele două litere ale ultimului cuvânt din şir coincid cu primele două litere ale cuvântului curent (nu se face distincţie între literele mici şi cele mari); | ||
+ | * Cuvintele adăugate la şirul de caractere sunt despărţite de caracterul ’-’. | ||
+ | |||
+ | == Date de intrare == | ||
+ | ---- | ||
+ | |||
+ | Pe prima linie din fişierul de intrare se va afla un numar natural **n** reprezentand numarul de cuvinte din fisier. | ||
+ | Pe urmatoarea linie se afla cele **n** cuvinte separate prin cate un spatiu. | ||
+ | |||
+ | == Date de ieşire == | ||
+ | ---- | ||
+ | |||
+ | O singura linie ce reprezinta cuvintele din sirul separate prin cate un '-' si care respecta ordinea din cerinta. | ||
+ | |||
+ | == Restrictii si Precizari == | ||
+ | ---- | ||
+ | |||
+ | * n <= 100 | ||
+ | |||
+ | == Exemplu == | ||
+ | |||
+ | ---- | ||
+ | ^ Intrare ^ Ieşire ^ | ||
+ | | 5 \\ abC def bcFr ty froop | abC-bcfR-froop | | ||