Sunteți pe pagina 1din 39

I.

Elemente de programare avansat n limbajul C


1. 2. 3. 4. 5. 6. 7.

Uniuni Funcii de conversie Tabelul precedenei operatorilor Cmpuri de bii Argumente n linia de comand Argumente de tip pointer Pointeri la funcii

Uniuni
O uniune este o structur n care toi membrii sunt memorai la aceeai adres. Aceasta nseamn c, la un moment dat, ntr-o uniune poate exista doar un singur membru. Tipul de dat union a fost inventat pentru a preveni fragmentarea memoriei n buci de dimensiuni inutilizabile. Tipul de dat union previne fragmentarea prin crearea unei dimensiuni standard pentru anumite date. Spaiul alocat pentru uniune este egal cu dimensiunea elementului maxim al uniunii. Uniunile permit ca o poriune de memorie s fie interpretat ca fiind tipuri de date diferite, ntruct toate aceste tipuri sunt de fapt n aceeai locaie de memorie dar la momente de timp diferite.

Uniuni
Declarare
Declararea unei uniuni. O uniune se declar n acelai mod ca i o structur. Ea conine o list de membri de diferite tipuri. union nume_uniune { tip1 element1; tip2 element2; tip3 element3; } nume_obiect; - Declararea unei variabile uniune se face la fel ca i declararea unei variabile structur. - O uniune nu poate fi iniializat dect cu o valoare de tipul primului su membru.

Uniuni
Utilizare
union int_sau_real { int membru_int; float membru_float; }; union int_sau_real uniune1, uniune2; - Ca i n cazul structurilor, membrii unei uniuni pot fi accesai cu operatorii . i ->. - Totui, spre deosebire de structuri, variabilele uniune1 i uniune2 pot fi tratate, n timpul execuiei programului, fie ca variabile ntregi, fie ca variabile reale n virgul flotant.

Uniuni
Utilizare
De exemplu, dac scriem: uniune1.membru_int = 5; atunci programul vede uniune1 ca fiind un ntreg. Dac apoi vom scrie: uniune1.membru_float = 7.5; valoarea ntreag a variabilei uniune1 se va pierde i aceast variabil va reprezenta n continuare un numr real. Concluzie: o variabil de tip union nu poate avea, la un moment dat, dect un singur tip: tipul membrului activ n acel moment.

Uniuni
Utilizare
O modalitate de a reine ce tip de valoare este memorat n variabila uniune este aceea de utiliza pentru fiecare uniune o variabil fanion. Se recomand ca tipul variabilei fanion s fie un tip enumerare. Exemplu: uniunii int_sau_real i putem asocia tipul enumerare : enum care_membru { INT, FLOAT };

Uniuni
Exemple
Variabilele de tip uniune i de tip enumerare pot fi declarate n pereche: union int_sau_real uniune1; enum care_membru stare_uniune1; Exemplu: switch (stare_uniune1) { case INT: uniune1.membru_int += 5; break; case FLOAT: uniune1.membru_float += 23.222333; break; }

Uniuni
Exemple
n vederea unei mai uoare utilizri, putem grupa aceste variabile ntr-o structur: struct multitip { enum care_membru stare; union int_sau_real numar; }; struct multitip mt; Asignrile membrilor structurii le facem n pereche: mt.stare = INT; mt.numar.membru_int = 5;

Uniuni
Exemple
ntr-o uniune putem grupa tipuri elementare mpreun cu tablouri sau structuri de elemente de dimensiuni mici. union mixt_t { long l; struct { short x; short y; } s; char c[4]; } mixt; Structura definete trei nume care ne permit s accesm acelai grup de 4 octei, ca i tipuri long, short sau char.

Uniuni
Exemple
Modalitile de accesare a datelor sunt: mixt

mixt.l mixt.s.x mixt.s.y

mixt.c[0] mixt.c[1] mixt.c[2] mixt.c[3]

