Laborator 12: Recursivitate, Pointeri la funcții. Funcţii cu număr variabil de parametri
Obiectivele laboratorului
- alte aspecte legate de recursivitate;
- pointer la funcții: cum putem manipula funcțiile prin intermediul pointerilor;
- funcții generice (paremetri de tip
void *
) - aplicație: sortare generică; - cum putem scrie funcții cu număr variabil de parametri - aplicație: funcție de numărare paremetri, gcd pentru un număr variabil de numere.
Materiale utile
- [OCW/Suport Teoretic pentru Laborator] Secțiunea '"Pointeri la funcții"
- [OCW/Suport Teoretic pentru Laborator] Secțiunea '"Funcţii cu număr variabil de parametri"
Exerciții
- Analizați împreună cu asistentul exemplul funcției
listf
din secțiunea de teorie de pe ocw.
a. Rulați programul dat în exemplu.
b. Modificați programul anterior a.i. să apelați funcția listf pentru a afișa valorile corespunzătoare pentru următoarele funcții matematice:
i. sin
ii. cos
iii. exp
iv. log10
v. sqrt
vi. fabs
ATENȚIE! Se dorește implementarea unei soluții modularizate, de aceea obligatoriu se va defini un vector de pointeri la funcții. Orice altă soluție nu se va puncta.
- Realizați implementarea funcției cu număr variabil de parametri numită
gcd
, care să permită aflarea celui mai mare divizor comun (gcd) al parametrilor dați (cel puțin două elemente care sunt numere naturale). Puteți presupune că lista se termină cu un număr negativ.
Hint: Exemplu 8 din teoria indicată de pe ocw.
Exemplu:
printf("%d\n", gcd(5, 10, -1));
// va printa 5 pentru ca gcd(5, 10) = 5
printf("%d\n", gcd(5, 10, 2, 100, -1));
// va printa 1 pentru ca gcd(5, 10, 2, 100) = 1
printf("%d\n", gcd(500, 10, 25, 75, -1));
// va printa 5 pentru ca gcd(500, 10, 25, 75) = 5
printf("%d\n", gcd(1024, 48, 64, 256, 2048, -1));
// va printa 16 pentru ca gcd(1024, 48, 64, 256, 2048) = 16
- Se dorește implementarea unei funcții polimorfice (generice) de sortare (o funcție care va putea sorta crescător un vector de caractere / întregi / șiruri de caractere / structuri etc). Semnătura funcției este:
// definim tipul de pointer la funcție care va compara 2 elemente (tip necunoscut) si va returna
// un număr care indică relația dintre cele 2 elemente
// ex. să presupunem că cei 2 parametri se numesc first și second
// funcția va returna
// -x, dacă first < second ("first - second < 0")
// 0, dacă first == second ("first - second == 0")
// +x, dacă first > second ("first - second > 0")
// (unde -x/+x semnifică un număr strict negativ/pozitiv)
typedef int (*cmp_t)(const void*, const void*);
// funcția sortează vectorul v descris astfel:
// - nu se cunoaște exact tipul unui element (void *)
// - are num elemente
// - fiecare element are size byte
// - pentru compararea a 2 elemente, se da o funcție cmp de comparare
void sort(void* v, size_t num, size_t size, cmp_t cmp);
Pentru validarea soluției, se va demonstra că funcția sortează corect un vector de caractere (char
), un vector de numere reale (double
) și un vector de șiruri de caractere (char *
).
Exemplu de utilizare pentru un vector cu elemente de tip int
:
int cmp_int(const void* first, const void* second) {
int f = *(int *) first;
int s = *(int *) first;
if (f < s) {
return -1; // f < s
}
if (f > s) {
return +1; // f > s
}
return 0; // f == s
}
// succesiunea de if-uri se putea înlocui cu "return f - s;"
int num_v, *v; // presupunem existența unui vector v cu n elemente întregi
sort(v, n, sizeof(int), cmp_int);
// printează v pentru verificare
[BONUS] 4. Realizați o pereche de funcții cu număr variabil de parametri, numită bprintf()
/ bscanf()
care să permită scrierea / citirea cu format a unui număr de variabile dintr-un fișier binar.
Semnăturile funcțiilor sunt:
int bprintf(FILE*, char *format, ...);
int bscanf(FILE*, char *format, ...);
Funcțiile vor folosi în implementare fwrite()
/ fread()
.
Pentru simplitate presupunem că există doar următorii specificatori:
-
%c
- data de tipchar
-
%d
- data de tipinteger
-
%s
- data de tipstring
-
Convenția folosită este aceeași ca în laboratorul de fișiere binare:
- lungime (
strlen(s) + 1
) - bytes (inclusiv
‘\0’
)
- lungime (
-
Pentru simplitate se va considera că după caracterul '%'
urmează mereu unul din cei 3 specificatori (c/d/s).
Funcționare:
-
bprintf
- dacă caracterul curent din format nu e specificator de format, se va scrie ca atare în fișier
- dacă caracterul curent din format este specificator de format, se va folosi parametrul corespunzător în fișiere (folosind convențiile de mai sus)
-
bscanf
- dacă caracterul curent din format nu e specificator de format, se va ignora, deoarece această funcție așteaptă doar construcții de forma
%<tip>
. - dacă caracterul curent din format este specificator de format, se va citi din fișier în variabila curentă un număr de octeți corespunzător tipului dat de specificator (folosind convențiile de mai sus).
- dacă caracterul curent din format nu e specificator de format, se va ignora, deoarece această funcție așteaptă doar construcții de forma
Mod de implementare:
-
implementați
bprintf
- testați fișierul generat cu
hexdump
- testați fișierul generat cu
-
implementați
bscanf
- testați cu fișierul generat la subpunctul anterior
[BONUS] 5. Se cere implementarea unei funcții polimorfice de căutare binară. Aceasta va urma modelul funcției de sortare de la exercițiul 3.
Pentru o aprofundare mai bună a conceptelor prezentate în laborator, vă recomandăm să parcurgeți materialele din arhiva demo_func_ptr.zip de pe Moodle.