Curs C(Moraru)

download Curs C(Moraru)

of 166

Transcript of Curs C(Moraru)

  • 8/2/2019 Curs C(Moraru)

    1/166

    Florian Moraru

    PROGRAMAREA

    CALCULATOARELOR

    n limbajul C

    2005

    PROGRAMAREA CALCULATOARELOR IN LIMBAJUL C

  • 8/2/2019 Curs C(Moraru)

    2/166

    1. Introducere n programare. Limbajul C

    Algoritmi si programe . . . . . . . . . . . . . . . . . . . . . . . 5Dezvoltarea de programe . . . . . . . . . . . . . . . . . . . . . 7Limbajul de programare C . . . . . . . . . . . . . . . . . . . . 8Elementele componente ale unui program . . . . . . . . 9Conventii lexicale ale limbajului C . . . . . . . . . . . . .10Structura programelor C . . . . . . . . . . . . . . . . . . . . . 12Directive preprocesor . . . . . . . . . . . . . . . . . . . . . . . 13

    2. Date si prelucrri

    Variabile si constante . . . . . . . . . . . . . . . . . . . . . . . 15Tipuri de date n limbajul C . . . . . . . . . . . . . . . . . . 15Constante n limbajul C . . . . . . . . . . . . . . . . . . . . . 17Operatori si expresii aritmetice n C . . . . . . . . . . . 18Erori de reprezentare a numerelor . . . . . . . . . . . . . 20Prelucrri la nivel de bit . . . . . . . . . . . . . . . . . . . . . 22Ordinea de evaluare a expresiilor . . . . . . . . . . . . . . 23Instructiuni expresie n C . . . . . . . . . . . . . . . . . . . . 24Functii standard de intrare-iesire . . . . . . . . . . . . . . 25

    3. Prelucrri conditionate

    Bloc de instructiuni . . . . . . . . . . . . . . . . . . . . . . . . 27Instructiunea "if" . . . . . . . . . . . . . . . . . . . . . . . . . . . 28Operatori de relatie si logici . . . . . . . . . . . . . . . . . . 30Expresii conditionale . . . . . . . . . . . . . . . . . . . . . . . 33Instructiunea "switch" . . . . . . . . . . . . . . . . . . . . . . . 34Macroinstructiunea assert . . . . . . . . . . . . . . . . . . 36

    4. Prelucrri repetitive n C

    Instructiunea "while" . . . . . . . . . . . . . . . . . . . . . . . 37Instructiunea "for" . . . . . . . . . . . . . . . . . . . . . . . . . 38Instructiunea "do" . . . . . . . . . . . . . . . . . . . . . . . . . . 39

  • 8/2/2019 Curs C(Moraru)

    3/166

    Instructiunile "break" si "continue" . . . . . . . . . . . . 40Vectori n limbajul C . . . . . . . . . . . . . . . . . . . . . . . 42Matrice n limbajul C . . . . . . . . . . . . . . . . . . . . . . 43

    5. Programare modular n C

    Importanta functiilor n programare . . . . . . . . . . . . 47Utilizarea functiilor in C . . . . . . . . . . . . . . . . . . . . . 47Definirea de functii in C . . . . . . . . . . . . . . . . . . . . . 49Instructiunea return . . . . . . . . . . . . . . . . . . . . . . . 50Transmiterea de date intre functii . . . . . . . . . . . . . 52Functii recursive . . . . . . . . . . . . . . . . . . . . . . . . . . . .54Biblioteci de functii . . . . . . . . . . . . . . . . . . . . . . . . . 56

    6. Programare structurat n C

    Structuri de control . . . . . . . . . . . . . . . . . . . . . . . . . .Programare structurat n C . . . . . . . . . . . . . . . . . . .Solutii alternative . . . . . . . . . . . . . . . . . . . . . . . . . . .Eficienta programelor . . . . . . . . . . . . . . . . . . . . . . .

    7. Tipuri pointer n C

    Variabile pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . 57

    Operatii cu pointeri la date . . . . . . . . . . . . . . . . . . . 58Vectori si pointeri . . . . . . . . . . . . . . . . . . . . . . . . . . 60Pointeri n functii . . . . . . . . . . . . . . . . . . . . . . . . . . 62Pointeri la functii . . . . . . . . . . . . . . . . . . . . . . . . . . 64

    8. Operatii cu siruri de caractere n C

    Memorarea sirurilor de caractere n C . . . . . . . . . . 67

    Erori uzuale la operatii cu siruri de caractere . . . . . 68Functii standard pentru operatii cu siruri . . . . . . . . 70Definirea de noi functii pe siruri de caractere . . . . 72Extragerea de cuvinte dintr-un text . . . . . . . . . . . . 73Cutarea si nlocuirea de siruri . . . . . . . . . . . . . . . . 75

  • 8/2/2019 Curs C(Moraru)

    4/166

    9. Alocarea dinamica a memoriei n C

    Clase de memorare n C . . . . . . . . . . . . . . . . . . . . . 77

    Functii de alocare si eliberare a memoriei . . . . . . . 78Vectori alocati dinamic . . . . . . . . . . . . . . . . . . . . . .79Vectori de pointeri la date alocate dinamic . . . . . . 80Argumente n linia de comand . . . . . . . . . . . . . . . 82Matrice alocate dinamic . . . . . . . . . . . . . . . . . . . . . 83

    10. Tipuri structur n C

    Definirea de tipuri si variabile structur . . . . . . . . . 85Utilizarea tipurilor structur . . . . . . . . . . . . . . . . . . 86

    Functii cu argumente si rezultat structur . . . . . . . 88Definirea unor noi tipuri de date . . . . . . . . . . . . . . 89Structuri cu continut variabil . . . . . . . . . . . . . . . . . 90Structuri predefinite . . . . . . . . . . . . . . . . . . . . . . . . 92Structuri legate prin pointeri . . . . . . . . . . . . . . . . . . 93

    11. Fisiere de date n C Tipuri de fisiere . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95Functii pentru deschidere si nchidere fisiere . . . . . 96

    Functii de citire-scriere n fisiere text . . . . . . . . . . . 98Functii de citire-scriere cu format . . . . . . . . . . . . . . 99Functii de acces secvential la fisiere binare . . . . . . 100Functii pentru acces direct la date . . . . . . . . . . . . . 102Descriptori de format n functii de intrare-iesire . . 103

    12. Tehnici de programare n C

    Stil de programare . . . . . . . . . . . . . . . . . . . . . . . . . 105Conventii de scriere a programelor . . . . . . . . . . . . .106Constructii idiomatice . . . . . . . . . . . . . . . . . . . . . . 108

    Portabilitatea programelor . . . . . . . . . . . . . . . . . . . .110Erori uzuale n programe C . . . . . . . . . . . . . . . . . . . 111Definirea si utilizarea de functii . . . . . . . . . . . . . . . 113

    13. Tehnici de programare specifice programelor mari

  • 8/2/2019 Curs C(Moraru)

    5/166

    Particularitti ale programelor mari . . . . . . . . . . . . 117Compilri separate si fisiere proiect . . . . . . . . . . . . 118Fisiere antet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120Directive preprocesor utile n programele mari . . . . 121

    Proiectul initial . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123Extinderea programului . . . . . . . . . . . . . . . . . . . . . . 126Imbunttirea programului . . . . . . . . . . . . . . . . . . . . 128Concluzii . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 130

    14. Programare generic n C

    Structuri de date si algoritmi . . . . . . . . . . . . . . . . . . 131Colectii de date . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 132Colectii de date generice . . . . . . . .. . . . . . . . . . . . . . 132

    Functii generice standard n C . . . . . . . . . . . . . . . . . 133Utilizarea de tipuri neprecizate . . . . . . . . . . . . . . . . . 134Utilizarea de pointeri la void . . . . . . . . . . . . . . . . . 136Tipuri abstracte de date . . . . . . . . . . . . . . . . . . . . . . . 138

    15. Diferente ntre limbajele C si C++

    Diferente de sintax . . . . . . . . . . . . . . . . . . . . . . . . . . 141Diferente la functii . . . . . . . . . . . . . . . . . . . . . . . . . . . 142Operatori pentru alocare dinamic . . . . . . . . . . . . . . . 143

    Tipuri referint . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 144Fluxuri de intrare-iesire . . . . . . . . . . . . . . . . . . . . . . . 146Tipuri clas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147Supradefinirea operatorilor . . . . . . . . . . . . . . . . . . . . .149

    1. Introducere n programare. Limbajul C.

    Algoritmi si programe

    Un algoritm este o metod de rezolvare a unei probleme printr-o succesiunede operatii simple. Numrul de operatii este de obicei foarte mare, dar finit.

    Spre deosebire de aplicarea unor formule de calcul, un algoritm contineoperatii executate conditionat, numai pentru anumite date, si operatii repetatede un numr de ori, n functie de datele problemei. Exemplul clasic estealgoritmul lui Euclid pentru determinarea celui mai mare divizor comun a dointregi, care nu poate fi exprimat sub forma unei expresii (formule).

  • 8/2/2019 Curs C(Moraru)

    6/166

    Tipic pentru un algoritm este faptul c anumite operatii se executconditionat (n functie de valorile datelor initiale), iar alte operatii se executn mod repetat (iar numrul de repetri poate depinde de datele initiale).Practic nu exist un program fr decizii si cicluri, deci un program n care sse execute mereu aceleasi operatii, n aceeasi ordine, indiferent de datele

    initiale. Altfel spus, anumite operatii dintr-un program pot s nu fie executatede loc sau s fie executate de un numr de ori, functie de datele initiale.Algoritmii mai simpli pot fi exprimati direct ntr-un limbaj de programare,

    dar pentru un algoritm mai complex se practic descrierea algoritmului fie subform grafic (organigrame sau scheme logice), fie folosind un pseudocod,ca un text intermediar ntre limbajul natural si un limbaj de programare. Un

    pseudocod are reguli mai putine si descrie numai operatiile de prelucrare (nu sivariabilele folosite). Nu exist un pseudocod standardizat sau unanim acceptat.Descrierea unor prelucrri n pseudocod se poate face la diferite niveluri dedetaliere. Exemplu de algoritm pentru afisarea numerelor perfecte mai mici caun numr n dat, descris ntr-un pseudocod:

    repet pentru fiecare ntreg m ntre 2 si ncalcul sum s a divizorilor lui mdac m = s atunci

    scrie m

    sau, la un nivel de detaliere mai aproape de un program n C:

    repet pentru fiecare ntreg m ntre 2 si ns=0repeta pentru fiecare ntreg d ntre 1 si m

    daca d este divizor al lui m atunciaduna d la s

    dac m = s atunciscrie m

    Prin alinierea spre dreapta s-a pus n evident structura de blocuri, adic ceoperatii fac obiectul unei comenzi de repetare sau de selectie (dac). Aceastconventie nu este suficient de precis si poate fi nlocuit cu caracteredelimitator pentru operatiile dintr-un bloc ce face obiectul unei repetri sauunei conditionri. Exemplu:

    repet pentru fiecare ntreg m ntre 2 si n{ s=0

    repeta pentru fiecare ntreg d ntre 1 si m{ daca d este divizor al lui m atunci

    aduna d la s}

    dac m = s atunciscrie m

    }

  • 8/2/2019 Curs C(Moraru)

    7/166

    Un program este o descriere precis si concis a unui algoritm ntr-un limbaj

    de programare. Un program are un caracter general si de aceea are nevoie dedate initiale (diferite de la o utilizare la alta a programului), date care

    particularizeaz programul pentru o situatie concret. De exemplu, un program

    pentru afisarea numerelor perfecte mai mici ca un numr dat n are ca dateinitiale numrul n si ca rezultate numerele perfecte ntre 2 si n. Exemplu:

    #include void main () {int n,m,s,d ; // declaratii de variabileprintf("n="); scanf("%d",&n); // citire datefor (m=2; m

  • 8/2/2019 Curs C(Moraru)

    8/166

    Un program scris ntr-un limbaj independent de masin (C, Pascal, s.a.)trebuie mai nti tradus de ctre un program translator sau compilator.Compilatorul citeste si analizeaz un text surs (de exemplu n limbajul C) si

    produce un modul obiect (scris ntr-un fisier), dac nu s-au gsit erori n textulsurs. Pentru programele mari este uzual ca textul surs s fie format din mai

    multe fisiere surs, care s poat fi scrise, compilate, verificate si modificateseparat de celelalte fisiere surs.Mai multe module obiect, rezultate din compilri separate sunt legate

    mpreun si cu alte module extrase din biblioteci de functii standard ntr-un program executabil de ctre un program numit editor de legturi (Linker sauBuilder). Executia unui program poate pune n evident erori de logic sauchiar erori de programare care au trecut de compilare (mai ales n limbajul C).

    Cauzele erorilor la executie sau unor rezultate gresite nu sunt de obiceievidente din cauz c ele sunt efectul unui numr mare de operatii efectuate decalculator. Pentru descoperirea cauzelor erorilor se poate folosi un programdepanator (Debugger) sau se pot insera intructiuni de afisare a unor rezultate

    intermediare n programul surs, pentru trasarea evolutiei programului.Fazele de modificare (editare) a textului surs, de compilare, linkeditare siexecutie sunt repetate de cte ori este necesar pentru a obtine un programcorect. De fapt, testarea unui program cu diverse date initiale poate arta

    prezenta unor erori si nu absenta erorilor, iar efectuarea tuturor testelor necesare nu este posibil pentru programe mai complexe (pentru. uncompilator sau un editor de texte, de exemplu).

    Programele compilator si linkeditor pot fi apelate n mod linie de comandsau prin selectarea unor optiuni din cadrul unui mediu integrat de dezvoltare a

    programelor (IDE = Integrated Development Environment).Alte programe utilizate n procesul de dezvoltare a unor aplicatii mari sunt:

    - program bibliotecar pentru crearea si modificarea unor biblioteci desubprograme pe baza unor module obiect rezultate din compilare.- program pentru executia unor fisiere de comenzi necesare pentru compilarea

    selectiv si re-crearea programului executabil, dup modificarea unor fisieresurs sau obiect (make).- program de control al versiunilor succesive de fisiere surs.

    Limbajul de programare C.

    Limbajul C s-a impus n principal datorit existentei unui standard care

    contine toate facilittile necesare unui limbaj pentru a putea fi folosit ntr-omare diversitate de aplicatii, fr a fi necesare abateri sau extinderi fat destandard (ca n cazul limbajelor Basic si Pascal). Un exemplu esterecunoasterea posibilittii ca un program s fie format din mai multe fisieresurs si a compilrii lor separate, inclusiv referiri dintr-un fisier n altul. In

  • 8/2/2019 Curs C(Moraru)

    9/166

    plus, exist un numr relativ mare de functii uzuale care fac parte dinstandardul limbajului si care contribuie la portabilitatea programelor C.

    Unii programatori apreciaz faptul c limbajul C permite un control totalasupra operatiilor realizate de procesor si asupra functiilor sistemului deoperare gazd, aproape la fel ca si limbajele de asamblare. Astfel se explic de

    ce majoritatea programelor de sistem si utilitare sunt scrise de mai multi ani nlimbajul C, pe lng multe programe de aplicatii.Limbajul C permite scrierea unor programe foarte compacte, ceea ce poate fi

    un avantaj dar si un dezavantaj, atunci cnd programele devin criptice si greude nteles. Scurtarea programelor C s-a obtinut prin reducerea numrului decuvinte cheie, prin existenta unui numr mare de operatori exprimati prin unulsau prin dou caractere speciale dar si prin posibilitatea de a combina maimulti operatori si expresii ntr-o singur instructiune (acolo unde alte limbajefolosesc mai multe instructiuni pentru a obtine acelasi efect).

    Din perspectiva timpului se poate spune c instructiunile C sunt o reusit alimbajului (si au fost preluate fr modificari de multe alte limbaje : C++, Java

    s.a.) dar functiile de intrare-iesire (printf,scanf) nu au fost un succes (si au fostnlocuite n alte limbaje). Un alt neajuns s-a dovedit a fi necesitateaargumentelor de tip pointer pentru functiile care trebuie s modifice o parte dinargumentele primite si a fost corectat prin argumente de tip referint.

    Utilizarea direct de pointeri (adrese de memorie) de ctre programatorii Ccorespunde lucrului cu adrese de memorie din limbajele de asamblare si

    permite operatii imposibile n alte limbaje, dar n timp s-a dovedit a fi o sursimportant de erori la executie, greu de depistat.

    Au mai fost preluate n limbajele post-C si anumite conventii, cum ar fidiferenta dintre litere mici si litere mari, diferenta dintre caractere individualesi siruri de caractere (si terminarea sirurilor de caractere cu un octet zero),

    operatorii, comentariile s.a.Programarea n C este mai putin sigur ca n alte limbaje ( Pascal, Java) sinecesit mai mult atentie. Limbajul C permite o mare diversitate deconstructii corecte sintactic (care trec de compilare), dar multe din ele trdeazintentiile programatorului si produc erori greu de gsit la executie. Poate celmai bun exemplu este utilizarea gresit a operatorului de atribuire = n loculoperatorului de comparare la egalitate ==. Exemplu:

    if ( a=b) printf (" a = b" \n"); // gresitif ( a==b) printf (" a = b" \n"); // corect

    Elementele componente ale unui program

    Orice limbaj de programare trebuie s contin:

  • 8/2/2019 Curs C(Moraru)

    10/166

    - Instructiuni imperative, prin care se comand executarea anumitor actiuni(prelucrri);- Declaratii de variabile, de functii s.a., necesare compilatorului dar fr efect

    la executie;- Comentarii, ignorate de compilator, destinate oamenilor care citesc

    programe.In plus, limbajul C mai contine si directive preprocesor, pentru compilator.Instructiunile executabile sunt grupate n functii (subprograme). In C trebuie

    s existe cel putin o functie cu numele "main", cu care ncepe executia unui program. Celelalte functii sunt apelate din functia "main" sau din alte functiiactivate direct sau indirect de "main".

    Prin "program" ntelegem uneori toate instructiunile necesare rezolvrii unei probleme, deci o aplicatie complet, dar uneori se ntelege prin "program" doar programul principal (functia "main"). Exemplu de program C minimal, cu ofunctie "main" ce contine o singur instructiune (apelul functiei "printf") si nucontine declaratii:

    #include void main ( ) {

    printf (" main ");}

    Cuvntul void reprezint tipul functiei "main" si arat c aceast functie nutransmite nici un rezultat prin numele su. Parantezele care urmeazcuvntului "main" arat c numele "main" este numele unei functii (si nu estenumele unei variabile), dar o functie fr parametri. Sunt posibile si alte formede definire a functiei "main".

    Acoladele sunt necesare pentru a delimita definitia unei functii, care este un bloc de instructiuni si declaratii.

    Un program descrie procedurile de obtinere a unor rezultate pe baza unor date initiale si foloseste rezultate intermediare. Toate aceste date suntmemorate n variabile ale programului. Pot exista si date constante, ale cror valori nu se pot modifica n cursul executiei. Toate variabilele folosite ntr-un

    program trebuie definite sau declarate prin declaratii ale limbajului. Exemplu:

    #include /* calculeaza si afiseaza media a doua numere */void main ( ) {

    int a,b; float c; /* declaratii de variabile */scanf ("%d%d", &a,&b); /* citire date initiale */c= (a+b) / 2.0; /* instructiune de calcul */printf ("%f\n", c); /* afisare rezultat */

    }

  • 8/2/2019 Curs C(Moraru)

    11/166

    In programul anterior "scanf" si "printf" sunt functii de citire de la tastatur sirespectiv de afisare pe ecran, iar liniile n care ele apar sunt instructiuni pentruapelarea acestor functii. Practic nu exist program fr operatii de citire a unor date si de scriere a unor rezultate. Datele initiale asigur adaptarea unui

    program general la o problem concret iar rezultatele obtinute de program

    trebuie comunicate persoanei care are nevoie de ele.Un program este adresat unui calculator pentru a i se cere efectuarea unor operatii, dar programul trebuie citit si nteles si de ctre oameni; de aceea sefolosesc comentarii care explic de ce se fac anumite operatii (comentariile dinexemplul anterior nu sunt un bun exemplu).

    Initial n limbajul C a fost un singur tip de comentariu, care ncepea cusecventa "/*' si se termina cu secventa "*/". Ulterior s-au adoptat sicomentariile din C++, care ncep cu secventa "//" si se termin la sfrsitul linieicare contine acest comentariu, fiind mai comode pentru programatori.

    Conventii lexicale ale limbajului C

    Instructiunile si declaratiile limbajului C sunt formate din cuvinte cheie alelimbajului, din nume simbolice alese de programator, din constante (numericesi nenumerice) si din operatori formati n general din unul sau dou caracterespeciale.

    Vocabularul limbajului contine litere mari si mici ale alfabetului englez,cifre zecimale si o serie de caractere speciale, care nu sunt nici litere, nici cifre.Printre caracterele speciale mult folosite sunt semne de punctuatie (',' ';'),operatori ('=','+','-','*','/'), paranteze ('(',')',[',']','{'}') s.a.

    In C se face diferent ntre litere mici si litere mari, iar cuvintele cheie ale

    limbajului trebuie scrise cu litere mici. Cuvintele cheie se folosesc n declaratiisi instructiuni si nu pot fi folosite ca nume de variabile sau de functii (suntcuvinte rezervate ale limbajului). Exemple de cuvinte cheie:

    int, float, char, void, unsigned,do, while, for, if, switchstruct, typedef, const, sizeof

    Numele de functii standard (scanf, printf, sqrt, etc.) nu sunt cuvinte cheie, dar nu se recomand utilizarea lor n alte scopuri, ceea ce ar produce schimbareasensului initial, atribuit n toate versiunile limbajului.

    Literele mari se folosesc n numele unor constante simbolice predefinite :

    EOF, M_PI, INT_MAX, INT_MIN

  • 8/2/2019 Curs C(Moraru)

    12/166

    Prin numele de "spatii albe" se nteleg n C mai multe caractere folosite curol de separator:

    blanc ( ), tab ('\t'), linie nou ('\n'),Acolo unde este permis un spatiu alb pot fi folosite oricte spatii albe (de

    obicei blancuri).

    Spatii albe sunt necesare ntre nume simbolice succesive (n declaratii, ntrecuvinte cheie si/sau identificatori) dar pot fi folosite si ntre alti atomi lexicalisuccesivi. Exemple:

    const int * p; typedef unsigned char byte;

    Atomii lexicali ("tokens" n englez) sunt: cuvinte cheie, identificatori (numesimbolice alese de programatori), numere (constante numerice), constante sir (ntre ghilimele), operatori si separatori. Un atom lexical trebuie scris integral

    pe o linie si nu se poate extinde pe mai multe linii. In cadrul unui atom lexicalnu se pot folosi spatii albe (exceptie fac spatiilor dintr-un sir).

    Respectarea acestei reguli poate fi mai dificil n cazul unor siruri constantelungi, dar exist posibilitatea prelungirii unui sir constant de pe o linie pe altafolosind caracterul '\'. Exemple:

    puts (" Inceput sir foarte foarte lung\sfrsit sir"); // spatiile albe se vor afisa

    // solutie alternativaputs ("Inceput sir foarte foarte lung",

    "sfrsit sir"); // spatiile albe nu conteaz

    Spatiile albe se folosesc ntre elementele unei expresii, pentru a usura citirealor, si la nceput de linie pentru alinierea instructiunilor dintr-un bloc.

    Structura programelor C.

    Un program C este compus n general din mai multe functii, dintre carefunctia "main" nu poate lipsi, deoarece cu ea ncepe executia programului.Functiile pot face parte dintr-un singur fisier surs sau din mai multe fisieresurs. Un fisier surs C este un fisier text care contine o succesiune dedeclaratii: definitii de functii si, eventual, declaratii de variabile.

    Functia main poate fi declarat fr argumente sau cu argumente, prin careea primeste date transmise de operator prin linia de comand care lanseaz

    programul n executie. Functia main poate fi declarat si de tip int sau frtip explicit, dar atunci trebuie folosit instructiunea return pentru a preciza uncod de terminare (zero pentru terminare normal, negativ pentru terminare cueroare). Exemplu:

  • 8/2/2019 Curs C(Moraru)

    13/166

    #include int main ( ) {

    printf (" main ");return 0;

    }

    Definitia unei functii C are un antet si un bloc de instructiuni ncadrat deacolade. In interiorul unei functii exist de obicei si alte blocuri de instructiuni,ncadrate de acolade, si care pot contine declaratii de variabile. Antetul continetipul si numele functiei si o list de argumente.

    Exemplu de program cu dou functii:

    #include void clear () { // sterge ecran prin defilare

    int i; // variabila locala functiei clear for (i=0;i

  • 8/2/2019 Curs C(Moraru)

    14/166

    #include void main () { // calcul factorial

    int n; // un ntreg datscanf ("%d", &n); // citeste valoare nlong nf=1; // variabila rezultat

    for (int k=1;k

  • 8/2/2019 Curs C(Moraru)

    15/166

    Numele fisierelor antet pot fi scrise cu litere mici sau cu litere mari nsistemele MS-DOS si MS-Windows, deoarece nu sunt nume proprii limbajuluiC, ci sunt nume specifice sistemului de operare gazd care are alte conventii.

    Parantezele unghiulare sunt delimitatori ai sirului de caractere cereprezint numele fisierului si arat c acest nume trebuie cutat ntr-un

    anumit director (grup de fisiere).Fiecare directiv de compilare trebuie scris pe o linie separat si nu trebuieterminat cu caracterul ;, spre deosebire de instructiuni si declaratii.

    De obicei toate directivele include si define se scriu la nceputul unuifisier surs, n afara functiilor, dar pot fi scrise si ntre functii dac respectregula general c definitia trebuie s precead utilizarea.

    In multe din exemplele care urmeaz vom considera implicite directivele deincludere necesare pentru functiile folosite, fr a le mai scrie (dar ele suntnecesare pentru o compilare fr erori).

    2. Date si prelucrri

    Variabile si constante

    Orice program prelucreaz un numr de date initiale si produce o serie derezultate. In plus, pot fi necesare date de lucru, pentru pstrarea unor valorifolosite n prelucrare, care nu sunt nici date initiale nici rezultate finale.

    Toate aceste date sunt memorate la anumite adrese, dar programatorul serefer la ele prin nume simbolice. Cu exceptia unor date constante, valorileasociate unor nume se modific pe parcursul executiei programului. De aici

    denumirea de variabile pentru numele atribuite datelor memorate. Numele unei variabile ncepe obligatoriu cu o liter si poate fi urmat de literesi cifre. Caracterul special _ (subliniere) este considerat liter, fiind folosit nnumele unor variabile sau constante predefinite (n fisiere de tip H).

    Aplicatiile calculatoarelor sunt diverse, iar limbajele de programare reflectaceast diversitate, prin existenta mai multor tipuri de date: tipuri numericentregi si nentregi, siruri de caractere de lungime variabil s.a.

    Pentru a preciza tipul unei variabile este necesar o definitie ( o declaratie).Cuvintele definitie si declaratie se folosesc uneori cu acelasi sens, pentruvariabile declarate n main sau n alte functii.

    In limbajul C se face diferent ntre notiunile de definitie si declaratie,

    iar diferenta apare la variabile definite ntr-un fisier surs si declarate (sifolosite) ntr-un alt fisier surs. O definitie de variabil aloc memorie pentruacea variabil (n functie de tipul ei), dar o declaratie anunt doar tipul uneivariabile definite n alt parte, pentru a permite compilatorului s verificeutilizarea corect a variabilelor.

  • 8/2/2019 Curs C(Moraru)

    16/166

    O declaratie trebuie s specifice numele variabilei (ales de programator),tipul variabilei si, eventual, alte atribute. In C o variabil poate avea mai multeatribute, care au valori implicite atunci cnd nu sunt specificate explicit (cuexceptia tipului care trebuie declarat explicit).

    Tipuri de date n limbajul C

    Principalele tipuri de date n C sunt:- Tipuri numerice ntregi si nentregi, de diferite lungimi.- Tipuri pointer (adrese de memorie)- Tipuri structurate (derivate): vectori, structuri s.a.

    Pentru functiile fr rezultat s-a introdus cuvntul void , cu sensul fr tip.Tipul unei variabile C poate fi un tip predefinit (recunoscut de compilator) si

    specificat printr-un cuvnt cheie ( int,char,float etc) sau poate fi un nume de tipatribuit de programator (prin declaratii typedef sau struct ). Exemple de

    declaratii de variabile:int a,b;float x,y,z; double d; // tipuri standardstiva s; // tip definit de utilizator

    O definitie de variabil poate fi nsotit de initializarea ei cu o valoare,valoare care poate fi ulterior modificat.

    int suma=0; // declaratie cu initializare

    Asemntor cu tipul variabilelor se declar si tipul functiilor. Exemple:

    int cmmdc(int a, int b); // declaratie (prototip)double sqrt (double x);

    Orice declaratie si orice instructiune trebuie terminat cu caracterul ;, dar un bloc nu trebuie terminat cu ;. Exemplu de definire a unei functii simple:

    double sqr (double x) { return x * x; } // square = ridicare la patrat

    Declaratiile de variabile si de functii pot include si alte atribute: static,const.Datorit reprezentrii interne complet diferite, limbajele de programare

    trateaz diferit numerele ntregi de numerele reale, care pot avea si o partefractionar. Pentru a utiliza eficient memoria si a satisface necesittile uneimultitudini de aplicatii exist n C mai multe tipuri de ntregi si respectiv dereali, ce difer prin memoria alocat si deci prin numrul de cifre ce pot fimemorate si prin domeniul de valori.

  • 8/2/2019 Curs C(Moraru)

    17/166

    Implicit toate numerele ntregi sunt numere cu semn (algebrice), dar prinfolosirea cuvntului cheie unsigned la declararea lor se poate cere interpretareaca numere fr semn.

    Tipurile ntregi sunt: char , short , int , long , long long Tipuri nentregi: float , double , long double (numai cu semn).

    Standardul C din 1999 prevede si tipul boolean _Bool (sau bool ) pe un octet.Reprezentarea intern si numrul de octeti necesari pentru fiecare tip nu suntreglementate de standardul limbajului C, dar limitele fiecrui tip pentru oanumit implementare a limbajului pot fi aflate din fisierul antet limits.h.

    Toate variabilele numerice de un anumit tip se reprezint pe acelasi numr de octeti, iar acest numr limiteaz domeniul de valori (pentru ntregi sinentregi) si precizia numerelor nentregi. Numrul de octeti ocupati de un tipde date sau de o variabil se poate obtine cu operatorul sizeof .

    De exemplu, n Borland C , tipul int ocup 2 octeti, tipul long ocup 4 octetiiar domeniul de valori este ntre -32768 si 32767 pentru int si de cca. 10 cifrezecimale pentru tipul long . Depsirile la operatii cu ntregi de orice lungime nu

    sunt semnalate desi rezultatele sunt incorecte n caz de depsire. Exemplu:short int a=15000, b=20000, c;c=a+b; // depasire ! c > 32767

    Reprezentarea numerelor reale n diferite versiuni ale limbajului C este maiuniform deoarece urmeaz un standard IEEE de reprezentare n virgulmobil. Pentru tipul float domeniul de valori este ntre 10E-38 si 10E+38 iar

    precizia este de 6 cifre zecimale exacte. Pentru tipul double domeniul de valorieste ntre 10E-308 si 10E+308 iar precizia este de 15 cifre zecimale.

    De observat c, la afisarea valorilor unor variabile reale se pot cere maimulte cifre zecimale dect pot fi memorate, dar cifrele suplimentare nu suntcorecte. Se pot cere, prin formatul de afisare, si mai putine cifre zecimale dectsunt memorate n calculator.

    Constante n limbajul C

    Tipul constantelor C rezult din forma lor de scriere, dup cum urmeaz:- Constantele ntregi sunt siruri de cifre zecimale, eventual precedate de un

    semn (-, +). Exemple :

    0 , 11 , -205 , 12345

    - Constantele care contin, pe lng cifre si semn, un punct zecimal si/sau literaE (sau e) sunt de tipul double . Exemple:

  • 8/2/2019 Curs C(Moraru)

    18/166

    7.0 , -2. , 0.5 , .25 , 3e10 , 0.12345678E-14

    - Constantele care contin un exponent precedat de litera E (e) sau contin un punct zecimal dar sunt urmate de litera F (f) sunt de tipul float . Exemple:

    1.0f, -2.F , 5e10f , 7.5 E-14F

    - Constantele formate dintr-un caracter ntre apostrofuri sunt de tip char .Exemple:

    0, a , A, +, -, \n , \t,

    Constantele caracter se pot scrie si sub forma unei secvente ce ncepe cu \,urmat de o liter (\n = new line , \t =tab , \b = backspace etc), sau de codulnumeric al caracterului n octal sau n hexazecimal (\012 = \0x0a = 10 estecodul pentru caracterul de trecere la linie nou \n).- Constantele ntregi n baza 16 trebuie precedate de precedate de sufixul "0x".

    Cifrele hexazecimale sunt 0..9,A,B,C,D,E,F sau 0..9,a,b,c,d,e,f. Exemple

    0x0A, 0x7FFFF, 0x2c, 0xef

    - Constantele formate din unul sau mai multe caractere ntre ghilimele suntconstante sir de caractere . Exemple:

    a , alfa , -1234 , ####

    Orice constant poate primi un nume, devenind o constant simbolic.Utilizarea de constante simbolice n programe are mai multe avantaje:

    - Permit modificarea mai simpl si mai sigur a unei constante care apare nmai multe locuri.

    - Permite ntelegerea mai usoar a programelor, cu mai putine comentarii.Exemplu de nume pentru constanta ce reprezint dimensiunea maxim aunor vectori :

    #define NMAX 1000 // dimensiune maximavoid main () {

    int n, x[NMAX], y[NMAX];printf ("n= "); scanf ("%d" &n);assert ( n < NMAX);... // citire elemente vectori

    Declaratia enum permite definirea mai multor constante ntregi cu valori

    succesive sau nu, simultan cu definirea unui nou tip de date. Exemple:enum color {BLACK, BLUE, RED}; //BLACK=0, BLUE=1, RED=2enum color {RED=5, WHITE=15, BLUE=1};

  • 8/2/2019 Curs C(Moraru)

    19/166

  • 8/2/2019 Curs C(Moraru)

    20/166

    int g,m; // nr intreg de grade, minutegrd = 180*rad/M_PI; // nr de grade (neintreg)g=grd; // sau g= (int)grd;min=60*(grd-(float)g); // min=60*(grd-g)m=min; // sau m= (int)min;

    Conversiile automate pot fi o surs de erori (la executie) si de aceea se prefer conversii explicite prin operatorul de conversie (cast= fortare tip),care are forma (tip) si se aplica unei expresii. Exemple:

    float x; int a,b;x= (float)a/b; // ctul exactfloat x; int k;

    k= (int)(x+0.5); // rotunjire x la intregul apropiat

    Conversia prin operatorul (tip) se poate face ntre orice tipuri aritmetice sauntre tipuri pointer. Pentru tipurile aritmetice se poate folosi si atribuirea pentrumodificarea tipului (si valorii) unor variabile sau functii. Exemplu:

    float x; int k;x= x+0.5; k=x; // rotunjire x

    In limbajul C exist mai multi operatori care reunesc un calcul sau alt

    prelucrare cu o atribuire:+= -= *= /= %=

    Urmtoarele expresii sunt echivalente ( v = o variabil, e = o expresie):

    v += e v = v + e

    Operatorii unari de incrementare (++) si decrementare (--) au ca efectmrirea si respectiv micsorarea cu 1 a valorii operandului numeric:

    ++x adun 1 la x nainte de se folosi valoarea variabilei xx++ adun 1 la x dup ce se foloseste valoarea variabilei xOperatorii ++ si -- se pot aplica oricrei expresii numerice (ntregi sau reale)

    si variabilelor pointer. In general acesti operatori realizeaz o prescurtare aatribuirilor de forma x=x+1 sau x=x-1, dar pot exista si diferente ntre celedou forme de mrire sau diminuare a unei valori.

    Expresiile urmtoare au rezultat diferit: a= ++b a=b++

    Urmtoarele expresii au acelasi efect dac x este o variabil :x=x+1 x += 1 ++x x++

  • 8/2/2019 Curs C(Moraru)

    21/166

    Prelucrri la nivel de bit

    O variabil este un nume pentru o zon de memorie, care contine un sir decifre binare (biti). Operatorii aritmetici interpreteaz sirurile de biti ca numere

    binare cu semn. Anumite aplicatii dau alte interpretri sirurilor de biti si

    necesit operatii la nivel de bit sau grupuri de biti care nu sunt multiplii de 8.Operatorii la nivel de bit din C sunt aplicabili numai unor operanzi de tipntreg. Putem deosebi dou categorii de operatori pe biti:- Operatori logici bit cu bit- Operatori pentru deplasare cu un numr de biti

    Operatorul unar '~' face o inversare logic bit cu bit a operandului si poate fiutil n crearea unor configuratii binare cu multi biti egali cu 1, pe oricelungime. Exemplu:

    ~0x8000 // este 0x7FFF

    Operatorul pentru produs logic bit cu bit '&' se foloseste pentru fortarea pe

    zero a unor biti selectati printr-o masc si pentru extragerea unor grupuri de biti dintr-un sir de biti. Pentru a extrage cei 4 biti din dreapta (mai putinisemnificativi) dintr-un octet memorat n variabila 'c' vom scrie:

    c & 0x0F

    unde constanta hexa 0x0F reprezint un octet cu primii 4 biti zero si ultimii 4 biti egali cu 1.

    Operatorul pentru sum logic bit cu bit '|' se foloseste pentru a forta selectiv pe 1 anumiti biti si pentru a reuni dou configuratii binare ntr-un singur sir de biti. Exemplu:

    a | 0x8000 // pune semn minus la numarul din a

    Operatorul pentru sum modulo 2 ("sau exclusiv") '^' poate fi folosit pentruinversarea logic sau pentru anularea unei configuratii binare.

    Operatorii pentru deplasare stnga '' se folosesc pentrumodificarea unor configuratii binare. Pentru numere fr semn au acelasi efectcu nmultirea si respectiv mprtirea cu puteri ale lui 2. Exemplu:

    a >>10 // echivalent cu a / 1024

    Functia urmtoare afiseaz prin 4 cifre hexa un sir de 16 biti primit ca parametru :

    void printHex ( unsigned short h) {unsigned short i, ch;for (i=1;i12);

  • 8/2/2019 Curs C(Moraru)

    22/166

    }}

    Ordinea de evaluare a expresiilor

    Limbajul C are un numr mare de operatori care pot fi combinati n expresiicomplexe. Ordinea n care actioneaz acesti operatori ntr-o expresie este datn urmtorul tabel de prioritti:

    Prioritate Operator 1 Paranteze si acces la structuri: ( ) [ ] -> .2 Operatori unari: ! ~ + - ++ -- & * sizeof (tip)3 Inmultire, mprtire, rest : * / %4 Adunare si scdere: + -5 Deplasri: >6 Relatii: >=7 Egalitate: == !=8 Produs logic bit cu bit: &9 Sau exclusiv bit cu bit: ^

    10 Sum logic bit cu bit: |11 Produs logic: &&12 Sum logic: ||13 Operator conditional: ? :14 Atribuiri: = *= /= %= += -= &= ^= |= =15 Operator virgula: ,

    Ignorarea priorittii operatorilor conduce la erori de calcul detectabile numaila executie, prin depanarea programului.

    Dou recomandri utile sunt evitarea expresiilor complexe (prin folosirea devariabile pentru rezultatul unor subexpresii) si utilizarea de paranteze pentruspecificarea ordinii de calcul (chiar si atunci cnd ele nu sunt necesare).

    Operatorii de aceeasi prioritate se evalueaz n general de la stnga ladreapta, cu exceptia unor operatori care actioneaz de la dreapta la stnga(atribuire, operatorii unari si cel conditional).

    Operatorii unari actioneaz naintea operatorilor binari. Intre operatorii binari sunt de retinut cteva observatii:

    - Operatorul de atribuire simpl si operatorii de atribuire combinat cu alteoperatii au prioritate foarte mic (doar operatorul virgul are prioritate maimic); de aceea pot fi necesare paranteze la subexpresii de atribuire dincomponenta altor expresii. Exemple n care atribuirea trebuie efectuat naintede a compara valoarea atribuit:

    while ( (c =getchar()) != EOF) ...if ( (d= b*b-4*a*c) < 0) ...

    - Operatorii aritmetici au prioritate naintea celorlalti operatori binari, iar operatorii de relatie au prioritate fat de operatorii logici. Exemplu:

  • 8/2/2019 Curs C(Moraru)

    23/166

    (a

  • 8/2/2019 Curs C(Moraru)

    24/166

    x = 1/2*(a+b); // x=0, corect: x=(a+b)/2 ;int x = sqrt(2); // x=1

    - Erori de depsire a valorilor maxime absolute la operatii cu ntregi, chiar sin valori intermediare (n subexpresii). Un exemplu este calculul numrului desecunde fat de ora zero pe baza a trei ntregi ce reprezint ora, minutul sisecunda. Acest numr poate depsi cel mai mare ntreg reprezentabil pe 16 biti( short sau int n unele implementri). Exemplu:

    #include // interval intre doua momente de timp

    void main () {int h1,m1,s1, h2,m2,s2, h,m,s;long t1,t2,t; int r;printf("timp1="); scanf("%d%d%d",&h1,&m1,&s1);printf("timp2="); scanf("%d%d%d",&h2,&m2,&s2);t1= 3600L*h1 + 60*m1 + s1; // poate depasi daca t1 intt2= 3600L*h2 + 60*m2 + s2; // poate depasi daca t2 intt=t1-t2;h= t/3600; r=t%3600;m=r/60; s=r%60;printf ("%02d:%02d:%02d \n",h,m,s);

    }

    Nu exist nici o metod general de a detecta depsirile la operatii cu ntregi pe un numr mare de calcule, dar n cazuri simple putem s verificmrezultatul unei operatii unde suspectm o depsire. Exemplu:

    void main (){

    int a,b,c;scanf ("%d%d",&a,&b);c=a*b;if ( c/a != b)

    printf ("depasire !\n");else

    printf ("%d \n",c);}

    O alternativ este prevenirea aceste depsiri. Exemplu:

    if (MAXINT /a < b) // MAXINT definit in printf ("depasire ! \n");

    elseprintf ("%d \n", a*b);

  • 8/2/2019 Curs C(Moraru)

    25/166

    - Erori la adunarea sau scderea a dou numere reale cu valori foarte diferite prin aducerea lor la acelasi exponent nainte de operatie. Se poate pierde din precizia numrului mai mic sau chiar ca acesta s fie asimilat cu zero.

    - Erori de rotunjire a numerelor reale datorit numrului limitat de cifre pentru mantis. Mrimea acestor erori depinde de tipul numerelor ( float sau

    double sau long double ), de tipul, numrul si ordinea operatiilor aritmetice.Pierderea de precizie este mai mare la mprtire si de aceea se recomand caaceste operatii s se efectueze ct mai trziu ntr-o secvent de operatii. Deci:expresia (a*b)/c este preferabil expresiei (a/c)*b.

    Erorile de rotunjire se pot cumula pe un numr mare de operatii, astfel c nanumite metode iterative cresterea numrului de pasi (de iteratii) peste unanumit prag nu mai reduce erorile de calcul intrinseci metodei, deoareceerorile de reprezentare nsumate au o influent prea mare asupra rezultatelor.Un exemplu este calculul valorii unor functii ca sum a unei serii de puteri cumulti termeni; ridicarea la putere si factorialul au o crestere rapid pentrunumere supraunitare iar numerele subunitare ridicate la putere pot produce

    valori nesemnificative.In general, precizia rezultatelor numerice este determinat de mai multifactori: precizia datelor initiale (numr de zecimale), numrul si feluloperatiilor, erori intrinseci metodei de calcul (pentru metode de aproximatiisuccesive), tipul variabilelor folosite.

    Functii standard de intrare-iesire

    Functiile scanf si printf permit citirea cu format (ales de programator) siscrierea cu format pentru orice tip de date. Pentru numere se face o conversie

    automat ntre formatul extern (sir de caractere cifre zecimale) si formatulintern (binar virgul fix sau virgul mobil). Primul argument al functiilor scanf si printf este un sir de caractere ce poate contine:- specificatori de format, adic secvente de caractere care ncep cu %.- alte caractere, afisate ca atare de printf

    Celelate argumente sunt variabile (la scanf) sau expresii (la printf) ncare se citesc valori (scanf) sau ale cror valori se scriu (printf). Exemplede utilizare printf:

    printf ("\n"); // trecere la o noua linieprintf ("\n Eroare \n"); // scrie un sir constantprintf ("%d \n",a); // scrie un intreg si schimba liniaprintf ("a=%d b=%d \n", a, b); // scrie doi intregi

    printf ( %2d grade %2d min %2d sec \n, g,m,s);

    Argumentele functiei scanf sunt de tip pointer si contin adresele unde sememoreaz valorile citite. De obicei aceste adrese se obtin cu operatorul deadresare (&) aplicat variabilei care primeste valoarea citit. Exemple:

  • 8/2/2019 Curs C(Moraru)

    26/166

    scanf("%d",&n); // citeste un ntreg n variabila nscanf("%d%d", &a,&b); // citeste doi ntregi in a si bscanf (%f, &rad); // citeste un numar real in rad

    De retinut diferenta de utilizare a functiilor scanf si printf. Exemplu:

    scanf("%d%d", &a,&b); // citeste numere in a si bprintf("%d %d", a,b); // scrie valorile din a si b

    Numerele citite cu scanf pot fi introduse pe linii separate sau n aceeasilinie dar separate prin spatii albe sau caractere Tab. Intre numere succesive

    pot fi oricte caractere separator (\n,\t, ). Un numr se termin la primulcaracter care nu poate apare ntr-un numr .

    Functiile scanf si printf folosesc notiunea de cmp (field): un cmpcontine o valoare si este separat de alte cmpuri prin spatii albe, inclusivterminator de linie (\n) ca spatiu alb. Fiecare descriptor de format poate

    contine mrimea cmpului, ca numr ntreg. Aceast mrime se foloseste maiales la afisare, pentru afisare numere pe coloane, aliniate la dreapta. In lipsaacestei informatii mrimea cmpului rezult din valoarea afisat. Exemple:

    printf("%d %d",a,b); // 2 campuri separate prin blancprintf("%8d8%d",a,b); // 2 cmpuri de cate 8 caractere

    Desi sunt permise si alte caractere n sirul cu rol de format din scanf serecomand pentru nceput s nu se foloseasc ntre specificatorii de formatdect blancuri (pentru a usura ntelegerea formatului de citire). Chiar si spatiiletrebuie folosite cu atentie n sirul format din scanf. Exemplu de citire care

    poate crea probleme la executie din cauza blancului din format:scanf("%d ",&a); // corect este scanf (%d,&a);printf("%d \n",a);

    Functia scanf nu poate afisa nimic, iar pentru a precede introducerea dedate de un mesaj trebuie folosit secventa printf, scanf. Exemplu:

    printf (n= ); scanf (%d, &n);

    Descriptorii de format admisi n functiile scanf si printf sunt:

    %c caractere individuale (cod ASCII)%s sir de caractere ASCII%p pointeri la void %d, %i numere ntregi cu semn n baza 10 (zecimale)%u numere ntregi fr semn n baza 10%x,%X numere ntregi fr semn n baza 16 (hexa)

  • 8/2/2019 Curs C(Moraru)

    27/166

    %ld,%li numere ntregi lungi%f numere reale, cu parte ntreag si fractionar%e,%E numere reale cu mantis si exponent (al lui 10)%g numere reale n format %f sau %e, functie de valoare%lf,%le,%lg numere reale n precizie dubl ( double )%Lf,%Le,%Lg numere reale de tip long double

    Dac nu se precizeaz mrimea cmpului si numrul de cifre de la parteafractionar pentru numere, atunci functia printf alege automat aceste valori:

    - dimensiunea cmpului rezult din numrul de caractere necesar pentruafisarea cifrelor, semnului si altor caractere cerute de format;- numrul de cifre de la partea fractionar este 6 indiferent dac numerele sunt

    de tip float sau double sau long double , dac nu este precizat explicit.Se poate preciza numai mrimea cmpului sau numai numrul de cifre la

    partea fractionar. Exemple:

    float a=1.; double b=0.0002; long double c=7.5; float d=-12.34;printf ("%.0f %20lf %20.10Lf %f \n", a, b, c, d);

    Se poate specifica dimensiunea cmpului n care se afiseaz o valoare, ceeace este util la scrierea mai multor valori n coloane. Dac valoarea de afisatnecesit mai putine caractere dect este mrimea cmpului, atunci aceastvaloare este aliniat la dreapta n cmpul respectiv. Exemplu:

    int a=203, b= 5, c=16;printf (%10d \n %10d \n %10d \n,a,b,c);

    Secventa anterioar va scrie trei linii, iar numerele afisate vor apare ntr-ocoloan cu cifrele de aceeasi pondere aliniate unele sub altele.

    Formatul cu exponent (%e) este util pentru numere foarte mari, foarte micisau despre ale cror valori nu se stie nimic. Numrul este scris cu o mantisfractionar (ntre 0 si 10) si un exponent al lui 10, dup litera E (e).

    La formatul %g printf alege ntre formatul %f sau %e n functie deordinul de mrime al numrului afisat: pentru numere foarte mari sau foartemici formatul cu exponent, iar pentru celelalte formatul cu parte ntreag si

    parte fractionar.Intre caracterul % si literele care desemneaz tipul valorilor citite/scrise

    mai pot apare, n ordine :a) un caracter ce exprim anumite optiuni de scriere:

    - (minus) aliniere la stnga n cmpul de lungime specificat

    + (plus) se afiseaz si semnul + pentru numere pozitive0 numerele se completeaz la stnga cu zerouri pe lungimea w# form alternativ de scriere pentru numere (detalii n Help)

    b) un numr ntreg w ce arat lungimea cmpului pe care se scrie o valoare,

  • 8/2/2019 Curs C(Moraru)

    28/166

    sau caracterul * dac lungimea cmpului se d ntr-o variabil de tip int care precede variabila a crei valoare se scrie.

    c) punct urmat de un ntreg, care arat precizia (numr de cifre dup punctulzecimal) cu care se scriu numerele nentregi.d) una din literele h, l sau L care modific lungimea tipului numeric.

    Exemplu de utilizare a optiunii 0 pentru a scrie ntotdeauna dou cifre,chiar si pentru numere de o singur cifr :

    int ora=9, min=7, sec=30;printf ("%02d:%02d:%02d\n",ora, min, sec); // scrie 09:07:30

    Exemplu de utilizare a optiunii - pentru aliniere siruri la stnga:

    char a[ ] = "unu", b[ ] ="cinci", c[ ]= "sapte" ;printf (" %-10s \n %-10s \n %-10s \n", a, b, c);

    In general trebuie s existe o concordant ntre numrul si tipul variabilelor

    si formatul de citire sau scriere din functiile scanf si printf, dar aceastconcordant nu poate fi verificat de compilator si nici nu este semnalat caeroare la executie, dar se manifest prin falsificarea valorilor citite sau scrise.Exemplu:

    int m=3; float x=7.8;printf (%f %d \n, m, x); // scrie doua valori dar nu scrie 3 si 7.8printf (%d %d %d \n, m); // scrie 3 numere

    O exceptie notabil de la aceast regul general este posibilitatea de a citisau scrie corect numere de tip double cu formatul %f (pentru tipul float ), dar nu si numere de tip long double (din cauza diferentelor de reprezentare interna exponentului).

    3. Prelucrri conditionate

    Blocul de instructiuni

    Instructiunile expresie dintr-un program sunt executate n ordinea aparitieilor n program.

  • 8/2/2019 Curs C(Moraru)

    29/166

    In limbajul C un bloc grupeaz mai multe instructiuni (si declaratii) ntreacolade. Exemple:

    { t=a; a=b; b=t;} // schimba a si b ntre ele{ int t; t=a; a=b; b=t;} // schimba a si b prin t

    Uneori un bloc contine doar o singur instructiune. Un bloc nu trebuieterminat cu ;.

    Acoladele nu modific ordinea de executie, dar permit tratarea unui grup deinstructiuni ca o singur instructiune de ctre alte instructiuni de control ( if ,while, do, for s.a). Instructiunile de control au ca obiect, prin definitie, osingur instructiune (care se repet sau care este selectat pentru executie).Pentru a extinde domeniul de actiune al acestor instructiuni la un grup deoperatii se folosesc acolade pentru gruparea instructiunilor vizate de comenzileif, for, while, do, switch . Exemplu:

    scanf (%d, &n);if ( n > MAX) {

    printf (Eroare in date: n > %d \n,MAX);return;

    }

    Instructiunea "if"

    Instructiunea introdus prin cuvntul cheie if exprim o decizie binar si poate avea dou forme: o form fr cuvntul else si o form cu else :

    if (e) i // fara alternativa elseif (e) i1 else I2 // cu alternativa else

    In descrierea unor structuri de control vom folosi urmtoarele notatii:e, e1, e2,... expresii (sau conditii)i, i1, i2 instructiuni sau blocuri

    Instructiunile i, i1,i2 pot fi:- O instructiune simpl, terminat cu ';' (terminatorul face parte din

    instructiune).- O instructiune compus, ntre acolade.- O alt instructiune de control.Expresia din if este de obicei o expresie de relatie sau o expresie logic, dar

    poate fi orice expresie cu rezultat numeric.Valoarea expresiei dintre paranteze se compar cu zero, iar instructiunea

    care urmeaz se va executa numai atunci cnd expresia are o valoare nenul.In general expresia din instructiunea if reprezint o conditie, care poate fi

  • 8/2/2019 Curs C(Moraru)

    30/166

    adevarat (valoare nenul) sau fals (valoare nul). De obicei expresia este oexpresie de relatie (o comparatie de valori numerice) sau o expresie logic carecombin mai multe relatii ntr-o conditie compus.

    Exemplu de instructiune if fr alternativ else :

    if ( sec >= 60) // verifica numar de secundeerr=1;

    De multe ori se alege o secvent de operatii (instructiuni) si trebuie folositeacoladele pentru precizarea acestei secvente. Exemplu:

    // inversarea valorilor lui a si b daca a>bif ( a > b) {

    t=a; a=b; b=t;}

    De observat c pentru comparatia la diferit de zero nu trebuie neaprat

    folosit operatorul de inegalitate (!=), desi folosirea lui poate face programulmai clar:

    if (d) return; // if (d != 0) return;

    Forma instructiunii if care foloseste cuvntul cheie else permite alegereadintre dou secvente de operatii posibile, n functie de o conditie. Exemplu:

    // determinare minim dintre a si bif ( a < b)

    min=a;else

    min=b; Instructiunile precedate de if si else sunt de obicei scrise pe liniile urmtoare

    si sunt deplasate spre dreapta, pentru a pune n evident structurile si modul deasociere ntre if si else . Acest mod de scriere permite citirea corect a unor cascade de decizii. Exemplu:

    // determinare tip triunghi cu laturile a,b,cif ( a==b && b==c)

    printf ("echilateral \n");else

    if ( a==b || b==c || a==c)

    printf ("isoscel \n");elseprintf ("oarecare \n");

  • 8/2/2019 Curs C(Moraru)

    31/166

    O problem de interpretare poate apare n cazul a dou (sau mai multe)instructiuni if incluse, dintre care unele au alternativa else , iar altele nu contin

    pe else . Regula de interpretare este aceea c else este asociat cu cel maiapropiat if fr else (dinaintea lui). Exemplu:

    if ( a == b )if (b == c)printf ("a==b==c \n");

    elseprintf (" a==b si b!=c \n");

    Pentru a programa o instructiune if cu else care contine un if fr else avemmai multe posibilitti:

    if ( e1) { if ( ! e1)if (e2) i2

    i1 else if (e2)} i1else

    i2

    Exemplu dintr-un program care inverseaz pe a cu b daca a0 && b>0) {if ( a

  • 8/2/2019 Curs C(Moraru)

    32/166

    Operatorii de relatie se folosesc de obicei ntre operanzi numerici si, mai rar,ntre variabile pointer. In limbajul C operatorii de comparatie la egalitate siinegalitate arat mai deosebit:

    == comparatie la egalitate (identitate)!= comparatie la inegalitate

    Operatorii pentru alte relatii au forma din matematic si din alte limbaje:< , , >=

    Toti operatorii de relatie au rezultat zero (0) dac relatia nu este adevrat siunu (1) dac relatia este adevrat.

    Comparatia la egalitate de numere nentregi este nesigur si trebuie evitat,din cauza erorilor de reprezentare intern a numerelor reale. Se va comparamai bine diferenta celor dou valori cu un epsilon foarte mic. Exemplu:

    // daca punctul (x0,y0) se afla pe dreapta y=a*x+bif ( fabs (y0- (a*x0+b)) < 1e-5) ... // in loc de if ( y0 ==a*x0+b) ...

    Operatorii logici se folosesc de obicei ntre expresii de relatie pentru aexprima conditii compuse din dou sau mai multe relatii. Operatorii logici aurezultat 1 sau 0 dup cum rezultatul expresiei logice este adevrat sau fals.Operatorii logici binari n C sunt:

    && si-logic ( a && b =1 dac si a==1 si b==1)|| sau-logic ( a || b =1 dac sau a==1 sau b==1 sau a==b==1)

    Operatorul && se foloseste pentru a verifica ndeplinirea simultan a dousau mai multe conditii, iar operatorul || se foloseste pentru a verifica dac cel

    putin una dintre dou (sau mai multe) conditii este adevrat.Exemple de conditii compuse:

    if ( x >= a && x b)printf ("x in afara interv. [a,b] \n");

    De observat c efectuarea mai multor verificri poate fi exprimat uneori fie prin mai multe instructiuni if , fie printr-o singur instructiune if cu expresielogic. Exemplu:

    if ( x >= a)

  • 8/2/2019 Curs C(Moraru)

    33/166

    if ( x = a)if ( x =0 && b >=0 // echiv. cu !(a=a && x b+c || b > a+c || c > a+b )

    printf (" a,b,c nu pot forma un triunghi \n");

    Intr-o expresie logic evaluarea operanzilor (expresii de relatie) se face de lastnga la dreapta; din acest motiv ordinea operanzilor ntr-o expresie logic

    poate fi uneori important si poate conduce la erori de programare. Exemplu:

  • 8/2/2019 Curs C(Moraru)

    34/166

    void main () {int k, b=9, a[]={1,2,3,4};k=0;while ( b != a[k] && k

  • 8/2/2019 Curs C(Moraru)

    35/166

    // functie pentru minim intre doua variabileint minim (int a, int b) {

    return a=60) {

    s=s-60; m1++;}m=m1+m2; // minuteif (m >=60) {

    m=m-60; h1++;}h=h1+h2; // ore

    Solutia fr instructiuni if este dat mai jos:x=s1+s2; s= x%60; // secundex=m1+m2 + x/60; m=x%/60; // minuteh=h1+h2+x/60; // ore

    Instructiunea "switch"

    Selectia multipl, dintre mai multe cazuri posibile, se poate face cu maimulte instructiuni if incluse unele n altele sau cu instructiunea switch .Instructiunea switch face o enumerare a cazurilor posibile (fiecare precedat decuvntul cheie "case") ntre acolade si foloseste o expresie de selectie, curezultat ntreg. Forma general este:

    switch (e) { // e= expresie de selectiecase c1: s1; // cazul c1case c2: s2; // cazul c2. . . // alte cazuri

    default: s; // cazul implicit ( poate lipsi)}

    unde: c1,c2,.. sunt constante sau expresii constante ntregi (inclusiv char)s, s1, s2 ... sunt secvente de instructiuni (cu sau fr acolade)

  • 8/2/2019 Curs C(Moraru)

    36/166

    Dac secventele de instructiuni nu se termin cu break , atunci secventaechivalent cu instructiuni if este urmtoarea:

    if (e==c1) { s1}if (e==c2) {s2}. . .else {s} // daca e difera de c1,c2,...

    Deseori cazurile enumerate se exclud reciproc si fiecare secvent deinstructiuni se termin cu break , pentru ca dup selectia unui caz s se sardup blocul switch . Exemplu:

    swich( c=getchar()) { // c poate fi +,-,*,/case ' + ': c=a + b; break;case ' - ': c=a - b; break;case ' * ': c=a * b; break;case ' / ': c=a / b; break;default: error(); // tratare erori

    }

    Prin definitia instructiunii switch dup executarea instructiunilor unui caz setrece la cazul imediat urmtor (n lipsa unei instructiuni break ). Aceastinterpretare permite ca mai multe cazuri s foloseasc n comun aceleasioperatii (partial sau n totalitate). Exemple:

    // determinare semn numar din primul caracter cititswitch (c=getchar()) { // c este semn sau cifra

    case - : semn=1; c=getchar(); break;case +: c=getchar(); // si semn=0default: semn=0; // semn implicit

    }

    // determina nr de zile dintr-o lun a unui an nebisectswitch (luna) {case 2: zile=28; break; // februarie

    // aprilie, iunie,..., noiembriecase 4: case 6: case 9: case 11: zile =30; break;

    // ianuarie, martie, mai,.. decembriedefault: zile=31; break; // celelalte (1,3,5,..)

    }

    Cazul default poate lipsi, dar cnd este prezent atunci este selectat cndvaloarea expresiei de selectie difer de toate cazurile enumerate explicit.

    Macroinstructiunea assert

  • 8/2/2019 Curs C(Moraru)

    37/166

    Macroinstructiunea assert , definit n fisierul , este expandat printr-o instructiune if si este folosit pentru verificarea unor conditii, fr ancrca programele cu instructiuni if , care le-ar face mai greu de citit.

    O asertiune este o afirmatie presupus a fi adevrat, dar care se poatedovedi fals.

    Utilizarea este similar cu apelul unei functii de tip void , cu un argument alcrei rezultat poate fi adevrat sau fals (nenul sau nul). Parametrul efectiveste o expresie de relatie sau logic care exprim conditia verificat. Dacrezultatul expresiei din assert este nenul (adevrat) atunci programul continunormal, dar dac expresia este nul (fals) atunci se afiseaz un mesaj careinclude expresia testat, numele fisierului surs si numrul liniei din fisier,dup care programul se opreste. Exemple de utilizare:

    assert ( n 0 && b > 0);

    Prin simplitatea de utilizare assert ncurajeaz efectuarea ct mai multor verificri asupra corectitudinii datelor initiale citite sau primite ca argumentede functii si asupra unor rezultate intermediare.

    Macroinstructiunea assert se foloseste pentru erori irecuperabile si mai alesn etapa de punere la punct a programelor, deoarece pentru versiunea final se

    prefer afisarea unor mesaje mai explicite pentru utilizatorii programului,eventual n alt limb dect engleza, nsotite de semnale sonore sau de imagini(pentru programe cu interfat grafic). Exemplu:

    #include #include #define MAX 1000

    void main () {int n;printf (n = ); scanf (%d,&n);if ( n > MAX) {

    printf ( Eroare: n > %d \n,MAX);return ;

    }...

    }

    De asemenea, assert se poate folosi pentru erori foarte putin probabile dar posibile totusi. Exemplu:

    double arie (double a, double b, double c) { // arie triunghi cu laturile a,b,cdouble p;assert (a > 0 && b > 0 && c > 0); // verificare argumente functiep =(a+b+c)/2;return sqrt (p*(p-a)*(p-b)*(p-c));

  • 8/2/2019 Curs C(Moraru)

    38/166

    }

    Anumite erori la operatii de citire de la consol sunt recuperabile, n sensulc se poate cere operatorului repetarea introducerii, si nu se va folosi assert .

    Eliminarea tuturor apelurilor assert dintr-un program se poate face prin

    secventa de directive: #define NDEBUG // inainte de include #include

    4. Prelucrri repetitive n C

    Instructiunea "while"

    Instructiunea while exprim structura de ciclu cu conditie initial si cu numr necunoscut de pasi si are forma urmtoare:

    while (e) i

    unde e este o expresie, iar i este o instructiune (instr. expresie, bloc, instr. decontrol)

    Efectul este acela de executare repetat a instructiunii continute ninstructiunea while ct timp expresia din paranteze are o valoare nenul (esteadevarat). Este posibil ca numrul de repetri s fie zero dac expresia arevaloarea zero de la nceput. Exemplu:

    // cmmdc prin incercari succesive de posibili divizorid= min(a,b); // divizor maxim posibilwhile (a%d || b%d)

    d=d-1; // incearca alt numar mai mic

    In exemplul anterior, dac a=8 si b=4 atunci rezultatul este d=4 si nu seexecut niciodat instructiunea din ciclu (d=d-1).

  • 8/2/2019 Curs C(Moraru)

    39/166

    Ca si n cazul altor instructiuni de control, este posibil s se repete un bloc deinstructiuni sau o alt instructiune de control. Exemplu:

    // determinare cmmdc prin algoritmul lui Euclidwhile (a%b > 0) {

    r = a % b; // restul impartirii a prin ba =b; b = r;

    } // la iesirea din ciclu b este cmmdc

    Este posibil ca n expresia din instructiunea while s se efectueze atribuirisau apeluri de functii nainte de a compara rezultatul operatiei efectuate.Exemplu:

    // algoritmul lui Euclidwhile (r=a%b) {

    a=b; b=r;} // b este cmmdc

    Instructiunea "for"

    Instructiunea for din C permite exprimarea compact a ciclurilor cu conditieinitial sau a ciclurilor cu numr cunoscut de pasi si are forma:

    for (e1; e2; e3) i

    Efectul acestei instructiuni este echivalent cu al secventei urmtoare:e1; // operatii de initializarewhile (e2){ // cat timp exp2 !=0 repeta

    i; // instructiunea repetatae3; // o instructiune expresie

    }

    Oricare din cele 3 expresii pot fi expresii vide, dar nu pot lipsi separatorii deexpresii (caracterul ';'). Dac lipseste "e2" atunci se consider c e2 arevaloarea 1, deci ciclul se va repeta neconditionat. Exemplu de ciclu infinit (saudin care se va iesi cu break sau return ):

    // repetare fara sfarsitfor ( ; ; ) instructiune // sau while(1) instructiune

    Cel mai frecvent instructiunea for se foloseste pentru programarea ciclurilor cu numr cunoscut de pasi (cu contor). Exemple:

    // stergere ecran prin defilare repetata de 24 ori

  • 8/2/2019 Curs C(Moraru)

    40/166

    for (k=1;k0;k--)

    putchar('\n');

    Exemplul urmtor arat cum se poate folosi for n loc de while :

    // determinare cmmdc pornind de la definitiefor (d=min(a,b); a%d || b%d; d--)

    ; // repeta nimic

    // determinare cmmdc pornind de la definitied=min(a,b); // sau o instr. "if"for (; a%d || b%d;)

    d--;

    Cele trei expresii din instructiunea for sunt separate prin ';' deoarece oexpresie poate contine operatorul virgul (','). Este posibil ca prima sau ultimaexpresie s reuneasc mai multe expresii separate prin virgule. Exemplu:

    // calcul factorial de nfor (nf=1, k=1 ; k

  • 8/2/2019 Curs C(Moraru)

    41/166

    Instructiunea do-while se foloseste pentru exprimarea ciclurilor cu conditiefinal, cicluri care se repet cel putin o dat. Forma uzual a instructiunii doeste urmtoarea:

    do i while (e);do { i } while (e);

    Acoladele pot lipsi dac se repet o singur instructiune, dar chiar si atuncise recomand folosirea lor. Exemplu de utilizare a instructiunii do:

    // calcul radical din x prin aproximatii succesiver2=x; // aproximatia initialado {

    r1=r2; // r1 este aprox. vecher2=(r1+x/r1) / 2; // r2 este aprox. mai noua

    } while ( abs(r2-r1)) ; // pana cand r2==r1Un ciclu do tipic apare la citirea cu validare a unei valori, citire repetat pn

    la introducerea corect a valorii respective. Exemplu:

    do {printf ("n="); // n trebuie sa fie sub 1000scanf("%d", &n);

    } while (n>1000) ;

    Exemplu de ciclu do pentru verificarea unor functii cu diferite date initiale:

    do {printf("x="); scanf("%f",&x); // citeste un xprintf ("sqrt(%f)= %lf \n", x, sqrt(x));

    } while (x>0);

    Motivatia instructiunii do este aceea c expresia verificat contine valoricalculate (citite) n operatiile din ciclu, deci (aparent) expresia trebuie plasatdup instructiunile din ciclu si nu naintea lor (ca n cazul instructiunii while ).Cu pretul repetrii unor instructiuni, un ciclu do poate fi rescris ca ciclu while

    // echivalent cu: do i while(e);i ;while (e)

    i ;

    Exemplu de citire repetat cu validare:

    printf (n=); scanf (%d,&n); // prima citirewhile ( n > 1000) { // daca n

  • 8/2/2019 Curs C(Moraru)

    42/166

    }

    Instructiunile "break" si "continue"

    Instructiunea break permite iesirea fortat dintr-un ciclu sau dintr-o structur switch . Sintaxa instructiunii este simpl:break;

    Efectul instructiunii break este un salt imediat dup instructiunea sau bloculrepetat prin while, do, for sau dup blocul switch . Exemple:

    // determinare cmmdc pornind de la definitiefor (d=min(a,b); d>0; d--)

    if (a%d==0 && b%d==0)break;

    printf ("%d \n",d); // d este cmmdc(a,b)

    // verifica daca un numar dat n este primfor (k=2; k

  • 8/2/2019 Curs C(Moraru)

    43/166

    // verifica daca n este primfor (prim=1,k=2; k

  • 8/2/2019 Curs C(Moraru)

    44/166

    Anumite aplicatii (cu grafuri sau cu matrice de exemplu) folosesc n modtraditional o numerotare de la 1 ( nu exist un nod zero ntr-un graf). O solutiesimpl este nefolosirea primei pozitii din vector (pozitia zero) si o alocaresuplimentar de memorie, pentru a folosi pozitiile 1..n dintr-un vector cu n+1elemente. Exemplu de nsumare a elementelor a[1],..a[n] din vectorul a:

    for (i=1,s=0; i

  • 8/2/2019 Curs C(Moraru)

    45/166

    Introducerea de valori ntr-un vector se poate face numai ntr-un ciclu si nu printr-o singur atribuire. Exemplu:

    // initializare vector afor (i=0;i

  • 8/2/2019 Curs C(Moraru)

    46/166

    printf ("%d ",c[k]);}

    Matrice n limbajul C

    O matrice bidimensional este privit n C ca un vector cu componentevectori, deci un vector de linii. Exemplu de matrice cu dimensiuni constante:

    int a[20][10]; // maxim 20 linii si 10 coloane

    Notatia a[i][j] desemneaz elementul din linia i si coloana j a uneimatrice a, sau elementul j din vectorul a[i].

    Este posibil initializarea unei matrice la definirea ei, iar elementele care nusunt initializate explicit primesc valoarea zero. Exemple:

    float unu[3][3] = { {1,0,0}, {0,1,0}, {0,0,1} };int a[10][10] ={0}; // toate elementele zero

    Prelucrarea elementelor unei matrice se face prin dou cicluri; un ciclurepetat pentru fiecare linie si un ciclu pentru fiecare coloan dintr-o linie:

    // afisare matrice cu nl linii si nc coloanefor (i=0;i

  • 8/2/2019 Curs C(Moraru)

    47/166

    In exemplul urmtor se citesc arce dintr-un graf orientat (cu nodurile 1..n) sise construieste o matrice de adiacente n care a[i][j]=1 dac exist arc de lanodul i la nodul j si a[i][j]=0 dac nu exist arcul (i-j) :

    short a[20][20]={0}; int i,j,n;printf(numar noduri: ); scanf (%d,&n);printf (" lista arce: \n");while ( scanf ("%d%d",&i,&j) == 2)

    a[i][j]=1;printf ( matrice de adiacente: \n);for (i=1;i

  • 8/2/2019 Curs C(Moraru)

    48/166

    5. Programare modular n C

    Importanta functiilor n programare

    Practic nu exist program care s nu apeleze functii din bibliotecile existentesi care s nu contin definitii de functii specifice aplicatiei respective.

    Motivele utilizrii de subprograme sunt multiple:- Un program mare poate fi mai usor de scris, de nteles si de modificat dac

    este modular, deci format din module functionale relativ mici.- Un subprogram poate fi reutilizat n mai multe aplicatii, ceea ce reduce

    efortul de programare al unei noi aplicatii.- Un subprogram poate fi scris si verificat separat de restul aplicatiei, ceea ce

    reduce timpul de punere la punct a unei aplicatii mari (deoarece erorile potapare numai la comunicarea ntre subprograme corecte).- Intretinerea unei aplicatii este simplificat, deoarece modificrile se facnumai n anumite subprograme si nu afecteaz alte subprograme (care nici numai trebuie recompilate).

    Utilizarea de functii permite dezvoltarea progresiv a unui program mare, fiede jos n sus (bottom up), fie de sus n jos (top down), fie combinat.

    In limbajele anterioare limbajului C subprogramele erau de dou feluri:- Functii, care au un singur rezultat, asociat cu numele functiei.- Proceduri (subrutine), care pot avea mai multe rezultate sau nici unul, iar

    numele nu are asociat nici o valoare.

    In limbajul C exist numai functii, iar n loc de proceduri se folosesc functiide tip void . Pentru o functie cu rezultat diferit de void tipul functiei este tipulrezultatului functiei.

    Standardul limbajului C contine si o serie de functii care trebuie s existe ntoate implementrile limbajului. Declaratiile acestor functii sunt grupate nfisiere antet cu acelasi nume pentru toate implementrile.

    In afara acestor functii standard exist si alte functii specifice sistemului deoperare, precum si functii utile pentru anumite aplicatii (grafic pe calculator,

    baze de date, aplicatii de retea s.a.).Utilizarea functiilor standard din biblioteci reduce timpul de dezvoltare a

    programelor, mreste portabilitatea lor si contribuie la reducerea diversittii

    programelor, cu efect asupra usurintei de citire si de ntelegere a lor.

    Utilizarea functiilor n C

  • 8/2/2019 Curs C(Moraru)

    49/166

    O functie de tip void se va apela printr-o instructiune expresie. Exemple:

    printf (\n n=);clearerr (stdin); // sterge indicator de eroare si EOF

    O functie de un tip diferit de void este apelat prin folosirea ei ca operandntr-o expresie. Exemple:

    z=sqrt(x)+ sqrt(y);printf ("%lf \n", sqrt(x));comb = fact(n) / ( fact(k) * fact(n-k)); // combinariy = atan (tan(x)); // functie in functie

    In limbajul C este uzual ca o functie s raporteze prin rezultatul ei (numr ntreg) modul de terminare (normal/cu eroare) sau numrul de valoricitite/scrise (la functiile de intrare-iesire). Uneori acest rezultat este ignorat iar functia cu rezultat este apelat ca o functie void . Exemple:

    scanf ("%d",&n); // rezultatul lui scanf este 1getchar(); // rezultatul este caracterul cititgets(adr); // rezultatul este adresa "adr"

    Argumentele folosite la apelul functiei se numesc argumente efective si pot fiorice expresii (constante, functii etc.). Argumentele efective trebuie scorespund ca numr si ca ordine (ca semnificatie) cu argumentele formale (cuexceptia unor functii cu numr variabil de argumente). Exemplu de functieunde ordinea argumentelor este important:

    // calculul unui unghi dintr-un triunghidouble unghi (double a, double b, double c) {

    return acos ((b*b+c*c-a*a) / (2.*b*c)); // unghiul A}

    // utilizariua = unghi (a,b,c); ub=unghi (b,c,a); uc = unghi (c,c,b);

    Este posibil ca tipul unui argument efectiv s difere de tipul argumentuluiformal corespunztor, cu conditia ca tipurile s fie "compatibile" la atribuire.Conversia de tip (ntre numere sau pointeri) se face automat, la fel ca si laatribuire. Exemple:

    x=sqrt(2); // arg. formal "double", arg.efectiv "int"y=pow(2,3); // arg. formale de tip "double"

  • 8/2/2019 Curs C(Moraru)

    50/166

    Deci o functie cu argument formal de un tip numeric (de ex. int ) poate fiapelat cu argumente efective de orice tip numeric (inclusiv long, float,double, long double ).

    Conversia automat nu se face si pentru argumente vectori de numere, iar conversia explicit de tip conduce la erori de interpretare. Exemplu:

    // suma elemente vector de intregifloat suma ( float a[ ], int n) {

    int k; float s=0;for (k=0;k

  • 8/2/2019 Curs C(Moraru)

    51/166

    // sterge ecran prin defilare cu 24 de liniivoid erase () {

    int i;for (i=0;i

  • 8/2/2019 Curs C(Moraru)

    52/166

    }

    Se recomand ca o functie s ndeplineasc o singur sarcin si s nu aibmai mult de cteva zeci de linii surs (preferabil sub 50 de linii).

    In limbajul C se pot defini si functii cu numr variabil de argumente, care pot

    fi apelate cu numr diferit de argumente efective. Exemplu de functie pentruadunarea unui numr oarecare de valori:

    #include int va_add(int numberOfArgs, ...) {

    va_list ap; // tip definit in int n = numberOfArgs; // numar de argumente efectiveint sum = 0;va_start(ap,numberOfArgs); // macro din while (n--)

    sum += va_arg(ap,int);va_end(ap); // macro din return sum;

    }// exemple de apelareva_add(3,987,876,567); // cu 3 argva_add(2,456,789); // cu 2 arg

    Instructiunea return

    Instructiunea return se foloseste pentru revenirea dintr-o functie apelat lafunctia care a fcut apelul si poate contine o expresie ce reprezint rezultatulfunctiei. Conversia rezultatului la tipul functiei se face automat, dac e posibil

    O functie de un tip diferit de void trebuie s contin cel putin o instructiunereturn prin care se transmite rezultatul functiei. Exemplu:

    long fact (int n) { // factorial de nlong nf=1L; // ptr calcul rezultatwhile ( n)

    nf=nf * n--; // nf=nf * n; n=n-1;return nf; // rezultat functie

    }

    O functie poate contine mai multe instructiuni return . Exemplu:char toupper (char c) { // trece car. c in litere mari

    if (c>='a'&& c

  • 8/2/2019 Curs C(Moraru)

    53/166

    Cuvntul else dup o instructiune return poate lipsi, dar de multe ori este prezent pentru a face codul mai clar. Exemplu fr else :

    char toupper (char c) { // trece car. c in litere mariif (c>='a' && c

  • 8/2/2019 Curs C(Moraru)

    54/166

    Functii cu argumente vectori

    O functie C nu poate avea ca rezultat direct un vector, dar poate modificaelementele unui vector primit ca argument. Exemplu:

    // genereaza vector cu cifrele unui nr.natural dat nvoid cifre (int n, char c[5] ) {

    int k;for (k=4;k>=0;k--) {

    c[k]=n%10; // cifra din pozitia kn=n/10;

    }}

    In exemplul anterior vectorul are dimensiune fix (5) si contine toatezerourile initiale, dar putem defini o functie de tip int cu rezultat egal cunumrul cifrelor semnificative. Pentru argumentele formale de tip vector nutrebuie specificat dimensiunea vectorului. Exemplu:

    float maxim (float a[ ], int n ) {int k;float max=a[0];for (k=1;k

  • 8/2/2019 Curs C(Moraru)

    55/166

    void sort (float a[ ],int n) {int n,i,j, gata; float aux;

    // repeta cat timp mai sunt schimbari de elementedo {

    gata =1;// compara n-1 perechi vecine

    for (i=0;i a[i+1] ) { // daca nu sunt in ordine// schimba pe a[i] cu a[i+1]aux=a[i]; a[i]=a[i+1]; a[i+1]=aux;gata =0;

    }} while ( ! gata);

    }

    Probleme pot apare la argumentele de functii de tip matrice din cauzainterpretrii diferite a zonei ce contine elementele matricei de ctre functiaapelat si respectiv de functia apelant. Pentru a interpreta la fel matricealiniarizat este important ca cele dou functii s foloseasc acelasi numr decoloane n formula de liniarizare. Din acest motiv nu este permis absentanumrului de coloane din declaratia unui argument formal matrice. Exempluincorect sintactic:

    void printmat ( int a[ ][ ], int nl, int nc); // gresit !

    O solutie simpl dar care nu e posibil ntotdeauna ar fi specificareaaceleeasi constante pentru numr de coloane n toate functiile si n definitiamatricei din programul principal. Exemplu:

    void printmat(int a[ ][10], int nl, int nc); // nc

  • 8/2/2019 Curs C(Moraru)

    56/166

    Compilatorul C genereaz o secvent de atribuiri la argumentele formalenainte de efectuarea saltului la prima instructiune din functia apelat. Dinacest motiv toate conversiile de tip efectuate automat la atribuire se aplic si latransmiterea argumentelor.

    In functia "fact" se modifica aparent valoarea lui "n" dar de fapt se modific

    o variabil local, fr s fie afectat variabila ce contine pe "n" n "main".Un alt exemplu clasic este o functie care ncearc s schimbe ntre elevalorile a dou variabile, primite ca argumente:

    void swap (int a, int b) { // nu este corect !!!int aux;aux=a; a=b; b=aux;

    }void main () {

    int x=3, y=7;swap(x,y);printf ("%d,%d \n",x,y); // scrie 3,7 !

    }

    In general o functie C nu poate transmite rezultate si nu poate modificaargumente de un tip numeric. In C pentru transmiterea de rezultate prinargumente de ctre o functie trebuie s folosim argumente formale de tip

    pointer (adrese de memorie).Versiunea corect pentru functia swap este urmtoarea:

    void swap (int * pa, int * pb) { // pointeri la intregiint aux;aux=*pa; *pa=*pb; *pb=aux;

    }

    Apelul acestei functii foloseste argumente efective pointeri:int x, y ; . . .swap (&x, &y) ; // schimba valorile x si y intre ele

    Pentru variabilele locale memoria se aloc la activarea functiei (deci laexecutie) si este eliberat la terminarea executrii functiei. Initializareavariabilelor locale se face tot la executie si de aceea se pot folosi expresii

    pentru initializare (nu numai constante). Exemplu:

    double arie (double a, double b, double c) {double p = (a+b+c)/2.; // initializare cu expresie

    return sqrt(p*(p-a)*(p-b)*(p-c));}

    Practic nu exist nici o diferent ntre initializarea unei variabile locale ladeclarare sau printr-o instructiune de atribuire.

  • 8/2/2019 Curs C(Moraru)

    57/166

    Functiile pot comunica date ntre ele si prin variabile externe, definitenaintea functiilor care le folosesc. Exemplu:

    int a[20][20],n; // variabile externevoid citmat() { // citire matrice

    int i,j;printf ("n="); scanf("%d",&n); // dimensiunifor (i=0;i

  • 8/2/2019 Curs C(Moraru)

    58/166

    Functia de mai sus nu scrie nimic pentru n=0, dar poate fi usor completat cuo ramur else la instructiunea if .

    Orice functie recursiv trebuie s contin (cel putin) o instructiune if (deobicei chiar la nceput), prin care se verific dac (mai) este necesar un apel

    recursiv sau se iese din functie. Reamintim c orice functie void primeste oinstructiune return ca ultim instructiune. Absenta instructiunii if conduce la orecursivitate infinit ( la un ciclu fr conditie de terminare).

    Pentru functiile de tip diferit de void apelul recursiv se face printr-oinstructiune return , prin care fiecare apel preia rezultatul apelului anterior.

    Anumite functii recursive corespund unor relatii de recurent. Exemplu:

    long fact (int n) {if (n==0)

    return 1L; // 0! = 1else

    return n * fact(n-1); // n!=n*(n-1)!

    }

    Algoritmul lui Euclid poate folosi o relatie de recurent:

    int cmmdc (int a,int b) {if ( a%b==0)

    return b;return cmmdc( b,a%b); // cmmdc(a,b)=cmmdc(b,a%b)

    }Pentru determinarea cmmdc mai exist si o alt relatie de recurent.Functiile recursive nu contin n general cicluri explicite (cu unele exceptii),

    iar repetarea operatiilor este obtinut prin apelul recursiv.

    O functie care contine un singur apel recursiv ca ultim instructiune poate fitransformat ntr-o functie nerecursiv, nlocuind instructiunea if cu while .

    int fact (int n) { // recursivif (n>0)

    return n*fact(n-1); // n!=n*(n-1)!else

    return 1; // 0! = 1}

    Functiile recursive cu mai multe apeluri sau cu un apel care nu este ultimainstructiune pot fi rescrise iterativ numai prin folosirea unei stive. Aceast

    stiv poate fi un simplu vector local functiei. Exemplu:

    void binar ( int n) { // afisare in binar int c[16],i; // c este stiva de cifre// pune resturi in stiva c

  • 8/2/2019 Curs C(Moraru)

    59/166

    i=0;while ( n>0) {

    c[i++]=n%2;n=n/2;

    }// descarca stiva: scrie vector in ordine inversa

    while (i>0)printf ("%d",c[--i]);}

    Exemplul urmtor este o functie recursiv cu argument vector :

    double max2 (double a, double b) { // maxim dintre doua valorireturn a > b ? a:b;

    }double maxim (double a[ ], int n) { // maxim dintr-un vector

    if (n==1)return a[0];

    elsereturn max2 (maxim (a,n-1),a[n-1]);

    }

    6. Programare structurat n limbajul C

    Structuri de control

    Instructiunile de control dintr-un limbaj permit selectarea si controlulsuccesiunii n timp a operatiilor de prelucrare. In limbajele masin si n

    primele limbaje de programare controlul succesiunii se realiza prin instructiunide salt n program (instructiunea go to mai exist si n prezent n C si n altelimbaje, desi nu se recomand utilizarea ei).

    S-a demonstrat teoretic si practic c orice algoritm (program) poate fiexprimat prin combinarea a trei structuri de control:- secventa liniar de operatii- decizie binar (alegere dintre dou alternative posibile)

    - ciclul cu conditie initial (repetarea unor operatii n functie de o conditie)

  • 8/2/2019 Curs C(Moraru)

    60/166

    Limbajul C este un limbaj de programare structurat deoarece posedinstructiuni pentru exprimarea direct a acestor trei structuri de control, fr ase mai folosi instructiuni de salt. Aceste instructiuni sunt blocul, if si while .

    Limbajul C contine si alte structuri de control, pe lng cele strict necesare:- selectie multipl (dintre mai multe alternative)

    - ciclul cu conditie final (verificat dup executarea operatiilor din ciclu)- ciclul for (cu conditie initial sau cu numr cunoscut de pasi)Combinarea structurilor de control se face prin includere; orice combinatie

    este posibil si pe oricte niveluri de adncime (de includere). Deci un ciclu poate contine o secvent sau o decizie sau un alt ciclu, s.a.m.d.

    Pentru evidentierea structurilor de control incluse se practic scriereadecalat (indentat): fiecare structur inclus se va scrie decalat la dreapta cuun caracter Tab sau cu cteva blancuri; la revenirea n structura de nivelsuperior se revine la alinierea cu care a nceput acea structur. Exemplu:

    // secventele de numere naturale consecutive a caror suma este egala cu nvoid main () {int n, m, k, j, s;printf("n= "); scanf ("%d",&n);m= n/2+1; // unde poate incepe o secventafor (i=1;i

  • 8/2/2019 Curs C(Moraru)

    61/166

    elsereturn -1; // nu exista secventa cautata

    }

    // toate secventele de numere consecutive a caror suma este nvoid main () {

    int n,k,i,j;printf("n= "); scanf ("%d",&n);for (i=1;i 0) {for (k=i;k

  • 8/2/2019 Curs C(Moraru)

    62/166

    // cauta prima aparitie a lui b in matricea afor (i=0;i

  • 8/2/2019 Curs C(Moraru)

    63/166

    }

    Un alt punct de vedere este acela c avem un singur ciclu de afisare, dar landeplinirea unei conditii se trece la linie nou. Exemplu:

    void print ( int x[ ],int n,int nc) {int i;for (i=0;i

  • 8/2/2019 Curs C(Moraru)

    64/166

    c=cod[0]; sum=val[0];for (i=1;i

  • 8/2/2019 Curs C(Moraru)

    65/166

    De multe ori avem de ales ntre mai multe variante corecte ale unei functii sicare difer ntre ele prin timpul de executie. In general vom prefera secventelede instructiuni mai eficiente ca timp.

    Metodele de reducere a timpului de executie pot fi mprtite n metode cucaracter general si metode specifice fiecrei probleme de rezolvat.

    Dintre metodele cu caracter general mentionm:- Se scot din cicluri apeluri de functii si alte calcule care pot fi efectuate osingur dat, nainte de intrarea n ciclu.

    In exemplul urmtor se genereaz toate numerele naturale de n cifre:

    for (k=1;k< pow(10,n)-1;k++) { ... }

    Calculul celui mai mare numr de n cifre se poate face n afara ciclului:

    max=(int)pow(10,n) -1;for (k=1;k a[k])este=0;

    return este;

    }

    - Evitarea apelurilor repetate, inutile de functii. In exemplul urmtor sedetermin cel mai lung segment din toate segmentele care unesc n puncte date

    prin coordonatele lor.

    float dmax ( float x[ ], float y[ ], int n) {int i,j; float d, dmax=0;for (i=0;i

  • 8/2/2019 Curs C(Moraru)

    66/166

    O programare inabil ar fi putut arta astfel :

    dmax=0;for (i=0;i

  • 8/2/2019 Curs C(Moraru)

    67/166

    s=s+c[i]*p;}return s;

    }

    Diferenta de timp dintre cele dou solutii este insesizabil pentru valoriuzuale ale lui n ( < 50). In general, optimizarea programelor este justificat

    pentru probleme de dimensiuni mari sau pentru secvente de program repetatefrecvent, din programe des utilizate.

    Exist ns anumite categorii de probleme unde diferenta dintre un algoritmsau altul este semnificativ si ea creste accelerat odat cu dimensiunea

    problemei. Studiul complexittii algoritmilor este un subiect de programareavansat si este independent de limbajul de programare utilizat.

    7. Tipuri pointer n C

    Variabile pointer

    O variabil pointer poate avea ca valori adrese de memorie. Aceste adrese pot fi:

    - Adresa unei valori de un anumit tip (pointer la date)- Adresa unei functii (pointer la o functie)- Adresa unei zone cu continut necunoscut (pointer la void ).

    Cel mai frecvent se folosesc pointeri la date.Exist o singur constant de tip pointer, cu numele NULL (valoare zero) si

    care este compatibil la atribuire si comparare cu orice tip pointer. Totusi, se poate atribui o constant ntreag convertit la un tip pointer unei variabile pointer. Exemplu:

    char * p = (char*)10000; // o adresa de memorie

    Desi adresele de memorie sunt de multe ori numere ntregi pozitive, tipurile pointer sunt diferite de tipurile ntregi si au utilizri diferite.

    In limbajul C tipurile pointer se folosesc n principal pentru:- Declararea si utilizarea de vectori, mai ales pentru vectori ce contin siruri decaractere.- Argumente de functii prin care se transmit rezultate (adresele unor variabile

    din afara functiei).

  • 8/2/2019 Curs C(Moraru)

    68/166

    - Acces la date alocate dinamic si care nu pot fi adresate printr-un nume.- Argumente de functii prin care se transmite adresa unei alte functii.

    Declararea unei variabile (sau argument formal) de un tip pointer includedeclararea tipului datelor (sau functiei) la care se refer acel pointer. Sintaxadeclarrii unui pointer la o valoare de tipul tip este

    tip * ptr; // sau tip* ptr; sau tip *ptr;

    Exemple de variabile si argumente pointer:

    char * pc; // pc= adresa unui caracter sau sir de car.int * pi; // pi= adresa unui intreg sau vector de intvoid * p; // p= adresa de memorieint * * pp; // pp= adresa unui pointer la un intregint strlen (char* str); // str=adr. unui sir de caractere

    Atunci cnd se declar mai multe variabile pointer de acelasi tip, nu trebuie

    omis asteriscul care arat ca este un pointer. Exemple:int *p, m; // m de tip "int", p de tip "int*"int *a, *b ; // a si b de tip pointer

    Dac se declar un tip pointer cu typedef atunci se poate scrie astfel:

    typedef int* intptr; // intptr este nume de tipintptr p1,p2,p3; // p1,p2,p3 sunt pointeri

    Tipul unei variabile pointer este important pentru c determin cti octeti vor fi folositi de la adresa continut n variabila pointer si cum vor fi interpretati.Un pointer la void nu poate fi utilizat direct, deoarece nu se stie cti octetitrebuie folositi si cum.

    Operatii cu pointeri la date

    Operatiile posibile cu variabile pointer pot fi rezumate astfel:- Indirectarea printr-un pointer (diferit de void *), pentru acc