Funcii de conversie
Clasificri i conversii de caractere <ctype.h>
isalpha(c) - returneaz adevrat (valoare nenul) dac c este o liter, respectiv fals (zero) n caz contrar. isupper(c) - returneaz adevrat dac c este o liter mare islower(c) - returneaz adevrat dac c este o liter mic isdigit(c) - returneaz adevrat dac c este o cifr isalnum(c) - returneaz adevrat dac c este liter sau cifr isspace(c) - returneaz adevrat dac c este un caracter de spaiere (spaiu, tab, linie nou). toupper(c) - transform caracterul c din liter mic n liter mare tolower(c) - transform caracterul c din liter mare n liter mic

Funcii de conversie
Conversii de iruri <stdlib.h>
Conversia unui ir de caractere la real, ntreg, respectiv long: double atof(char *s); int atoi(char *s); long atol(char *s); irul de caractere dat ca i parametru - valoare numeric n formatul corespunztor. Dac irul nu poate fi convertit, funciile returneaz val. 0. Conversia invers, din format numeric n ir de caractere. char * itoa(int val, char *s, int baza); char * ltoa(long val, char *s, int baza); Aceste funcii produc n irul s o reprezentare a val n baza.

Funcii de conversie
Conversii de iruri cu format <stdio.h>
int sscanf(char *s, char *format, adresa1, adresa2, ...); int sprintf(char *s, char *format, arg1, arg2, ...); Spre deosebire de scanf i printf, transferul de date se face dintr-un ir de caractere i nu de la intrarea sau ieirea standard. Exemplu: char s[80]="23.5 abc 3"; char sir[10]; int n; float x; sscanf(s, "%f %s %d", &x, sir, &n); sprintf(s, "2*%f=%f ",x, 2*x); n urma execuiei secvenei anterioare, variabilele x, sir i n au valorile: x=23.5 sir=abc i n=3. irul de caractere s va fi n final 2*23.5=47

Tabelul precedenei operatorilor


Nivel

Operatori ( ) (apel funcie) [ ] (indexare) . -> (op. de selecie) + - (op. unari de schimbare de semn) ++ -~ ! (negaie bit cu bit i respectiv logic) (tip) sizeof * (adresare indirect) & (adresa) * / % (op. binari multiplicativi) + - (op. binari aditivi)

Asociativitate stnga dreapta

1 2

3 4

stnga stnga

Tabelul precedenei operatorilor


5 6 7 8 9 10 <> >> <= << (op. deplasare) >= (op. comparaie) == != stnga stnga stnga stnga stnga stnga

& (i pe bii) ^ (sau exclusiv pe bii) | (sau pe bii)

Tabelul precedenei operatorilor


11 12 13 14 += &= 15 && (i logic) || (sau logic) ? : stnga stnga dreapta dreapta

= -= *= /= %= ^= |= >>= <<= ,

stnga

Cmpuri de bii
Printre alte faciliti la nivel sczut, C include i operaii pe bii. n acest sens este fireasc preocuparea de a include i reprezentarea datelor pe bii. Limbajul C conine un mecanism de structurare a datelor la nivel de bit. Se pot aloca, unor cmpuri de structuri sau uniuni, bii individuali sau grupuri de bii dintr-un octet, numite cmpuri de bii care pot fi accesate individual n mod direct. Un cmp de bii este un ir de bii adiaceni coninui ntr-un cuvnt calculator. Cmpurile de bii se grupeaz n structuri. Se pot defini cmpuri de bii doar ca i componente de tip ntreg fr semn ale structurilor. n declaraia cmpului se specific i lungimea acestuia n bii.

Cmpuri de bii
Exemplu: Descrierea datelor meteorologice. Trebuie s se memoreze data (ziua i luna), dac n respectiva zi a plouat, dac a fost soare, sau dac a nins. Se aloc cte un bit pentru ploaie, soare i respectiv ninsoare. Ziua i luna pot fi reprezentate i ele ca i cmpuri de bii, deoarece au valori ntr-un interval redus. struct meteo { unsigned int ziua : 5; unsigned int luna : 4; unsigned int ploaie :1; unsigned int soare :1; unsigned int ninsoare :1; } m;

Cmpuri de bii
Avantaj: cmpurile de bii pot fi accesate n mod direct: m.ziua=15; m.luna=5; m.ploaie=1; m.soare=1; m.ninsoare=0; Utilizarea cmpurilor de bii implic urmtoarele restricii: - acetia trebuie definii n cadrul unei structuri; - nu se pot defini tablouri de cmpuri de bii; - unui cmp de bii nu i se poate aplica operatorul de adres. O structur poate conine att cmpuri de date normale ct i cmpuri de bii.

Argumente n linia de comand


Declaraia general a unei funcii main este : int main(int argc, char **argv); Funcia main returneaz un tip (int) i poate avea argumente. Att rezultatul funciei main ct i argumentele ei intereseaz n condiiile n care se utilizeaz programul ca i o comand lansat din linia de comand a sistemului de operare sau cnd programul este lansat n execuie de un alt program. Valoarea ntreag returnat de main este disponibil pentru programul care a lansat n execuie programul curent. Se obinuiete ca valoarea returnat de un program s fie 0 n caz de terminare corect i o valoare nenul n caz contrar.

Argumente n linia de comand


Pentru ieirea forat din program n caz de erori se recomand funcia exit cu parametrul 1. Spre deosebire de o simpl instruciune return 1; aceast funcie realizeaz n plus i alte operaii, precum nchiderea tuturor fiierelor deschise de program. Funcia main are dou argumente, cu urmtoarele semnificaii: primul argument, argc(argument count), este un ntreg avnd semnificaia de numr al argumentelor date n linia de comand, iar al doilea argument, argv(argument vector), este un vector de iruri de caractere, reprezentnd celelalte argumente din linia de comand. Prin convenie, argv[0] este numele prin care s-a apelat programul. argv[argc] este NULL (sfritul argumentelor)

Argumente n linia de comand


Exemplu:Program care i afieaz arg. primite n linia de comand. Fie urmtorul program, compilat n fiierul cu numele prog: #include <stdio.h> int main(int argc, char **argv) { int i; printf(numele programului:%s\n,argv[0]); if(argc==1) printf(nu are argumente\n); else for (i=1; i<argc; i++) printf(argumentul %d: %s \n", i, argv[ i ]); return 0; /*codul returnat de program*/ }

Argumente n linia de comand


Lansarea n execuie a programului prin linia de comand: prog arg1 arg2 arg3 produce ieirea: numele programului: prog argumentul 1: arg1 argumentul 2: arg2 argumentul 3: arg3 Observaie: Redirectrile de intrare i ieire specificate n linia de comand(vezi cap. Fiiere) nu se consider argumente n linia de comand.

Argumente de tip pointer


Transmiterea argumentelor prin valoare
n C, toate argumentele funciilor sunt transmise prin valoare. Acest lucru nseamn c funcia apelat primete valorile argumentelor sale prin stocare n variabile temporare create n stiv special n acest scop. n acest fel, funcia nu are acces la locaiile de memorie ale variabilelor originale. n C, funcia apelat nu poate modifica direct variabila corespunztoare argumentului transmis din funcia apelant; ea nu poate modifica dect copia temporar. Apelul prin valoare conduce la programe mai compacte, cu mai puine variabile neeseniale, deoarece parametrii pot fi tratai n rutina apelat ca variabile locale, convenabil iniializate ca urmare a apelului.

Argumente de tip pointer


Transmiterea argumentelor prin valoare
Exemplu: O funcie de interschimbare a dou elemente void schimba(int x, int y) { int temp; temp = x; x = y; y = temp; } Apelul schimba(a, b); nu produce efectul dorit. Nu interschimb argumentele a cu b, ci doar copiile lor x i y.

Argumente de tip pointer


Simularea transmiterii prin adres
Cnd este necesar, se poate face ca o funcie s modifice o variabil din funcia apelant. Funcia apelant trebuie s furnizeze adresa variabilei ce va fi accesat (un pointer ctre acea variabil), iar funcia apelat trebuie s declare parametrul ca fiind pointer i s acceseze variabila indirect, prin intermediul acestuia(vezi capitolul despre pointeri). O alt excepie este n cazul tablourilor: cnd numele unui tablou este folosit ca argument,valoarea transmis funciei este adresa locaiei primului element al tabloului. Folosind aceast valoare ca pe o variabil cu indici, funcia poate accesa i poate modifica direct orice element al tabloului.

Argumente de tip pointer


Exemplu
Reluarea exemplului anterior, utiliznd argumente pointeri: void schimba1(int *x, int *y) { int temp; temp = *x; *x = *y; *y = temp; } n acest caz, apelul devine: schimba1(&a, &b); i interschimbarea se realizeaz chiar ntre valorile argumentelor a i b.

Pointeri la funcii
Din punct de vedere al coninutului zonei de memorie indicate, exist urmtoarele categorii de pointeri: pointeri de date, care conin adresa unei variabile; pointeri generici, pointeri void *, pot conine adresa unui obiect oarecare, de orice tip. Se utilizeaz atunci cnd nu se cunoate precis tipul de date care va fi instaniat n mod dinamic la execuie; pointeri de funcii, care conin adresa codului executabil al unei funcii. n C, o funcie nu este o variabil, dar este posibil s se defineasc pointeri la funcii care se comport similar unor variabile: pot fi atribuii, plasai n tablouri, transmii ca argumente altor funcii, etc.

Pointeri la funcii
Exemple de utilizare
Declaraie obinuit de funcie: tip_rez f(.........); Declaraie de pointer la funcie: tip_rez (*pf) (.........); Atribuiri echivalente: pf = f ; pf = &f ; Apeluri echivalente: pf(....); (*pf)(....); int *f(void); //o funcie ce returneaz un pointer la int int (*f)(void); //pointer la o funcie ce returneaz un int Exemplu: un tablou de pointeri de funcii typedef void (*pf)(void); void f1(void); void f2(void); /*...*/ void f10(void); pf ftab[10] = { f1, f2, .. ,f10 }; .int k; .. ftab[k] ( );

Pointeri la funcii
Programul 1
void tab ( double (* f ) (int ) , int j , int i ) { for ( ; j < = i ; j ++) printf ( %d %f \ n , j , ( * f ) ( j ) ) ; } double f1 (int x ) { return 2 * 3.14 * x ; } double fact (int x ) { double f = 1 ; int i ; for ( i = 1 ; i < = x ; i ++) f*= i; return f ; }

Pointeri la funcii
Programul 1
tab ( f1, 1, 10 ) ; tab ( fact, 0, 10 ) ; ----------------------------n C, unica manier de transmitere a unui argument ctre o funcie, este prin valoare. Ea permite ns programatorului s realizeze efectul transmiterii prin adres precum i al transmiterii altor funcii ca argumente. Ultima posibilitate se realizeaz transmind, ca argument, pointerul la funcie. n exemplul de mai sus funcia tab, tabeleaz valorile oricrei funcii reale de un argument ntreg, ntre dou limite precizate. Funcia, mpreun cu limitele se transmit ca argumente.

Pointeri la funcii
Programul 2
Se citesc de pe mediul de intrare date(numele i vrsta) despre un numr oarecare de persoane i se dorete generarea listei persoanelor, ordonat nti n ordine alfabetic i apoi lista ordonat n ordinea cresctoare a vrstei. Se definete tipul structurat persoana: typedef struct { char *nume; int varsta; } persoana; Citirea datelor se face n funcia citeste, declarat astfel: void citeste (int *n, persoana **tab)

Pointeri la funcii
Programul 2
Funcia citete date despre n persoane i construiete un tablou alocat dinamic. Argumentele funciei sunt pointeri pentru a fora transferul lor prin referin (adres): n este numrul de persoane i se citeste n funcie, iar tab este tabloul n care sunt memorate cele n persoane. Tabloul (tabelul) tab se aloc dinamic n cadrul funciei de citire, deci se modific nsi adresa de nceput a tabloului, de aceea, la apel, argumentul este adresa tabelului.

Pointeri la funcii
Programul 2
void citeste (int *n, persoana **tab) { persoana *t; char sir[41]; int i; printf("Introduceti numarul de persoane\n"); scanf("%d", n); /* aloca spatiu pentru n structuri de tip persoana */ if (!(t=(persoana*) malloc ((*n)* sizeof(persoana)))) { printf("Eroare alocare dinamica memorie \n"); exit(1); }

Pointeri la funcii
Programul 2
/* atribuie spatiul alocat tabloului de persoane */ *tab=t; /* citeste datele despre fiecare persoana */ for (i=0; i<*n; i++, t++) { printf("\n nume: "); scanf("%40s", sir); /* aloca memorie pentru nume */ if (!(t->nume=(char *)malloc (strlen(sir)+1))) { printf("Eroare alocare dinamica memorie \n"); exit(1); } strcpy(t->nume, sir); printf("\n varsta: "); scanf("%d", &t->varsta); } }

Pointeri la funcii
Programul 2
Pentru cele 2 sortri cerute ale listei de persoane, ceea ce difer este criteriul de sortare. O sortare se descompune n 3 tipuri de operaii : o comparaie care determin ordinea relativ a 2 elemente, o interschimbare a unei perechi de elemente i un algoritm care efectueaz aceste operaii pn cnd elementele sunt n ordinea dorit. Algoritmul de sortare este independent de operaiile de comparare i interschimbare. Utiliznd funcii diferite de comparare i interschimbare, se pot realiza sortri dupa diverse criterii (numeric, alfabetic). Pentru compararea a 2 persoane se vor utiliza funcii separate ce primesc ca i parametri 2 persoane p1 i p2, i returneaz o valoare ntreag pozitiv dac p1 > p2, o valoare ntreag negativ dac p1< p2, respectiv zero dac ntre cele 2 persoane nu se poate face o ordonare pe baza criteriului de comparaie dat.

Pointeri la funcii
Programul 2
typedef int (*fct_cmp) (persoana , persoana ); void sortare (persoana *sir, int n, fct_cmp f) { int i,j; persoana temp; for (i=0; i<n-1; i++) for (j=i+1; j<n; j++) if ((*f)(sir[ i ], sir[ j ])>0) { temp=sir[ i ]; sir[ i ]=sir[ j ]; sir[ j ]=temp; } } int fc1(persoana p1, persoana p2) { return strcmp(p1.nume, p2.nume); }

Pointeri la funcii
Programul 2
int fc2(persoana p1, persoana p2) { return p1.varsta-p2.varsta; } void main(void) { int n; persoana *tabel=NULL; citeste(&n, &tabel); afiseaza(n, tabel); sortare(tabel, n, fc1); printf("\n Lista in ordine alfabetica:"); afiseaza(n, tabel); sortare(tabel, n, fc2); printf("\n Lista in ordinea varstei:"); afiseaza(n, tabel); }

Pointeri la funcii
Programul 2
Se observ c s-a transmis criteriul de comparare ca argument de tip funcie ctre algoritmul de sortare. n primul rnd se declar fct_cmp ca pointer cu tipul funcie cu rezultatul de tip ntreg i 2 parametri de tip persoana. Funcia sortare are un argument, f, de acest tip fct_cmp. Funcia f este apelat n interiorul corpului funciei sortare, n forma (*f)(sir[i], sir[j]). La apelul funciei sortare, locul acestui parametru formal f este luat de funciile argumente fc1 i respectiv fc2.

S-ar putea să vă placă și