1.2. Variabile, expresii si asignari 1.3. Un exemplu de utilizare a variabilelor de tip float 1.4. nitializarea variabilelor 1.!. "olosirea directivei #define 1.$. "olosirea functiilor printf%& si scanf%& 1.'. nstructiunea ()*ile( 1.+. ,tilul de redactare al programelor 1.-. .rori de programare frecvente 1.1/. 0edirectarea intrarii si iesirii 1.11. .xercitii propuse spre implementare 11111111 Capitolul 1 11111111 1111111111111111111111111 Cum se scrie un program (in C) ? 1111111111111111111111111 2rogramele sunt scrise pentru a instrui masinile sa lucreze cu tas3uri specifice sau sa rezolve probleme specifice. 4 procedura %descrisa pas cu pas& asociata unui tas3 se numeste algoritm. 2rogramarea este activitatea de comunicare %codificare& a algoritmilor in calculatoare. 2rocesul de programare are %in general& patru pasi5 1. ,pecificarea tas36ului7 2. 8escoperirea unui algoritm pentru solutia sa7 3. Codificarea algoritmului in C7 4. 9estarea codului. Un calculator este o masina electronica digitala compusa din trei componente5 1. procesor %central processing unit sau C2U&7 2. memorie7 3. dispozitive de intrare:iesire. 2rocesorul lucreaza cu instructiuni care sunt inregistrate in memorie. 2e langa aceste instructiuni, in memorie sunt pastrate si date. 8ispozitivele de intrare:iesire iau informatii de la agenti externi catre masina si produc informatii pentru acesti agenti. 8ispozitivele de intrare sunt %de obicei&5 1. tastatura7 2. disc*eta7 3. banda7 4. C8604;. 8ispozitivele de iesire sunt %de obicei&5 1. ecranul terminalului7 2. imprimanta7 3. disc*eta7 4. banda7 !. C8604;. ,istemul de operare consta intr6o colectie de programe speciale si are doua scopuri principale5 1. coordoneaza resursele %memoria, procesorul, imprimanta& masinii. 8e exemplu, daca un fisier este creat pe disc sistemul de operare are gri<a de detaliile localizarii acestuia si memoreaza numele, lungimea si data creearii7 2. produce instrumente necesare utilizatorilor, multe dintre ele sunt folositoare utilizatorilor C. 8e exemplu, doua dintre acestea sunt un editor de texte si un compilator de C. Un cod C se numeste cod sursa, iar un fisier ce contine un cod sursa se numeste fisier sursa. 8upa ce a fost creat un fisier sursa, atunci se invoca un compilator de C. 8e exemplu, pentru sistemele ;,684, se poate da comanda5 bc ex1.c sau tcc ex1.c iar pentru unele sisteme U=>5 cc ex1.c 8aca nu sunt erori in ex1.c, atunci aceasta comanda produce fisierul executabil asociat %ex1.exe&. ?cum acesta poate fi rulat %executat& cu numele sau %ex1 sau ex1.exe&. n continuare, vom preciza trei dintre trasaturile procesului de compilare %mentionam ca asupra acestor notiuni, vom reveni cu detalii interesante intr6un capitol viitor&5 1. invocarea preprocesorului7 2. invocarea compilatorului7 3. invocarea incarcatorului. 2reprocesorul modifica o copie a codului sursa prin includerea altor fisiere si facand alte sc*imbari. Compilatorul traduce aceasta in cod obiect folosit de incarcator pentru producerea fisierului executabil final. "isierul care contine codul obiect se numeste fisier obiect. "isierele obiect, spre deosebire de fisierele sursa, nu se pot intelege asa usor. Cand spunem deci compilare, de fapt invocam preprocesorul, compilatorul si apoi incarcatorul. 8upa ce scriem un program, acesta trebuie compilat si testat. 8aca sunt necesare modificari, atunci codul sursa trebuie editat din nou. ?sadar, partea proceselor de programare consta din ciclul5 editare 666@ compilare 666@ executie AA B B B BCCCCCCCCCC B B BCCCCCCCCCCCCCCCCCCCCCCCB 66666666666666666666666 Un prim program 66666666666666666666666 4 sa incepem cu un exemplu de program C necesar pentru tiparirea unui sir pe ecran. #include Dstdio.*@ main%& E printf%(azi am inceput laboratoarele de CFn(&7 G "olosind un editor de texte, presupunem ca am scris si salvat acest fisier numit (ex1.c(. Cand programul este compilat si rulat atunci va apare pe ecran sirul5 azi am inceput laboratoarele de C 6666666666666 Explicatii: 6666666666666 1. #include Dstdio.*@ Hiniile care incep cu (#( se numesc directive de preprocesare %precompilare&. ?cestea comunica cu preprocesorul. ?ceasta directiva (#include( determina preprocesorul sa includa o copie a fisierului *eader (stdio.*( in acest punct al codului. 2arantezele ung*iulare din (Dstdio.*@( indica ca acest fisier se gaseste in biblioteca C %pentru compilatorul Iorland 3.1 pentru ;,684,, acesta se gaseste in subdirectorul IC31:=CHU8.&. ?m inclus acest fisier deoarece acesta contine informatii despre functia (printf%&(. 2. main%& "iecare program are o functie numita (main(, care se executa intai. 2arantezele ce urmeaza dupa (main( indica compilatorului ca aceasta este o functie. 3. E ?colada stanga incepe corpul fiecarei functii. 4 acolada dreapta corespunzatoare trebuie sa fie la sfarsitul functiei. 4. printf%& ,istemul C contine o biblioteca standard de functii care poate fi utilizata in programe. (printf%&( este o functie din biblioteca care tipareste pe ecran. ?ceasta este o functie descrisa in biblioteca (stdio.*( %care se numeste prototipul functiei (printf%&(&. !. (azi am inceput laboratoarele de CFn( Un sir constant in C consta dintr6un numar de caractere incadrate intre g*ilimele. ?cest sir este un argument al functiei (printf%&(. Caracterele Fn de la sfarsitul sirului %se citesc (bac3slas* n(& reprezinta, de fapt, un singur caracter numit (ne)line(. 4 forma ec*ivalenta a programului de mai sus5 #include Dstdio.*@ main%& E printf%(azi am inceput (&7 printf%(laboratoarele de CFn(&7 G 66666666666666 4bservatii5 66666666666666 1. 2rimul (printf( contine la sfarsit un spatiu. 66666666666666666666666666666666666666 Variabile, expresii si asignari 66666666666666666666666666666666666666 n urmatorul exemplu vom ilustra folosirea variabilelor pentru manipularea valorilor intregi. Variabilele sunt folosite sa memoreze valori. 8in moment ce diferite tipuri de variabile sunt folosite sa memoreze diferite tipuri de date, tipul fiecarei variabile trebuie specificat. 2entru a ilustra aceasta idee vom calcula cate ore si minute contin un anumit numar de zile. ?lgoritmul ar fi5 1. asigneaza un numar de zile unei variabile7 2. calculeaza numarul de ore si memoreaza6l intr6o variabila7 3. calculeaza numarul de minute si memoreaza6l intr6o variabila7 4. afiseaza numarul de zile, ore si minute pe ecran. Urmatorul program scris in C reprezinta implementarea algoritmului precedent5 #include Dstdio.*@ main%& E int zile, ore, minute7 zile1'7 ore124Jzile7 minute1$/Jore7 printf%(4 saptamana are Kd ore, Kd minute.Fn(,ore, minute&7 G Cand compilam si rulam acest program, pe ecran va apare mesa<ul5 4 saptamana are 1$+ ore, 1//+/ minute. 6666666666666 Explicatii: 6666666666666 1. Hinia int zile, ore, minute7 reprezinta o declaratie de variabile. Variabilele zile, ore, minute sunt declarate de tip (int(, unul dintre cele mai importante tipuri din C. 4 variabila de tip (int( poate lua o valoare intreaga intre 632$'+ si 32$''. 9oate variabilele dintr6un program trebuie declarate inainte de a fi utilizate. 8eclaratiile, la fel ca si instructiunile, au la sfarsit (7(. 2. Hinia zile1'7 reprezinta o instructiune de atribuire %sau asignare&. ,emnul (1( este operatorul de asignare de baza in C. Valoarea expresiei din partea dreapta a simbolului (1( este atribuita variabilei din partea stanga. 3. nstructiunea printf%(4 saptamana are Kd ore, Kd minute.Fn(,ore, minute&7 este similara celei prezentate in exemplul precedent, dar are trei argumente. 2rimul argument, intotdeauna un sir de caractere, se numeste sir de control. ?ici, intalnim specificarea de conversie %care se mai numeste format& (Kd(. "ormatele (Kd( determina tiparirea valorilor expresiilor corespunzatoare %al doilea si al treilea argument& in formatul intregilor zecimali. ?sadar, primul format (Kd( corespunde cu valoarea variabilei (ore(, iar cel de6al doilea format (Kd( cu valoarea variabilei (minute(. n C, toate variabilele trebuie declarate inainte de a fi utilizate in expresii si instructiuni. "orma generala a unui program simplu este5 directive de precompilare main%& E declaratii instructiuni G
Un nume de variabila, numit si identificator, consta dintr6o secventa de litere, cifre si (underscore(, dar fara a incepe cu cifra. Cuvintele c*eie, numite si cuvinte rezervate, nu pot fi utilizate ca nume de variabile. .xemple de cuvinte c*eie5 c*ar, int, float. 4peratorii binari L 6 J : K sunt folositi pentru adunare, scadere, inmultire, impartire sau modul. .xemple5 ! K 2 1 1 si ' K 4 1 3. .vident, in expresia a K b, b nu trebuie sa fie zero, din moment ce nu se poate face impartirea cu zero. 6666666666666666666666666666666666666666666666666666666666666666 Un exemplu de utilizare a variabilelor de tip float 6666666666666666666666666666666666666666666666666666666666666666 #include Dstdio.*@ main%& E float x, M7
x 1 1./7 M 1 2./7 printf%(,uma dintre x si M este Kf.Fn(, xLM&7 G
2e ecran se va afisa ,uma dintre x si M este 3.//////. 66666666666666 Observatii: 66666666666666 1. Hinia float x, M7 semnifica declararea variabilelor x si M de tip (float( %deci de tip real&. n realitate sunt numere rationale din intervalul N61/AE3/+G,61/AE63/+GO U N1/AE63/+G,1/AE3/+GO 2. Hinia printf%(,uma dintre x si M este Kf.Fn(, xLM&7 are doua argumente si reprezinta o tiparire la ecran. 8e remarcat, ca spre deosebire de exemplele precedente %unde foloseam formatul Kd&, aici folosim formatul pentru numere reale, care este (Kf(. 3. 2recizarea tipului variabilelor este esential. 8e exemplu, daca, sa zicem, ca x1'./ si M12./, sunt declarati ca fiind de tip float, atunci x:M se evalueaza la 3.!. 8aca, insa x1' si M12, sunt declarati ca fiind de tip int, atunci x:M se evalueaza la 3 %ramane doar partea intreaga&. 6666666666666666 Initializarea 6666666666666666 nitializarea variabilelor se poate face si cand se declara acestea. 8e exemplu, putem scrie5 c*ar c1P?P7 int i117 2utem astfel modifica programul precedent, inlocuind liniile int zile, ore, minute7 zile1'7 cu int zile1', ore, minute7 66666666666666 Observatii: 66666666666666 1. 8e obicei, pentru initializarea unei variabile se folosesc constante sau expresii constante. ,e pot insa folosi si variabile care au de<a valoarea precizata. 8e exemplu, urmatoarea secventa de program este corecta5 int zile1', ore1zile J 24, minute1ore J $/7 666666666666666666666666666666666666 Folosirea directivei #define 666666666666666666666666666666666666 0eamintim ca in procesul de compilare a programelor C, intai este invocat preprocesorul. 8e exemplu, pot fi incluse fisiere, sau anumite siruri de caractere specificate pot fi modificate in alte siruri. 8irectivele de preprocesare incep cu caracterul # %in C traditional, acesta trebuie pus pe prima coloana, pe cand in ?=, C poate fi precedat de spatii&. ,e recomanda scrierea # pe prima coloana, iar a directivelor de precompilare la inceputul programului. ata cateva exemple de folosire a directivei (#define(5 #define H;9 1// #define 2 3.141!- 66666666666666 Observatii: 66666666666666 1. 8aca aceste directive de preprocesare apar la inceputul fisierului, atunci in momentul compilarii preprocesorul sc*imba toate aparitiile identificatorului H;9 la 1// si a lui 2 cu 3.141!-. ,ingurele care raman nesc*imbate sunt sirurile constante. 8e exemplu, preprocesorul va sc*imba printf%(2 1 KfFn(, 2&7 in printf%(2 1 KfFn(, 3.141!-&7 8eoarece identificatorul 2 se va inlocui peste tot %cu exceptia sirurilor constante& in 3.141!-, atunci acesta se va numi constanta simbolica. 2. 8irectiva #define poate aparea oriunde in program, dar ea afecteaza numai liniile care urmeaza acesteia. 3. 2rin conventie, identificatorii care trebuie sc*imbati de preprocesor se scriu cu ma<uscule. 66666666666666666666666666666666666666666666666666 Avantae ale folosirii directivei #define 66666666666666666666666666666666666666666666666666 1. Hizibilitate marita. ,e refera la citirea si intelegerea rapida a fisierului sursa %2 stim ce inseamna si ne amintim ca este 3.ceva, deci nu trebuie sa scriem de fiecare data valoarea sa&7 2. ,c*imbarile ulterioare ale unor valori constante se face foarte usor. 8e exemplu, vrem sa modificam valoarea lui H;9 la 1////. n locul liniei #define H;9 1// scriem #define H;9 1//// 8aca nu am fi folosit acest mod de definire a constantei H;9, atunci ar fi trebuit sa modificam peste tot in program 1// cu 1////. 66666666666666666666666666666666666666666666666 Folosirea functiilor printf!" si scanf!" 66666666666666666666666666666666666666666666666 "unctiile de tiparire, respectiv de citire, (printf%&( si (scanf%&( au urmatoarele argumente5 sirCdeCcontrol si celelalteCargumente unde sirCdeCcontrol este un sir care poate contine specificatii de conversie, sau formate. 4 specificare de conversie incepe cu caracterul K si se termina cu caracterul de conversie. 8e exemplu, in formatul Kd, litera (d( este caracterul de conversie. 666666666666666666666666666 Folosirea lui printf!" 666666666666666666666666666 0eamintim ca formatul Kd este folosit pentru scrierea valorii unei expresii ca un intreg zecimal. n mod similar5 6 Kc este folosit pentru tiparirea unei expresii ca un caracter 6 Kf este folosit pentru tiparirea unei expresii reale 6 Ks este folosit pentru tiparirea unui sir de caractere 66666666666 Exemplu:: "ie instructiunea5 66666666666 printf%(;ultime de argumente5 Ks Kd Kf KcKcFn(,(one(,2,2.33,PQP,P4P&7
?rgumentele lui (printf%&( sunt separate de virgula, deci avem sase argumente. 2rimul argument este sirul de control. 4btinem corespondenta5 Ks D666@ (one( Kd D666@ 2 Kf D666@ 2.33 Kc D666@ PQP Kc D666@ P4P
Cand se executa programul ce contine aceasta instructiune, obtinem5 ;ultime de argumente5 one 2 2.33//// Q4 66666666666666 Observatii: 66666666666666 1. 8aca instructiunea (printf%&( contine prea multe caractere, atunci se poate scrie aceasta pe mai multe linii, separate prin virgula. 8e exemplu, putem scrie5 printf%(KsKsFn(, (?ceasta instructiune se va scrie (, (pe o linie de text foarte lunga.Fn(&7 9abelul de mai <os descrie cum caracterele de conversie afecteaza argumentele corespunzatoare. printf%& B66666666666666666666666666666666666666666666666666666666666666666666666666666666B B Caracter B B B de B Cum este tiparit argumentul corespunzator ? B B conversie B B B66666666666666666666666666666666666666666666666666666666666666666666666666666666B B c B ca un caracter B B d B ca un intreg zecimal B B e B ca un numar in virgula flotanta in notatia stiintifica B B f B ca un numar in virgula flotanta B B g B in format e sau f %alegand cel mai scurt dintre ele& B B s B ca un sir B B666666666666666666666666666666666666666666666666666666666666666666666666666666666B Cand un argument este tiparit, locul unde este tiparit se numeste campul sau, iar numarul de caractere ale acestui camp se numeste lungimea campului. ?ceasta lungime poate fi specificata intr6 un format ca un intreg plasat intre caracterul K si caracterul de conversie. 8e exemplu, instructiunea printf%(KcK3cK'cFn(, P?P, PIP, PCP&7 va tipari ? I C 2entru numerele in virgula flotanta, putem controla precizia %numarul de cifre zecimale&, la fel ca lungimea campului. "orma generala a formatului este Km.nf si semnifica ca m este lungimea campului, iar n precizia. "ormatul Kmf specifica doar lungimea campului, iar formatul K.nf numai precizia. 8e exemplu, instructiunile5 printf%(=umere15 K.1f K.2f K.3fFn(, 1./, 2./, 3./&7 printf%(=umere25 K'.1f K'.2f K'.3fFn(, 4./, !./, $./&7 vor avea ca efect afisarea5 =umere15 1./ 2.// 3./// =umere25 4./ !.// $./// 66666666666666666666666666 Folosirea lui scanf!" 66666666666666666666666666 "unctia (scanf%&( este asemanatoare cu (printf%&(, dar este folosita pentru intrari in loc de iesiri. 2rimul sau argument este un sir de control care are formatele corespunzatoare cu variatele moduri de interpretare a sirurilor de intrare. 8upa sirul de control urmeaza adresele variabilelor. ?dresa unei variabile este locul din memorie unde este memorata variabila %vom reveni in capitolele viitoare&. ,imbolul (R( reprezinta operatorul de adresa. 8e exemplu, scanf%(Kd(, Rx&7 formatul Kd implica interpretarea caracterelor tiparite la intrare ca un intreg zecimal, si apoi memorarea valorii variabilei la adresa lui x. 9abelul de mai <os descrie efectele caracterelor de conversie din formate folosite de functia scanf%&. scanf%& B6666666666666666666666666666666666666666666666666666666666666666666666666B B Caracter B B B de B Ha ce caractere se face convertirea ? B B conversie B B B6666666666666666666666666666666666666666666666666666666666666666666666666B B c B la un caracter B B d B la un intreg zecimal B B f B la un numar in virgula flotanta %float& B B lf B la un numar in virgula flotanta %double& B B Hf B la un numar in virgula flotanta %long double& B B s B la un sir B B6666666666666666666666666666666666666666666666666666666666666666666666666B 66666666666 ?tentie S "unctia (prinf%&( foloseste formatul Kf pentru tiparirea numerelor 66666666666 float si double, pe cand (scanf%&( foloseste formatul Kf pentru citirea unui float si Klf pentru citirea unui double. 666666666666 Exemplu:: ?ria unui cerc. 666666666666 #include Dstdio.*@ #define 2 3.141!-2$!3!+-'-3 main%& E double raza7 printf%(FnKsFnFnKs(, (?cest program calculeaza aria cercului(, (8ati raza5(&7 scanf%(Klf(, Rraza&7 printf%(FnKsFnKsK.2fKsK.2fKsK.2fFnKsK.!fFnFn(, (?ria 1 2 J raza J raza(, ( 1 (, 2, ( J (, raza, ( J (, raza, ( 1 (, 2 J raza J raza&7 G
2resupunem ca la executia programului introducem raza egala cu 2.333. ?tunci vor apare pe ecran5 ?cest program calculeaza aria cercului
8aca am calcula separat %pe *artie&, am obtine ?ria 1 3.14 J 2.33 J 2.33 1 1'./4$'4$, numar care nu coincide cu cel furnizat de calculator. Tustificarea este aceea ca 2 si raza sunt tiparite doar cu doua zecimale, pe cand valorile lor sunt pastrate in memorie cu precizie mai mare. 66666666666666666666666666666 Instructiunea #$%ile# 66666666666666666666666666666 nstructiunea )*ile face parte din categoria actiunilor repetitive. 2entru a intelege aceasta instructiune, vom face un exemplu de adunare a numerelor de la 1 la 1/. 6666666666666 Exemplu:: 6666666666666 #include Dstdio.*@ main%& E int i11, suma1/7 )*ile %iD11/& E suma 1 suma L i7 i 1 i L 17 G printf%(,uma primelor 1/ numere este KdFn(,suma&7 G 6666666666666 Explicatii: 6666666666666 1. Ha linia int i11, suma1/7 se declara variabilele i si sum de tip int si sunt initializate cu 1 si /, respectiv. 2. Constructia )*ile %iD11/& E suma 1 suma L i7 i 1 i L 17 G reprezinta o instructiune )*ile %sau iteratie )*ile&. ;ai intai, se evalueaza expresia iD11/. Cum valoarea initiala a lui i este egala cu 1, rezulta ca se vor executa instructiunile dintre acolade. ?stfel, variabila suma va fi asignata cu vec*ea valoare a lui suma la care se adauga valoarea lui i. 8eci, suma se evalueaza la 1. ?poi, variabila se evalueaza la suma dintre vec*ea valoare a lui i %i11& si 1, deci este egala cu 2. n acest moment, executia revine la inceput adica evaluam expresia iD11/. Cum valoarea lui i este 2, rezulta ca se va executa iar corpul lui )*ile. Ha sfarsitul acestei iteratii, suma este evaluata la 1L2, iar i la 3. ,e observa usor ca iD11/ este tot adevarata, deci se va executa din nou corpul lui )*ile. Ha sfarsitul celei de6a treia iteratii, sum este evaluata la 1L2L3, iar i la 4. 2rocesul continua pana cand valoarea lui i este 11, care implica falsitatea expresiei iD11/. ?stfel se iese din bucla )*ile. 3. nstructiunea printf%(,uma primelor 1/ numere este KdFn(, suma&7 va afisa mesa<ul ,uma primelor 1/ numere este !!. 4. "ormatul general al instructiunii )*ile este )*ile %expresie& instructiune unde instructiune poate fi o singura instructiune sau un grup de instructiuni delimitate prin E si G %care se mai numeste si instructiune compusa&. 66666666666666666666666666666666666666666666666 &eneralizarea problemei precedente 66666666666666666666666666666666666666666666666 8orim sa citim mai multe numere %fara a sti aprioric numarul lor si care sunt acestea& si dorim sa afisam suma lor. Consideram urmatorul algoritm cu patru pasi5 1. nitializarea a doua variabile contor si suma7 2. ?fisarea unor mesa<e utile citirii numerelor7 3. Citirea repetata a numerelor, incrementarea variabilei contor si adunarea numarului citit la suma7 4. ?fisarea celor doua valori ale variabilelor. nstructiunea )*ile este una din cele trei constructii existente in C menite sa descrie actiuni repetitive. n solutia noastra, utilizam valoarea returnata de functia (scanf%&( pentru a controla instructiunea )*ile. Consideram urmatorul cod C5 #include Dstdio.*@ main%& E int contor 1 /7 float suma 1 /./, x7 printf%(,uma urmatoarelor numere va fi calculataFn(&7 printf%(8ati numerele5Fn(&7 )*ile %scanf%(Kf(, Rx&111& E contor 1 contor L17 suma 1 suma Lx7 G printf%(FnKsK!dFnKsK12fFnFn(, (=umarul de numere5 (, contor, (,uma lor5 (, suma&7 G 66666666666666 Explicatii: 66666666666666 1. scanf%(Kf(, Rx&111 ,imbolul 11 reprezinta operatorul de egalitate. .xpresia a11b intoarce true daca valoarea lui a este egala cu valoarea lui b. 8e exemplu, 1111 intoarce true, 2113 intoarce false. "unctia (scanf%&( are rolul de a citi caractere scrise de utilizator, sa le converteasca la float, si sa plaseze aceasta valoare la adresa lui x. 8aca totul se desfasoara cu succes, atunci scanf%& intoarce valoarea 1, adica true. 8aca din anumite motive, procesul de conversie esueaza, atunci se intoarce valoarea / %deci false&. 8aca nu mai introducem nici o data %ControlAz in ;8684,, C0 urmat de ControlAd in U=>&, atunci scanf%& va intoarce valoarea 61 %deci tot false&. 2. )*ile %scanf%(Kf(, Rx&111& E contor 1 contor L17 suma 1 suma Lx7 G 8upa cum am vazut mai sus, bucla )*ile se executa atata timp cat scanf%(Kf(, Rx&111 se evalueaza la true. teratia se inc*eie cand tastam ControlAz sau ceva ce nu se poate converti la float, de exemplu PaP sau C0. Ha fiecare executie a buclei se incrementeza variabila contor, iar valoarea variabilei suma creste cu valoarea lui x %citita de la tastatura&. 3. printf%(FnKsK!dFnKsK12fFnFn(, (=umarul de numere5 (, contor, (,uma lor5 (, suma&7 2resupunem ca executam acest program pentru numerele 1.1 2./2 3.//3 4.///4 !.////! 2e ecran va apare rezultatul5 =umarul de numere5 ! ,uma lor5 1!.12344- 666666666666666 Observatii: 666666666666666 1. 8aca numaram spatiile, observam ca valoarea lui contor a fost tiparita pe un camp de ! caractere, iar suma pe 12 caractere. ?ceasta este cauzata de formatele (K!d( si (K12f(. 0etineti ca tiparirea zecimalelor pentru suma este gresita de la a treia zecimala. 666666666666666666666666666666666666666666666 'tilul de redactare al programelor 666666666666666666666666666666666666666666666 Un stil bun de scriere a codului este esential pentru arta programarii. ?ceasta faciliteaza citirea, scrierea si intretinerea programelor. Un stil bun foloseste5 1. spatii goale si comentarii, astfel incat codul este usor de citit si de inteles7 2. utilizarea indentarii este cruciala, care indica cu precizie structurile de control. 8e exemplu, in constructia )*ile %expresie& instructiune indentarea instructiunii indica ca executia acesteia este sub controlul iteratiei )*ile7 3. alegerea de nume sugestive pentru variabile7 4. corespondenta dintre acolade. 8e exemplu, urmatorul program este scris in stilul (Iell Habs industrial programming stMle( %#,E,G,m pe prima coloana&. #include Dstdio.*@ #include Dstdlib.*@ #define Q4 (,tart( main%& E G 666666666666666 Observatii: 666666666666666 1. 2rogramatorii incepatori uneori cred ca vor (sparge( piata cu stilul lor propriu de redactare a programelor. ?tentie S Utilizati strategia care este de<a in uz. 66666666666666666666666666666666666666666 Erori de programare frecvente 66666666666666666666666666666666666666666 ;ai ales la inceputul invatarii programarii pe calculator, se fac multe erori simple, cum ar fi5 1. neinc*iderea sirului cu g*ilimele drepte. Cand compilatorul intalneste g*ilimeaua stanga, atunci incepe sa colecteze toate caracterele care urmeaza spre a forma un sir de caractere, pana intalneste g*ilimeaua dreapta. 8aca aceasta nu exista, atunci compilatorul da mesa<ul de eroare, de tipul5 Unterminated string or c*aracter constant 2. scrierea gresita a numelui variabilelor7 3. nedeclararea lor. n general, compilatorul da un mesa< de eroare potrivit, alteori din cauza interpretarii separate, nu. 8e exemplu, scriem gresit (prinf%&( in loc de (printf%&(. ?tunci compilatorul va da un mesa< prin care ne informeaza ca nu gaseste functia (prinf%&(. 8eci, el nu isi da seama de omiterea unei litere, ci o interpreteaza in mod diferit. 4. daca dorim sa citim o variabila de tip double, atunci in functia (scanf%&( trebuie sa specificam formatul (Klf(7 !. faptul ca uneori uitam ca in formatul (Km.nf( pentru afisarea cu virgula mobila, m semnifica lungimea campului. 8e exemplu, pentru a specifica doua zecimale la dreapta si trei la stanga, nu trebuie sa scriem K2.3f, ci K$.3f deoarece se numara si punctul zecimal7 $. poate cea mai frecventa greseala cand se foloseste scanf%& este uitarea operatorului de adresa. 8aca, de exemplu, scriem scanf%(KdKd(, a, b& in loc de scanf%(KdKd(, Ra, Rb& atunci compilatorul nu se va (prinde( de eroare. Iineinteles, ca vom obtine rezultate eronate %run6 time error& care sunt ceva mai greu de corectat. 666666666666666666666666666666666666666 (edirectarea intrarii si iesirii 666666666666666666666666666666666666666 2utem citi valorile variabilelor dintr6un fisier, nu neaparat de la tastatura. 8e exemplu, fisierul nostru executabil se numeste (ex1.exe(. 2entru a extrage datele din fisierul de intrare (in.dat(, dam comanda ex1.exe D in.dat 2utem, de asemenea, sa scriem valorile unor variabile intr6un fisier extern, sa zicem (out.dat(. ?stfel dam comanda ex1.exe @ out.dat .vident, daca se doreste atat citirea unor variabile din fisier, cat si scrierea rezultatelor in alt fisier, atunci se va da comanda ex1.exe D in.dat @ out.dat 6666666666666 Exemplu:: 6666666666666 #include Dstdio.*@ main%& E c*ar c*7
)*ile %scanf%(Kc(, Rc*& 111& E printf%(Kc(, c*&7 printf%(Kc(, c*&7 G G 66666666666666666666666666666666666666666666666 Exercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. 2resupunem ca dispunem de rezultatele din anul curent relative la cursul de sc*imb valutar dintre leu, dolar, marca si franc. ,a se scrie un program C care deseneaza %cu caractere ?,C& graficul evolutiei raportului leu:valuta, unde valuta1Edolar, marca, francG. ?poi, desenati graficul raportului dolar:marca si marca:franc. 2. ,crieti un program C care primeste la intrare un numar de secunde, si intoarce numar maxim de ore, de minute, de secunde care este ec*ivalent ca timp. 8e exemplu, '3+4 secunde este ec*ivalent cu 2 ore, 3 minute si 4 secunde. 3. "olosind o bucla )*ile, scrieti un program C care calculeaza al n6lea termen din sirul din "ibonacci. 0eamintim ca sirul lui "ibonacci este dat de recurenta liniara de ordin 25 aC11aC2117 aCEnL2G1aCEnL1GLaCn, n@11 ?tomi lexicali, operatori, sistemul C 2.1. Caractere si atomi lexicali 2.2. ?vanta<ele folosirii comentariilor 2.3. Cuvinte rezervate 2.4. dentificatori 2.!. Constante 2.$. ,iruri constante 2.'. 4peratori si semne de punctuatie 2.+. 4peratorii de precedenta si asociativitate 2.-. 4peratorii de incrementare si decrementare 2.1/. 4peratori de asignare 2.11. ,istemul C 2.12. .xercitii propuse spre implementare
111111111 Capitolul 2 111111111 111111111111111111111111111 ?tomi lexicali, operatori, sistemul C 111111111111111111111111111 Ca si alte limba<e, C are un alfabet si reguli pentru scrierea programelor corecte folosind semne de punctuatie. ?ceste reguli formeaza sintaxa limba<ului C. Compilatorul C are rolul de a testa daca un program C este corect. 8aca sunt erori, atunci va afisa o lista de mesa<e de eroare si se va opri. 8aca nu sunt erori, atunci compilatorul va (traduce( acest program in cod obiect, folosit de incarcator pentru producerea codului executabil. ;ai intai compilatorul imparte multimea caracterelor %programul sursa& in atomi lexicali, care reprezinta vocabularul de baza al limba<ului. n ?=, C %?=, 1 ?merican =ational ,tandards nstitute& sunt sase tipuri de atomi lexicali %care se mai numesc si elemente lexicale sau unitati lexicale&5 1. cuvinte rezervate %sau c*eie&7 2. identificatori7 3. constante7 4. siruri constante7 !. operatori7 $. semne de punctuatie. 6666666666666666666666666666666666 Caractere si atomi lexicali 6666666666666666666666666666666666 n fapt, un program C este o secventa de caractere. Caracterele permise in programele C sunt5 1. litere mici 5 a b ... z 2. litere mari 5 ? I ... U 3. cifre 5 / 1 ... - 4. alte caractere5 d f J : 1 % & E G N O D @ P ( S V # W K R C B A X F . , 7 5 ? !. spatii 5 blan3, ne)line si tab 666666666666666 Comentarii 666666666666666 Comentariile sunt siruri de caractere cuprinse intre :J si J:. Comentariile nu reprezinta atomi lexicali. Compilatorul va traduce comentariile intr6un singur caracter spatiu, de aceea comentariile nu fac parte din codul executabil. 66666666666 ?tentie S 2entru a verifica aceasta, puteti citi lungimea unui cod executabil %fara comentarii& si 66666666666 apoi sa comparati lungimea codului executabil obtinut dupa o noua compilare %cu comentarii&. 6666666666666666666666666666666 .xemple5 de comentarii5 6666666666666666666666666666666 1. :J un comentariu J: 2. :JJ al doilea comentariu JJ: 3. :JJJJJ: 4. :J J ?l patrulea J comentariu J: !. :JJJJJJJJJJJJJJ J ?l cincilea J J comentariu J JJJJJJJJJJJJJJ: 66666666666666666666666666666666666666666666 ?vanta<ele folosirii comentariilor5 66666666666666666666666666666666666666666666 1. 2rincipalul scop este usurarea documentarii ulterioare. ,copul documentarii este explicarea clara a folosirii programelor7 2. Uneori un comentariu poate contine informatii ce argumenteaza demonstratia corectitudinii acelui algoritm7 3. ,fat S "olositi comentariile in timpul introducerii textului programului. 66666666666666666666666 Cuvinte rezervate 66666666666666666666666 Cuvintele rezervate %c*eie& au un inteles strict insemnand un atom individual. .le nu pot fi redefinite sau utilizate in alte contexte. ata lista lor5
auto do goto signed unsigned brea3 double if sizeof void case else int static volatile c*ar enum long struct )*ile const extern register s)itc* continue float return tMpedef default for s*ort union
?numite implementari pot contine si alte cuvinte rezervate5 asm cdecl far *uge interrupt near pascal Comparativ cu alte limba<e de programare, C are un numar mic de cuvinte rezervate. ?da, de exemplu, are $2 cuvinte rezervate. ?ceasta este o caracteristica a limba<ului C de a avea doar cateva simboluri speciale si cuvinte rezervate. 66666666666666666 dentificatori 66666666666666666 Un identificator este un atom lexical compus din secventa de litere, cifre sau underscore %(C(& cu restrictia ca primul caracter este o litera sau underscore. n multe implementari C, se face distinctie dintre litere mici si mari. n general, se obisnuieste ca identificatorii sa fie scrisi cu nume sugestive care sa usureze citirea si documentarea programului. 666666666666 .xemple55 666666666666 1. 3, Cid, contor, unCidentificator sunt identificatori7 2. gresit#unu, 1//CgresitCdoi, 6plus nu sunt identificatori. dentificatorii sunt creati pentru a da nume unice pentru diverse obiecte dintr6un program. Cuvintele rezervate pot fi privite ca fiind identificatori. dentificatori precum (printf%&( sau (scanf%&( sunt de<a cunoscuti sistemului C ca fiind functii de intrare:iesire. 4 diferenta ma<ora dintre sistemele de operare si sistemele C o reprezinta lungimea admisa pentru numele identificatorilor. ?stfel, pentru unele sisteme vec*i, este acceptat un identificator al carui nume are mai mult de + caractere, dar numai primele + sunt semnificative. 8e exemplu, identificatorul C234!$'+1 este privit la fel ca C234!$'+2. n ?=, C, primele 31 de caractere sunt luate in considerare. 666666666 ?tentie S 666666666 dentificatorii care incep cu underscore pot fi confundati cu numele variabilelor sistem. 8e exemplu, identificatorul Ciob declarat in biblioteca Dstdio.*@ este folosit pentru numele unui vector de structuri. 8aca un programator foloseste un identificator cu acelasi nume, dar pentru alte scopuri, atunci ori se va semnala o eroare aparent necunoscuta, ori %si mai rau& compilatorul se va comporta ciudat. 0ecomandarea este5 =u folositi identificatori care incep cu underscore. 6666666666666 Constante 6666666666666 C manipuleaza diferite tipuri de valori. =umere precum / si 1' sunt exemple de constante intregi, iar numere precum 1./ si 3.141!- sunt exemple de constante numere zecimale. Ca si multe alte limba<e, C trateaza constantele (int( si (float( in mod diferit. Constantele caracter sunt foarte apropiate de tipul (int( %vom reveni&. Un caracter special l6am si intalnit de<a. .ste vorba de PFnP, care se mai c*eama (secventa escape(. n traducere libera, ar insemna (evadare a lui n din intelesul uzual(. n fapt, el este folosit pentru a trece cursorul curent la linie noua %ne)line&. Constantele de intregi, reali, caractere si enumerare sunt toate colectate de compilator ca fiind atomi lexicali. 8in cauza limitelor impuse de memoria masinilor, unele constante care pot fi exprimate sintactic nu pot fi disponibile pe o masina anume. 8e exemplu, numarul 1234!$'+-//////////// nu poate fi memorat ca fiind un intreg. 666666666666666666666 ,iruri constante 666666666666666666666 4 secventa de caractere incadrate intre g*ilimele, de exemplu (abc(, este un sir constant. .ste inteles de compilator ca fiind un singur atom lexical. n capitolele ulterioare, vom vedea ca de fapt sirurile constante se memoreaza ca siruri de caractere. ,irurile constante sunt tratate mereu diferit fata de constantele de tip caracter. 8e exemplu, (a( nu este totuna cu PaP. 8e mentionat ca g*ilimeaua ( reprezinta un singur caracter, nu doua. 8e aceea, daca dorim sa apara intr6un sir constant, atunci ea trebuie precedata de F %bac3slas*&. 8aca dorim ca intr6un sir sa apara F, atunci trebuie sa6l precedam tot cu F %devenind astfel FF&. 666666666666 .xemple55 666666666666 1. (sir text( 2. (( :J sirul vid J: 3. ( ( :J sir de spatii J: 4. ( a 1 b L c ( :J nu se executa nimic J: !. ( :J acesta nu este un comantariu J: ( $. ( un sir ce contine g*ilimea F( ( '. ( un sir ce contine bac3slas* FF ( +. :J (gresit( J: :J nu este un sir J: -. (gresit doi( :J nici asta nu este sir J: 8oua siruri constante care sunt separate doar printr6un spatiu vor fi concatenate de compilator intr6 unul singur. 8e exemplu, (abc( (def( este ec*ivalent cu (abcdef( ?ceasta este o trasatura a limba<ului ?=, C, nefiind disponibil in C traditional. ,irurile constante sunt tratate de compilator ca atomi lexicali. Ca si alte constante, compilatorul va rezerva spatiu in memorie pentru pastrarea sirurilor constante. 6666666666666666666666666666666666666666666 4peratori si semne de punctuatie 6666666666666666666666666666666666666666666 n C, exista multe caractere speciale cu inteles specific. 8e exemplu, operatorii aritmetici L 6 J : K reprezinta adunarea, scaderea, inmultirea, impartirea, modulul, respectiv. 0eamintim %pentru bubulici& ca a K b inseamna restul impartirii intregi a lui a la b %notatie matematica5 a mod b7 a nu se confunda modul cu valoarea absoluta&. 8e exemplu, ! K 3 are valoarea 2. ?tentie la numere intregi negative %Vezi .xercitiul 1&. ?numite simboluri au intelesuri dependente de context. Consideram simbolul K din instructiunile printf%(Kd(, a&7 si a 1 b K '7 2rimul simbol K este un format de scriere, pe cand al doilea reprezinta operatorul modul. n exemplul de mai <os, parantezele %,& se folosesc atat pentru a preciza ca %& este un operator %(main( reprezinta numele unei functii&, cat si ca semne de punctuatie. main%& E int a, b 1 2, c 1 37 a 1 1' J %b L c&7 ... G ?numite caractere speciale sunt folosite in multe contexte. "ie espresiile a L b LLa a L1 b .le folosesc caracterul L, dar LL este un singur operator, la fel ca si L1. 666666666666666666666666666666666666666666666666666666 4peratorii de precedenta si asociativitate 666666666666666666666666666666666666666666666666666666 4peratorii au reguli de precedenta si asociativitate care implica evaluarea expresiilor. 8in moment ce expresiile din interiorul parantezelor se evalueaza mai intai, este clar ca parantezele sunt folosite pentru a preciza care operatii se fac mai intai. Consideram expresia 1 L 2 J 3 n C, operatorul J are prioritate %precedenta& mai mare decat L, deci se va face intai inmultirea apoi adunarea. 8eci valoarea expresiei este '. 4 expresie ec*ivalenta este 1 L %2 J 3& 2e de alta parte, expresia %1 L 2& J3 este diferita7 ea are valoarea -. Consideram acum expresia 1 L 2 6 3 L 4 6 !. 4peratorii L si 6 au aceeasi precedenta, deci se va folosi regula de asociativitate la stanga. ?stfel %%%1 L 2& 6 3& L 4& 6! este o expresie ec*ivalenta. n continuare vom prezenta un tabel in care precizam regulile de precedenta si asociativitate pentru cativa operatori din C. B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B 4peratori B ?sociativitate B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B %& LL %postfix& 66 %postfix& B de la stanga la dreapta B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B L%unar& 6%unar& LL%prefix& 66%prefix& B de la dreapta la stanga B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B J : K B de la stanga la dreapta B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B L 6 B de la stanga la dreapta B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B B 1 L1 61 J1 :1 etc. B de la dreapta la stanga B B6666666666666666666666666666666666666666666666B6666666666666666666666666666B 9oti operatorii de pe o linie %de exemplu, J, :, K& au aceeasi prioritate intre ei, dar au prioritate mai mare decat cei ce apar in liniile de mai <os. 4peratorii L si 6 pot fi si binari si unari. 8e remarcat ca cel unar are prioritate mai mare. 8e exemplu, in expresia 6 a J b 6 c primul operator 6 este unar, pe cand al doilea binar. "olosind regulile de precedenta, se vede ca aceasta este ec*ivalenta cu %%6 a& J b& 6 c 6666666666666666666666666666666666666666666666666666666666 4peratorii de incrementare si decrementare 666666666666666666666666666666666666666666666666666666666 4peratorii de incrementare si de decrementare %LL, 66& au o prioritate foarte mare %dupa cum se poate vedea in tabelul de mai sus& si se pot asocia atat de la dreapta la stanga, cat se de la stanga la dreapta. 4peratorii LL si 66 se pot aplica variabilelor, dar nu si constantelor. ;ai mult, ei pot apare ca notatie prefixata, cat si postfixata. 8e exemplu, putem avea LLi si contorLL, dar nu putem avea 1$'LL sau LL%a J b 6 1&. "iecare din expresiile LLi si iLL au o valoare7 mai mult fiecare cauzeaza incrementarea valorii variabilei i cu o unitate. 8iferenta este5 1. expresia LLi va implica intai incrementarea lui i, dupa care expresia va fi evaluata la noua valoare a lui i7 2. expresia iLL va implica evaluarea sa la valoarea lui i, dupa care se va incrementa i. 666666666666 .xemplu55 666666666666 int a, b, c 1 /7 a 1 LLc7 b 1 cLL7 printf%(a1Kd b1Kd c1Kd LLc1KdFn(, a, b, c, LLc&7
ntrebare5 Ce se va tipari la ecran ? ntr6un mod similar, 66i va implica decrementarea valorii lui i cu 1, dupa care expresia 66i va avea noua valoare a lui i, pe cand i66 se va evalua la valoarea lui i, dupa care i se va decrementa cu 1. 0etineti deci ca, spre deosebire de L si 6, operatorii LL si 66 vor determina sc*imbarea valorii variabilei i din memorie. ,e mai spune ca operatorii LL si 66 au efect lateral %side effect&. 8aca nu folosim valoarea lui LLi sau a lui iLL, atunci acestea sunt ec*ivalente. ;ai precis, LLi7 si iLL7 sunt ec*ivalente cu i 1 i L 17
666666666666 .xemple55 666666666666 2resupunem ca avem declaratiile int a 1 1, b 1 2, c 1 3, d 1 47 ?tunci avem5 .xpresie .xpresie ec*ivalenta parantetizata Valoare
a J b : c %a J b& : c / a J b K c L 1 %%a J b& K c& L 1 3 LL a J b 6 c 66 %%LL a& J b& 6 %c 66& 1 ' 6 6 b J LL d ' 6 %%6 b& J %LL d&& 1' 66666666666666666666666666666 4peratori de asignare 6666666666666666666666666666 2entru sc*imbarea valorii unei variabile, am utilizat de<a instructiunea de asignare %atribuire&, cum ar fi a 1 b L c7 ,pre deosebire de celelalte limba<e, C trateaza 1 ca un operator. 2recedenta sa este cea mai mica dintre toti operatorii si asociativitatea sa este de la dreapta la stanga. 4 expresie de asignare simpla are forma5 variabila 1 parteCdreapta unde (parteCdreapta( este o expresie. 8aca punem 7 la sfarsitul expresiei de asignare, atunci vom obtine instructiune de asignare. 4peratorul 1 are doua argumente, (variabila( si (parteCdreapta(. Valoarea expresiei (parteCdreapta( este asignata pentru (variabila( si aceasta valoare se returneaza de catre expresia de asignare %ca un tot unitar&. 666666666666 .xemplu55 Consideram instructiunile 666666666666 b 1 27 c 1 37 a 1 b L c7 unde toate variabilele sunt de tipul int. "olosind faptul ca 1 este un operator, putem condensa aceasta la a 1 %b 1 2& L %c 1 3&7 .xplicatia este ca expresia de asignare b 1 2 atribuie valoarea 2 atat variabilei b, cat si instructiunii intregi. 8aca exemplul de mai sus pare artificial, atunci o situatie frecvent intalnita este asignarea multipla. 8e exemplu, instructiunea a 1 b 1 c 1 /7 este ec*ivalenta cu %folosind asociativitatea de la dreapta la stanga& a 1 %b 1 %c 1 /&&7 0elativ la 1, mai exista inca doi operatori. .ste vorba de L1 si 61. .xpresia 3 1 3 L 2 va aduna 2 la vec*ea valoare a lui 3 si va asigna rezultatul lui 3 si intregii expresii. .xpresia 3 L1 2 face acelasi lucru. 6666666666666666666666666666666666666666 Hista operatorilor de asignare5 1 L1 61 J1 :1 K1 @@1 DD1 R1 A1 B1 6666666666666666666666666666666666666666 9oti acesti operatori au aceeasi precedenta si se asociaza de la dreapta la stanga. ,emantica lor este specificata de variabila op1 expresie care este ec*ivalent cu variabila 1 variabila op %expresie& cu exceptia faptului ca variabila sa nu fie o expresie. 666666666666 .xemplu55 666666666666 .xpresia de asignare < J1 3 L 3 este ec*ivalenta cu < 1 < J %3 L 3& si nu cu < 1 < J 3 L 3 "ie declaratia int i 1 1, < 1 2, 3 1 3, m 1 47 Consideram urmatoarele exemple de evaluari ale expresiilor .xpresie .xpresie ec*ivalenta .xpresie ec*ivalenta Valoare i L1 < L 3 i L1 %< L 3& i 1 %i L %< L 3&& $ < J1 3 1 m L ! < J1 %3 1 %m L !&& < 1 %< J %3 1 %m L !&&& 1+ 666666666666 .xemple55 Calculul puterilor lui 2 66666666666 #include Dstdio.*@
main%& E int i 1 /, po)er 1 17
)*ile %LLi D1 1/& printf%(K$d(, po)er J12&7 printf%(Fn(&7 G esirea acestui program va fi5 2 4 + 1$ 32 $4 12+ 2!$ !12 1/24 666666666666666 ,istemul C 666666666666666 n capitolele precedente am prezentat directiva de preprocesare #include si #define. 8irectiva #include avea forma generala5 #include DnumeCfisier@ si insemna includerea in acest loc a fisierului *eader specificat din directoarele specifice C %;,6 84, FbcFinclude sau FtcFinclude, U=> :usr:include&. 4 alta forma este #include (numeCfisier( ce are drept scop inlocuirea acestei linii cu o copie a fisierului (numeCfisier( din directorul curent. 8eci, atunci cand utilizam o functie C, trebuie sa specificam prototipul ei %scanf%& si printf%& au prototipul Dstdio.*@, rand%& are prototipul Dstdlib.*@&. 666666666666 .xemplu55 666666666666 #include Dstdio.*@ #include Dstdlib.*@
main%& E int i, n7
printf%(FnKsFnKs(, (Vom afisa niste intregi aleatori.(, (Cati doriti sa vedeti ? (&7 scanf%(Kd(, Rn&7 for %i 1 /7 i D n7 LLi& E if %i K $ 11 /& printf%(Fn(&7 printf%(K12d(, rand%&&7 G printf%(Fn(&7 G 8aca de exemplu, tastam numarul 11, atunci pe ecran vor apare 11 numere intregi aleatoare. 66666666666666 4bservatii5 66666666666666 1. ?tentie S LLi D n este diferit de iLL D n7 2. 4peratorul 11 este operatorul de egalitate %test&, adica a 11 b va fi evaluata la true daca si numai daca valoarea lui a este egala cu valoarea lui b %in caz contrar va fi evaluata la false&. 3. "unctia rand%& intoarce un intreg cuprins intre / si n, unde n este dependent de sistem. n ?=, C, n este dat de constanta 0?=8C;?>. 66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. nvestigati comportarea operatorilor : si K pentru numere intregi negative. ;entionam ca in unele sisteme C, ':62 da rezultatul 63, in altele 64. Verificati daca se pastreaza identitatea din matematica %prevazuta a fi adevarata de ?=,&5 %a : b& J b L a K b 1 a ,ugestie5 ,crieti un program C care sa contina liniile de cod int a, b7 printf%(dati doi intregi nenuli5 (&7 scanf%(KdKd(, Ra, Rb&7 printf%(KsK4dFnKsK4dFnKsK4dFnKsK4dFnKsK4dFn(, ( a 1(,a, ( b 1(,b, ( a : b 1(, a : b, ( a K b 1(, a K b, (Verif. ?=,1(, %a : b& J b L a K b 6 a&7 2. ,crieti un program C care sa calculeze cel mai mare divizor comun dintre a si b, unde a, b sunt numere intregi, folosind algoritmul lui .uclid. 3. 8in moment ce L si LL sunt operatori, rezulta ca expresia aLLLb poate fi interpretata fie ca aLL L b fie a L LLb depinzand de modul de grupare semnului L. ,crieti un program scurt pentru a vedea ce interpretare face compilatorul C. 4. nlocuiti LLi cu iLL in programul de calcul a puterilor lui 2. !. Un patrat magic %de latura n& are proprietatea ca include in locatiile sale toate numerele intregi din intervalul 1, ..., nA2 si sumele numerelor de pe fiecare linie, fiecare coloana sau fiecare diagonala sunt egale. 8e exemplu5 $ 1 + ' ! 3 2 - 4 este un patrat magic de dimensiune 3. ,a se scrie un program C care testeaza daca un patrat este magic sau nu. 8e asemenea, incercati sa generati toate patratele magice de ordin n. $. ,a se scrie un program C care sa calculeze nS, unde n@/ este un numar natural %iar nS 1 1 J 2 J ... J n&. 3. Controlul instructiunilor 3.1. 4peratori relationali, de egalitate si logici 3.2. 4peratori si expresii relationale 3.3. 4peratori si expresii de egalitate 3.4. 4peratori logici si expresii logice 3.!. .valuare rapida %s*ort6circuit& 3.$. nstructiunea compusa 3.'. nstructiunea vida 3.+. nstructiunile (if( si (if6else( 3.-. nstructiunea ()*ile( 3.1/. nstructiunea (for( 3.11. 4peratorul (,( 3.12. nstructiunea (do( 3.13. nstructiunea (goto( 3.14. nstructiunile (brea3( si (continue( 3.1!. nstructiunea (s)itc*( 3.1$. 4peratorul conditional 3.1'. .xercitii propuse spre implementare 11111111 Capitolul 3 11111111 111111111111111111 Controlul instructiunilor 111111111111111111 666666666666666666666666666666666666666666666666666666 4peratori relationali, de egalitate si logici 666666666666666666666666666666666666666666666666666666 4peratori relationali 5 D, @, D1, @1 4peratori de egalitate5 11, S1 4peratori logici 5 S, RR, BB Ca si ceilalti operatori, acesti operatori au reguli de precedenta si asociativitate care determina precis modul de evaluare a acestor expresii. 66666666666666666666666666666666666666666666666666666666666666666666666666666666 B 4peratori B ?sociativitate B 66666666666666666666666666666666666666666666666666666666666666666666666666666666 %& LL %postfix& 66 %postfix& B de la stanga la dreapta B L %unar& 6 %unar& LL %prefix& 66 %prefix& B de la dreapta la stanga B J : K B de la stanga la dreapta B L 6 B de la stanga la dreapta B D D1 @ @1 B de la stanga la dreapta B 11 S1 B de la stanga la dreapta B RR B de la stanga la dreapta B BB B de la stanga la dreapta B ?5 B de la dreapta la stanga B 1 L1 61 J1 :1 etc B de la dreapta la stanga B , %operatorul virgula& B de la stanga la dreapta B 6666666666666666666666666666666666666666666666666666666666666666666666666666666 4peratorul S este unar, spre deosebire de toti operatori %relationali, de egalitate si logici& care sunt binari. 9oti operatorii vor fi prezenti in expresii ce pot lua valoarea intreaga 1 sau /. ;otivul este ca C reprezinta (false( orice expresie egala cu zero, si (true( orice expresie diferita de zero. 666666666666 Exemple: n continuare, dam o lista de expresii ce se evaluaza la false 666666666666 1. 4 expresie de tip int ce are valoarea /7 2. 4 expresie de tip float ce are valoarea /./7 3. Caracterul null PF/P7 4. 2ointerul =UHH. 66666666666666666666666666666666666666666 4peratori si expresii relationale 66666666666666666666666666666666666666666 ?m vazut ca operatorii D, @, D1, @1 sunt toti binari. .xpresiile ce contin acesti operatori pot lua valoarea / sau 1. 66666666666 .xemple. 2rimele patru exemple sunt corecte, restul sunt gresite5 66666666666 1. a D 3 2. a @ b 3. 61.1 @1 %2.2 J x L 3.3& 4. a D b D c %corecta, dar confuza& !. a 1D b $. a D 1 b '. a @@ b "ie expresia relationala (a D b(. 8aca valoarea lui a este mai mica decat valoarea lui b, atunci expresia va avea valoarea 1, pe care o gandim ca fiind (true(. 8aca valoarea lui a este mai mare decat valoarea lui b, atunci expresia va avea valoarea /, pe care o gandim ca fiind (false(. 4bservam ca valoarea lui (a D b( este aceeasi cu valoarea lui (a 6 b D /(. "olosind precedenta operatorilor aritmetici, aceasta este deci ec*ivalenta cu (%a 6 b& D /(. 8e altfel, pe multe masini, expresii cum sunt (a D b( sunt implementate ca fiind (a 6 b D /(. 66666666666 Exemple: Vom considera urmatorul tabel cu declaratii si initializari. 66666666666 2resupunem ca avem declaratiile5 int i 1 1, < 1 2, 3 1 37 double x 1 !.!, M 1 '.'7 6666666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 6666666666666666666666666666666666666666666666666666666666666666666666 i D < 6 3 i D %< 6 3& / 6 i L ! J < @1 3 L 1 %%6 i& L %! J <&& @1 %3 L 1& 1 x 6 M D1 < 6 3 61 %x 6 M& D1 %%< 6 3& 6 1& 1 x L 3 L ' D M : 3 %%x L 3& L '& D %M : 3& / B6666666666666666666666B666666666666666666666666666666666B6666666666666B 666666666666666666666666666666666666666666 4peratori si expresii de egalitate 66666666666666666666666666666666666666666 .xpresiile pot contine si operatorii de egalitate 11 si S1. .xpresiile ce le contin au valoarea / sau 1. 66666666666 .xemple. 2rimele trei exemple sunt corecte, restul sunt gresite5 66666666666 1. c 11 P?P 2. 3 S1 62 3. x L M 11 2 J x 6 ! 4. a 1 b !. a 1 1 b 6 1 $. %x L M& 1S 44 ntuitiv, o expresie de egalitate cum ar fi a 11 b este sau (true( sau (false(. ;ai precis, daca a este egal cu b, atunci a 11 b intoarce valoarea 1 %true&7 altfel, aceasta intoarce valoarea / %false&. 4 expresie ec*ivalenta este a 6 b 11 / %aceasta este ceea ce se implementeaza la nivel masina&. .xpresia (a S1 b( ilustreaza folosirea operatorului (diferit de( %sau (nu este egal cu(&. 66666666666 Exemple: Vom considera urmatorul tabel cu declaratii si initializari. 66666666666 2resupunem ca avem declaratiile5 int i 1 1, < 1 2, 3 1 37 6666666666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 6666666666666666666666666666666666666666666666666666666666666666666666666 i 11 < < 11 i / i S1 < < S1 i 1 i L < L 3 11 6 2 J 6 3 %%i L <& L 3& 11 %%62& J %6 3&& 1 6666666666666666666666666B666666666666666666666666666666666666B6666666666B 666666666666666666666666666666666666666666 4peratori logici si expresii logice 666666666666666666666666666666666666666666 4peratorul logic S este unar, iar RR si BB sunt binari. .xpresiile ce contin acesti operatori intorc valoarea / sau 1. =egarea logica poate fi aplicata unei expresii aritmetice sau unui tip pointer. 8aca o expresie are valoarea /, atunci expresia negata are valoarea 1. 8aca expresia are o valoare diferita de /, atunci expresia negata intoarce valoarea 1. 66666666666 .xemple. 2rimele trei exemple sunt corecte, restul sunt gresite5 66666666666 1. Sa 2. S%x L '.'& 3. S%a D b BB c D d& 4. aS !. a S1 b %este corecta, dar se refera la operatorul (diferit(& Unele identitati logice %din matematica& nu se (transmit( in C. 8e exemplu, se stie ca (not %not s& 1s(, in timp ce valoarea lui (SS!( nu este !, ci 1. ;otivul este ca operatorul (S( se asociaza de la dreapta la stanga, si deci (SS!( este ec*ivalent cu (S%S!&(, care ec*ivalent cu (S%/&(, ce intoarce valoarea 1. 666666666666 Exemple: Vom considera urmatorul tabel cu declaratii si initializari. 666666666666 2resupunem ca avem declaratiile5 int i 1 ', < 1 '7 double x 1 /./, M 1 ---.-7 66666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 66666666666666666666666666666666666666666666666666666666666666666666 S %i 6 <& L 1 %S %i 6 <&& L 1 2 S i 6 < L 1 %%S i& 6 <& L 1 6$ S S %x L 3.3& S %S %x L 3.3&& 1 S x J S S M %S x& J %S %S M&& 1 6666666666666666666666B666666666666666666666666666666B6666666666666B 4peratorii logici binari RR si BB pot fi folositi in expresii care intorc / sau 1. 66666666666 .xemple. 2rimele patru exemple sunt corecte, restul sunt gresite5 66666666666 1. a RR b 2. a BB b 3. S%a D b& RR c 4. 3 RR %62 J a L '& !. a RR $. a B B b '. a R b %corecta, dar se refera la operatii peste biti& +. Rb %corecta, dar se refera la adresa lui b&66666666666 Exemple: Vom considera urmatorul tabel cu declaratii si initializari. 66666666666 2resupunem ca avem declaratiile5 int i 1 3, < 1 3, 3 1 37 double x 1 /./, M 1 2.37 66666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 66666666666666666666666666666666666666666666666666666666666666666666 i RR < RR 3 %i RR <& RR 3 1 x BB i RR < 6 3 x BB %i RR %< 6 3&& / i D < RR x D M %i D <& RR %x D M& / i D < BB x D M %i D <& BB %x D M& 1 B6666666666666666666666B666666666666666666666666666666666B666666666666B 66666666666666666666666666666666666666 .valuare rapida %s*ort6circuit& 66666666666666666666666666666666666666 2entru expresiile ce contin RR sau BB, evaluarea are loc cand s6a stabilit de<a valoarea expresiei, eventual fara parcurgerea intregii expresii. ?stfel, presupunem ca (expr1( se evalueaza la / %false&. ?tunci expresia expr1 RR expr2 se va evalua la /, fara a se mai face evaluarea expresiei (expr2(. ?lt exemplu, daca (expr1( se evalueaza la 1 %true&, atunci expresia expr1 BB expr2 se va evalua la true fara a se mai evalua expresia (expr2(. Uneori se mai spune ca operatorii RR si BB sunt lazM %adica le este lene sa mai evalueze toti operanzii din expresie&. 66666666666666666666666666666 nstructiunea compusa 66666666666666666666666666666 4 instructiune compusa este un sir de declaratii si instructiuni delimitate de acolade. Ceea ce acoladele delimiteaza se numeste (bloc(. 4 instructiune compusa este ea insasi o instructiune. 66666666666 Exemplu: 66666666666 E a 1 17 E b 1 27 c 1 37 G G 6666666666666666666666666 nstructiunea vida 6666666666666666666666666 nstructiunea vida se reprezinta cu semnul 7 %punct si virgula&. .a se foloseste cand se doreste folosirea ei sintactica, si nu neaparat folosire semantica. 8upa cum vom vedea, aceasta se foloseste in constructii (if6else( si (for(. 4 expresie urmata de 7 se numeste (instructiune expresie(. 66666666666 Exemplu: 66666666666 a 1 b7 a L b L c7 7 printf%(KdFn(, a&7 66666666666666666666666666666666666666 nstructiunile (if( si (if6else( 66666666666666666666666666666666666666 "orma generala a instructiunii (if( este if %expresie& instructiune ,emantica intuitiva este simpla. ?stfel, daca valoarea expresiei este true %diferita de zero&, atunci se executa instructiunea, altfel nu. 66666666666 Exemplu: 66666666666 nstructiunea (if( de mai <os va testa daca se poate face impartirea cu M %ce trebuie sa fie diferit de /&5 if %M S1 /./& x :1 M7 Urmatoarele doua instructiuni if %< D 3& min 1 <7 if %< D 3& printf%(< este mai mic decat 3Fn(&7 se pot scrie intr6una singura if %< D 3& E min 1 <7 printf%(< este mai mic decat 3Fn(&7 G nstructiunea (if6else( de mai <os este foarte apropiata de instructiunea (if(. ?ceasta are forma generala if %expresie& instructiune1 else instructiune2 ,emantica intuitiva este de asemenea clara. 8aca valoarea expresiei este diferita de zero, atunci se executa instructiune1 si (se sare( peste instructiune2. 8aca valoarea expresiei este zero, atunci (se sare( instructiune1, si se executa instructiune2. 666666666666 Exemplu: 666666666666 Urmatorul subprogram C de mai <os calculeaza si afiseaza minimul dintre x si M. if %x D M& min 1 x7 else min 1 M7 printf%(Valoarea minima 1 KdFn(, min&7 66666666666666666666666666666 nstructiunea ()*ile( 66666666666666666666666666666 (Y*ile(, (for( si (do( sunt cele trei instructiuni repetitive din limba<ul C. Consideram urmatorul format general al instructiunii ()*ile( %iteratia sau bucla ()*ile(&. )*ile %expresie& instructiune instructiuneCurmatoare ;ai intai se evalueaza expresie. 8aca aceasta nu este zero %deci este (true(&, atunci se executa instructiunea, si control trece la inceputul buclei ()*ile(. ?stfel, corpul buclei se executa de cate ori expresie se evalueaza la (true(. 9erminarea buclei are loc cand expresie ia valoarea zero %adica (false(&. n acest punct, controlul se paseaza catre (instructiuneCurmatoare(. 66666666666 Exemplu:66666666666 )*ile %i D1 1/& E suma L1 i7 LLi7 G 66666666666666666666666666 nstructiunea (for( 6666666666666666666666666 Ca si instructiunea ()*ile(, instructiunea (for( se foloseste pentru descrierea structurilor iterative %repetitive&. ?stfel constructia for %expresie17 expresie27 expresie3& instructiune instructiuneCurmatoare este semantic ec*ivalenta cu expresie17 )*ile %expresie2& E instructiune7 expresie37 G instructiuneCurmatoare7 8eci, se va evalua expresie1. 8e obicei, aceasta se foloseste pentru initializarea buclei. ?poi, se evalueaza expresie2. 8aca aceasta nu este zero %(true(&, atunci se executa instructiune, se evalueaza expresie3, si controlul buclei se (paseaza( la inceputul buclei %cu deosebirea ca nu se mai evalueaza expresie1&. 8e obicei, expresie2 este o expresie logica care controleaza bucla. ?cest proces continua pana cand expresie2 este / %false&, punct in care se plaseaza controlul catre instructiuneCurmatoare. 666666666666 Exemplu: .xemplul de mai <os calculeaza factorialul numarului n. 666666666666 factorial117 for %i 1 17 i D1 n7 iLL& factorial J1 i7 4rice sau toate expresiile dintr6o instructiune (for( pot lipsi, dar nu poate lipsi 7. 66666666666 Exemple: 66666666666 .xemplul de mai <os calculeaza suma numerelor intregi de la 1 la 1/. i 1 17 suma 1 /7 for % 7 i D1 1/7 LLi& suma L1 i7 ?cesta se poate scrie ec*ivalent5 i 1 17 suma 1 /7 for % 7 i D1 1/7 & suma L1 iLL7 8aca, in sc*imb, lipseste expresie2, atunci obtinem o bucla infinita. 666666666666666666666 4peratorul (,( 666666666666666666666 4peratorul (,( are cea mai mica prioritate dintre toti operatorii din C. .ste un operator binar ce are ca operanzi drept expresii si se asociaza de la stanga la dreapta. ntr6o expresie de forma expresie1 , expresie2 se evalueaza mai intai expresie1, apoi expresie2. .xpresia (,( intoarce valoarea si tipul operandului din dreapta. 66666666666 Exemplu: 2resupunem ca a, b sunt de tip int. ?tunci expresia (,( 666666666666 a 1 /, b 1 1 intoarce valoarea 1 de tipul int. 4peratorul (,( este deseori folosit in instructiunea (for(. 6666666666 Exemplu: .xemplul de mai <os calculeaza factorialul numarului n %reluare&. 66666666666 for %factorial 1 1, i 1 17 i D1 n7 iLL& factorial J1 i7 666666666666 Exemplu: 0evenim asupra unui exemplu precedent %suma primelor = numere naturale& 666666666666 for %suma 1 /, i 1 17 i D1 n7 LLi& suma L1 i7 se poate scrie, ec*ivalent, in for %suma 1 /, i 1 17 i D1 n7 suma L1 i, LLi&7 6666666666666 ntrebare5 Ce se intampla cu valoarea lui suma daca intervertim instructiunile 666666666666 suma L1 i cu LLi 66666666666 Exemplu: 66666666666 for %i1/, p 1 *ead7 p S1 =UHH7 p1p 6@ next & ..... 666666666666666666666666 nstructiunea (do( 66666666666666666666666 nstructiunea (do( poate fi considerata o varianta a instructiunii ()*ile(. 8eosebirea consta in faptul ca pentru instructiunea ()*ile( testul se face la inceputul ciclului, iar pentru (do( la sfarsit. Consideram constructia de forma do instructiune )*ile %expresie&7 instructiuneCurmatoare Ha inceput se executa instructiune, apoi se evalueaza expresie. 8aca valoarea lui expresie este diferita de / %(true(&, atunci controlul se paseaza la inceputul instructiunii (do(, si procesul se repeta. 8aca expresie se evalueaza la / %false&, atunci controlul se paseaza la instructiuneCurmatoare. 66666666666 Exemplu: ,uma unor numere intregi diferite de / 66666666666 suma 1 i 1 /7 do E suma L1 i7 scanf%(Kd(, Ri&7 G )*ile %i @ /&7 66666666666666666666666666 nstructiunea (goto( 6666666666666666666666666 nstructiunea (goto( %salt neconditionat& este considerata opusa programarii structurate. ,fatul general valabil este evitarea acestei instructiuni. 9otusi, in unele cazuri se poate folosi %cand simplifica controlul, cand face codul mai eficient&. 4 instructiune de etic*etare are forma5 etic*eta 5 instructiune unde etic*eta este un identificator. 666666666666 Exemple: 666666666666 bMe5 exit%1&7 etic*eta15 a 1 b L c7 3335 a 1 b L c7 %exemplu gresit, de ce ?& Controlul programului poate fi transferat neconditionat catre o instructiune de etic*etare astfel goto etic*eta7 6666666666666666666666666666666666666666666666 nstructiunile (brea3( si (continue( 6666666666666666666666666666666666666666666666 Cele doua instructiuni brea37 si continue7 intrerup controlul normal al programelor. nstructiunea (brea3( va cauza iesirea din bucla in care se afla sau din instructiunea (s)itc*(. nstructiunea (continue( se poate afla numai in instructiuni (for(, ()*ile( si (do(. .a are rolul de a trasmite controlul catre sfarsitul buclei respective. 66666666666 Exemple: 66666666666 )*ile %1& E scanf%(Klf(, Rx&7 if %x D /./& brea37 :J iesim cand x este negativ J: printf%(KlfFn(, sZrt%x&&7 G )*ile %contor D n& E scanf%(Klf(, Rx&7 if %x @ 6/./1 RR x D 1/./1& continue7 :J valorile mici nu se iau in considerare J: LLcontor7 suma L1 x7 G 666666666666666666666666666666 nstructiunea (s)itc*( 66666666666666666666666666666 (s)itc*( este o instructiune conditionala ce generalizeaza o instructiune (if6else(. 66666666666 Exemplu: 66666666666 s)itc* %val& E case 15 LLcontorCa7 brea37 case 25 case 35 LLcontorCb7 brea37 default5 LLcontorCc7 G Corpul unei instructiuni (s)itc*( este un exemplu de instructiune compusa. .xpresia de control dintre paranteze %ce urmeaza cuvantului s)itc*& trebuie sa fie de tip integral %vom reveni intr6un alt capitol&. 8upa evaluarea lui val, controlul sare la etic*eta corespunzatoare valorii lui val. 8e obicei, ultima instructiune dintr6un (case( este de obicei (brea3(. 8aca nu exista (brea3(, atunci se vor executa si instructiunile din urmatoarele (case(6uri. ?tentie S 4miterea scrierii lui (brea3( este foarte frecventa SS 2oate apare cel mult un (default( %in general pe ultima pozitie&. Cuvintele rezervate (case( si (default( pot apare numai in interiorul unui (s)itc*(. 666666666666666666666666666666 4peratorul conditional 666666666666666666666666666666 4peratorul (?5( este mai putin obisnuit deoarece este ternar %cu trei argumente&. "orma generala este expresie1 ? expresie2 5 expresie3 ;ai intai, se evalueaza expresie1. 8aca aceasta este diferita de / %true&, atunci se evalueaza expresie2, si aceasta va fi valoarea returnata de intreaga expresie conditionala. 8aca expresie1 este / %false&, atunci se evalueaza expresie3, si aceasta va fi valoarea intregii expresii conditionale. 666666666666 Exemplu: nstructiunea 66666666666 if %M D z& x 1 M7 else x 1 z7 este ec*ivalenta cu x 1 %M D z& ? M 5 z7 4peratorul ?5 are aceeasi prioritate cu operatorul de asignare si se asociaza de la dreapta la stanga. 66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. ,a se scrie un program care sa calculeze minimul a trei numere %folosind o instructiune (if6t*en( si una (if( sau doua (if6t*en( %fara variabila suplimentara&&. Qeneralizare5 ,a se gaseasca primele doua numere %cele mai mici& dintr6un vector de n elemente %cu numar minim de comparatii&. 2. Cititi n numere de la tastatura si afisati maximul lor. ncercati sa cititi un numar arbitrar de numere %deci fara a citi acest n&. 3. "olosind structura for, scrieti un program care calculeaza urmatoarele formule logice %sub forma unei tabele de adevar&5 b1 BB b3 BB b! si b1 RR b2 BB b4 RR b! 4. "ie functia lui Collatz5 E n:2 daca n este par f%n& 1 E 3JnL1 daca n este impar ,a se scrie un program C care determina 3 natural minim astfel incat %f o f o ... o f&%n&11. de 3 ori !. ,crieti un program C care calculeaza suma divizorilor naturali ai unui numar natural n. Un numar este perfect daca este egal cu suma divizorilor proprii pozitivi %ex5 2+ 1 1 L 2 L 4 L ' L 14&. ,a se genereze primele 3 numere perfecte %3 D ! S&. $. 4peratia matematica min%x,M& se poate reprezenta ca o expresie conditionala5 %x D M& ? x 5 M ntr6un mod similar, descrieti operatiile aritmetice min%x, M, z& si max%x, M, z, t& '. ,e stie ca un procedeu de intersc*imbare a valorii a doua variabile %a si b& se poate face folosind o variabila auxiliara %se foloseste in metodele de sortare, arbori, sisteme de ecuatii, etc&5 aux 1 a 7 a 1 b 7 b 1 aux7 ,a se arate ca in limba<ul C se poate face acest lucru in mod ec*ivalent fara utilizarea explicita a unei variabile suplimentare. ?sadar intervertirea valorilor a si b se poate face si astfel5 a 1 b L a 6 %b 1 a&7 ?ratati ca aceasta instructiune este ec*ivalenta cu5 aux 1 b L a 7 b 1 a 7 a 1 aux 6 a7 %sau a 1 aux 6 b7& .c*ivalent, fara variabile suplimentare, se pot considera instructiunile5 a 1 a L b7 b 1 a 6 b7 a 1 a 6 b7 "unctii si programare structurata 4.1. ?pelul functiilor 4.2. nstructiunea (return( 4.3. 2rototipurile functiilor 4.4. 8escriere (top6do)n( 4.!. nvocare si apel prin valoare 4.$. 8eosebirea dintre (return( si (exit( 4.'. .xercitii propuse spre implementare
11111111 Capitolul 4 11111111 1111111111111111111111111 "unctii si programare structurata 1111111111111111111111111 2rogramarea structurata este o problema ce rezolva strategia si metodologia programarii si are urmatoarele principii5 1. ,tructurile de control trebuie sa fie cat se poate de simple7 2. Constructia unui program trebuie sa fie descrisa top6do)n. 8escrierea top6do)n se refera la descompunerea problemei noastre in subprobleme. 8e obicei, aceste subprobleme sunt usor de descris. 666666666666666666666 ?pelul functiilor 666666666666666666666 Un program este compus din una sau mai multe functii, printre care si (main%&(. ntotdeauna executia unui program incepe cu (main%&(. Cand o functie este apelata %sau invocata& atunci controlul programului este pasat functiei apelate. 8upa ce aceasta isi termina executia, atunci se paseaza inapoi controlul catre program. Codul C care descrie ce face o functie se numeste (definitia functiei(. ?ceasta are urmatoarea forma generala5 tip numeCfunctie %listaCparametri& E declaratii instructiuni G 2rimul rand se numeste (*eader6ul( %antetul& functiei, iar ceea ce este inclus intre acolade se numeste corpul functiei. 8aca in antet nu precizam parametri, atunci se va scrie (void( %cuvant rezervat pentru lista vida&. 8aca functia nu intoarce nici o valoare, atunci se va scrie ca tip intors tot (void(. 9ipul intors de functie este cel precizat in (return( %ce va fi indata explicat&. 2arametrii din antetul functiei sunt dati printr6o lista cu argumente separate prin virgula. ?ceste argumente sunt date de tipul argumentului urmat de un identificator ce apartine acelui tip. ,e mai spune ca acel identificator este (parametru formal(. 66666666666 .xemplu5 66666666666 #include Dstdio.*@ void tiparesteCmesa<%int 3& E int i7 printf%(ti urez5Fn(&7 for %i 1 /7 i D 37 LLi& printf%( 4 zi buna S Fn(&7 G
main%& E int n7 printf%(8ati un numar natural mic5 (&7 scanf%(Kd(, Rn&7 tiparesteCmesa<%n&7 G 666666666666666666666666666666 nstructiunea (return( 666666666666666666666666666666 nstructiunea (return( este folosita pentru doua scopuri. Cand se executa o instructiune (return(, controlul programului este pasat inapoi programului apelant. n plus, daca exista o expresie dupa acest (return(, atunci se va returna valoarea acestei expresii. nstructiunea (return( poate avea formele5 return7 sau return expresie7 66666666666 .xemplu5 ;inimul a doi intregi. 66666666666 #include Dstdio.*@ int min%int x, int M& E if %x D M& return x7 else return M G
main%& E int <, 3, m7
printf%(8ati doi intregi5 (&7 scanf%(KdKd(, R<, R3&7 m 1 min%<, 3&7 printf%(FnKd este minimul dintre Kd si Kd.Fn(, m, <, 3&7 G 666666666666666666666666666666 2rototipurile functiilor 666666666666666666666666666666 n C, apelul unei functii poate apare inaintea declararii ei. "unctia poate fi definita mai tarziu in acelasi fisier, sau in alt fisier sau dintr6o biblioteca standard. n ?=, C, prototipul functiei remediaza problema punand la dispozitie numarul si tipul argumentelor functiei. 2rototipul specifica, de asemenea, si tipul returnat de functie. ,intaxa prototipului unei functii este5 tip numeCfunctie %listaCtipuriCparametri&7 n lista de parametri putem specifica c*iar si parametrul, dar asta este optional. 8aca functia nu are parametri, atunci se foloseste (void(. 66666666666 .xemplu5 0eluam un exemplu precedent. 66666666666 #include Dstdio.*@ main%& E int n7 void tiparesteCmesa<%int&7
printf%(8ati un numar natural mic5 (&7 scanf%(Kd(, Rn&7 tiparesteCmesa<%n&7 G
void tiparesteCmesa<%3& E int i7
printf%(ti urez5Fn(&7 for %i 1 /7 i D 37 LLi& printf%( 4 zi buna S Fn(&7 G 2rototipul unei functii poate fi plasat in corpul altei functii, sau de regula, se scriu la inceputul programelor dupa directivele #include si #define. 6666666666666666666666666666 8escriere (top6do)n( 6666666666666666666666666666 2resupunem ca avem de citit cativa intregi si trebuie sa6i afisam in ordine pe coloane %in capatul de sus al coloanelor trebuie sa scriem numele campului&, sa le afisam suma lor partiala, minimul si maximul lor. 2entru scrierea unui program C ce face acest lucru, vom utiliza proiectarea %descrierea& (top6do)n(. ?stfel, descompunem problema in urmatoarele subprobleme5 1. Un antet pentru problema data7 2. ,crierea campurilor7 3. Citirea si scrierea lor pe coloane. 9oti acesti trei pasi vor fi descrisi in cate o functie ce se apeleaza din (main%&(. 4btinem, un prim cod5 #include Dstdio.*@
main%& E void tiparesteCantet%void&7 void scrieCcampurile%void&7 void citesteCscrieCcoloanele%void&7
tiparesteCantet%&7 scrieCcampurile%&7 citesteCscrieCcoloanele%&7 G
?ceasta reprezinta intr6un mod foarte simplu descrierea (top6do)n(. 8aca o problema este prea grea, atunci o descompunem in subprobleme, si apoi le rezolvam pe acestea. Ieneficiul suplimentar al acestei metode este claritatea sa. void tiparesteCantet%void& E printf%(FnKsKsKsFn(, (JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFn(, (J Calculul sumelor, minimului si maximului JFn(, (JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJFn(&7 G
"unctia ce foloseste la scrierea campurilor este la fel usor de scris5 void scrieCcampurile%void& E printf%(K!sK12sK12sK12sK12sFnFn(, (=umar(, (?rticol(, (,uma(, (;inimul(, (;aximul(&7 G Urmeaza apoi functia ce serveste la scrierea inregistrarilor referitoare la campurile discutate mai sus5 void citesteCscrieCcoloanele%void& E int contor 1 /, articol, suma, minim, maxim7 int min%int, int&, max%int, int&7
if %scanf%(Kd(, Rarticol& 11 1& E LLcontor7 suma 1 minim 1 maxim 1 articol7 printf%(K!dK12dK12dK12dK12dFnFn(, contor, articol, suma, minim, maxim&7 )*ile %scanf%(Kd(, Rarticol& 11 1& E LLcontor7 suma L1 articol7 minim 1 min%articol, minim&7 maxim 1 max%articol, maxim&7 printf%(K!dK12dK12dK12dK12dFnFn(, contor, articol, suma, minim, maxim&7 G G else printf%(=ici o data nu a fost citita.FnFn(&7 G 8aca datele se introduc de la tastatura, atunci tabelul se va afisa (intrerupt( de citirile ce au loc de la tastatura. ?stfel, se prefera citirea dintr6un fisier extern. 2resupunem ca fisierul nostru executabil %asociat fisierului sursa scris in C& se numeste (numere.exe( si am creat un fisier numit (fisier.int( ce contine urmatoarele numere5 1- 23 6' 2- 611 1' 8and comanda numere D fisier.int vom obtine un tabel ce contine toate datele dorite. 6666666666666666666666666666666666666 nvocare si apel prin valoare 6666666666666666666666666666666666666 4 functie este invocata prin scrierea numelui sau impreuna cu lista sa de argumente intre paranteze. 8e obicei, numarul si tipul acestor argumente se (potriveste( cu parametrii din lista de parametri prezenti in definitia functiei. 9oate argumentele sunt apelate prin valoare %(call6bM6value(&. ?sta inseamna ca fiecare argument este evaluat si valoarea sa este folosita ca valoare pentru parametrul formal corespunzator. 8e aceea, daca o variabila %argument& este folosita la transmiterea unei valori, atunci valoarea ei nu se sc*imba. 66666666666 .xemplu5 66666666666 #include Dstdio.*@ main%& E int n13, suma, calculeazaCsuma%int&7
printf%(KdFn(, n&7 :J se va scrie 3 J: suma 1 calculeazaCsuma%n&7 printf%(KdFn(, n&7 :J se va scrie 3 J: printf%(KdFn(, suma&7 :J se va scrie $ J: G
int calculeazaCsuma%int n& :J suma numerelor de la 1 la n J: E int suma 1 /7 for % 7 n @ /7 66n& :J n se sc*imba aici, dar nu si in main%& J: sum L1 n7 printf%(KdFn(, n&7 :J se va scrie / J: return suma7 G C*iar daca n este trimis ca argument in functia (calculeazaCsuma%&( si valoarea lui n se modifica in aceasta functie, valoarea sa din mediul apelant ramane nesc*imbata. Vom vedea mai tarziu cum se poate simula apelul prin adresa %(call6bM6reference(&. 6666666666666666666666666666666666666666666666 8eosebirea dintre (return( si (exit( 6666666666666666666666666666666666666666666666 .xista doua procedee de a returna o valoare. return expresie si exit%expresie& 8aca se folosesc in (main%&(, atunci acestea sunt ec*ivalente, dar in orice alta functie efectul lor este diferit %in ?=, C, functia (main%&( intoarce o valoare de tip int&. Un apel al lui exit%& in orice alta functie va implica terminarea executiei programului si returnarea valorii catre mediul apelant %sistemul de operare sau mediul de programare C&. Valoarea returnata se numeste stare de iesire %(exit status(&. 2rin conventie, starea de iesire zero indica terminare cu succes, pe cand iesire cu un numar diferit de zero indica o situatie anormala. 66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. "olosind functiile (rand%&(, (min%,&( si (max%,&(, sa se genereze n numere naturale si sa se afiseze minimul si maximul dintre acestea. 2. %Tocul cap6pa<ura, simulare ;onte6Carlo& 2resupunem ca dispunem de o moneda ideala %nemasluita&. 8oi <ucatori arunca cu moneda dupa urmatoarele reguli5 1.a. ,e fac un numar total de n aruncari7 1.b. 2rimul <ucator arunca moneda si celalalt spune (cap( sau (pa<ura(7 1.c. 8aca acesta (g*iceste( ce va pica moneda, atunci se inverseaza <ucatorii %adica arunca al doilea si primul incearca sa g*iceasca&7 1.d. Ha sfarsit, trebuie afisat scorul %si procentul de castig al fiecaruia&. 3. %Con<ectura lui Qoldbac*& 4rice numar par mai mare decat 2 se poate scrie ca suma a doua numere prime. ,crieti un program C care verifica aceasta con<ectura pentru numere situate intre m si n. 8e exemplu, daca m1'// si n111//, atunci afisati5 '// 1 1' L $+3 '/2 1 11 L $-1 '/4 1 3 L '/1 ... 1/-+ 1 ! L 1/-3 11// 1 3 L 1/-' Qeneralizare5 ,crieti toate combinatiile posibile de adunare a doua numere prime egal cu un numar dat. 2rocesarea caracterelor !.1. 9ipul de data (c*ar( !.2. Utilizarea lui (getc*ar%&( si (putc*ar%&( !.3. Iiblioteca DctMpe.*@ !.4. Un exemplu util5 =umararea cuvintelor !.!. .xercitii propuse spre implementare
11111111 Capitolul ! 11111111 111111111111111111 2rocesarea caracterelor 111111111111111111 666666666666666666666666666 9ipul de data (c*ar( 666666666666666666666666666 .ste unul dintre tipurile fundamentale din limba<ul C. Constantele si variabilele de acest tip sunt folosite pentru reprezentarea caracterelor. "iecare caracter este memorat pe 1 bMte %octet&, care %in general& este compus din + biti. Un octet compus din + biti poate pastra 2A+12!$ valori distincte. Cand memoram un caracter intr6un octet, continutul acestuia poate fi gandit ca un caracter sau un intreg mic %intre / si 2!!&. 8esi putem memora 2!$ valori distincte, doar o parte din ele sunt tiparibile %litere mici, mari, cifre, semne de punctuatie, spatiu, tab, caractere speciale L, J, K&. .xemple de caractere netiparibile5 ne)line, bell. 4 constanta caracter se scrie intre apostroafe, cum ar fi5 PaP, PbP. 4 declaratie obisnuita a unei variabile de tip caracter este5 c*ar c7 Variabilele caracter se pot initializa astfel5 c*ar c1 1 P?P, c2 1 PJP7 Un caracter este pastrat in memorie pe un octet dupa o codificare specifica. ;ulte masini folosesc codurile de caractere ?,C sau .IC8C. =e vom referi numai la codul ?,C. ?stfel, vom preciza constanta caracter si valoarea corespunzatoare a sa5 de la 2A!L2A4 pana la !', in ordine5 P/P, P1P, ..., P-P de la 2A$L2A/ pana la -/, in ordine5 P?P, PIP, ..., PUP de la 2A$L2A!L2A/ pana la 112, in ordine5 PaP, PbP, ..., PzP 8e exemplu, se observa ca pentru a obtine litere mici din cele mari, sc*imbam doar un bit. ?stfel, caracterul P?P are codul $! care inseamna numarul /1/////1 in baza 2, iar caracterul PaP are codul /11////1. ,e observa ca difera doar bitul cu numarul 3.
66666666666 .xemple5 66666666666 n functiile (printf%&( si (scanf%&(, pentru formatul caracter se foloseste Kc. printf%(Kc(, PaP&7 va tipari a printf%(KcKcKc(, P?P, PIP, PCP&7 va tipari ?IC printf%(Kd(, PaP&7 va tipari -' printf%(Kc(, -'&7 va tipari a ?numite caractere netiparibile necesita (secvente escape( %F reprezinta caracterul escape&. n acest sens, dam un tabel =umele caracterului ;odul de scriere Valoarea intreaga alert Fa ' bac3slas* FF -2 bac3space Fb + carriage return Fr 13 g*ilimea F( 34 formfeed Ff 12 tab orizontal Ft - ne)line Fn 1/ caracterul nul F/ / apostrof FP 3- tab vertical Fv 11
66666666666 .xemple5 Ce va fi afisat in cazul urmatoarelor instructiuni ? 66666666666 1. printf%(F(?ICF((&7 2. printf%(P?ICP(&7 Un alt mod de a scrie o constanta caracter este folosind una, doua sau trei cifre octale ca secvente escape, cum ar fi PF//'P. ?cest PF//'P este de fapt caracterul (alert( %sau clopotel&. .l mai poate fi scris PF/'P sau PF'P sau Fa.
6666666666666666666666666666666666666666666666666666 Utilizarea lui (getc*ar%&( si (putc*ar%&( 6666666666666666666666666666666666666666666666666666 ?ceste functii sunt folosite pentru citirea si scrierea caracterelor si sunt definite in Dstdio.*@. ?stfel pentru citirea unui caracter de la tastatura se foloseste (getc*ar%&(, iar pentru scrierea unui caracter pe ecran (putc*ar%&(. Iineinteles ca daca dorim sa afisam un sir de caractere mai mare, este mai elegant cu functia (printf%&(.
66666666666 .xemplu5 66666666666 Urmatorul program citeste un caracter din intrare %tastatura& si il atribuie unei varibile de tip c*ar, apoi il afiseaza pe ecran. #include Dstdio.*@ main%& E c*ar c7
)*ile %1& E c1getc*ar%&7 putc*ar%c&7 G G
,ingurul mod de a opri acest program este sa apasam C90HAC. 2utem reface acest program folosind constanta .4". #include Dstdio.*@ main%& E int c7
)*ile %%c 1 getc*ar%&& S1 .4"& E putc*ar%c&7 G G
66666666666666 Comentarii5 66666666666666 1. n biblioteca Dstdio.*@, exista o linie in care se declara #define .4" %61& 8enumirea lui .4" provine de la (end6of6file(. 2. Variabila c trebuie sa fie declarata de tip int si nu de tip c*ar. ?m vazut ca sfarsitul unui fisier este codificat cu 61, si nu cu un caracter. 3. ,ubexpresia c1getc*ar%& citeste o valoare de la tastatura si o asigneaza variabilei c.
66666666666666666666666666 Iiblioteca DctMpe.*@ 66666666666666666666666666 ,istemul C pune la dispozitie fisierul *eader DctMpe.*@ care contine o multime de macro6uri %definitii& folosite pentru testarea caracterelor si o multime de prototipuri de functii ce sunt folosite pentru conversia caracterelor. n tabelul de mai <os prezentam o lista de macro6uri folosite la testarea caracterelor. ?ceste macro6 uri iau ca argument o variabila de tip int si returneaza o valoare de tip int %zero1false, diferit de zero1true&. 66666666666666666666666666666666666666666666666666666666666666666666666 B ;acro B ,e returneaza true %diferit de zero& daca B 66666666666666666666666666666666666666666666666666666666666666666666666 isalp*a%c& c este litera isupper%c& c este litera ma<uscula islo)er%c& c este litera mica isdigit%c& c este cifra isalnum%c& c este litera sau cifra isxdigit%c& c este cifra *exazecimala isspace%c& c este caracter spatiu ispunct%c& c este semn de punctuatie isprint%c& c este caracter tiparibil isgrap*%c& c este tiparibil, dar diferit de spatiu iscntrl%c& c este caracter de control isascii%c& c este cod ?,C 6666666666666666666666666666666666666666666666666666666666666666666 n tabelul urmator, vom scrie functiile (toupper%&( si (tolo)er%&(, care sunt din biblioteca standard si macro6ul (toascii%&(. ;acro6ul si prototipurile pentru cele doua functii sunt in DctMpe.*@. ?cestea au ca argument o variabila de tip int si returneaza tipul int. toupper%c& sc*imba c din litera mica in ma<uscula tolo)er%c& sc*imba c din ma<uscula in litera mica toascii%c& sc*imba c cu codul ?,C
6666666666666666 Un exemplu %util&5 =umararea cuvintelor 6666666666666666 Vrem sa numaram cate cuvinte sunt introduse de la tastatura. .le sunt separate prin spatiu. 2entru scrierea programului vom utiliza tot strategia (top6do)n(.
#include Dstdio.*@ #include DctMpe.*@ main%& E int numarCcuvinte 1 /7 int gasesteCurmatorulCcuvant%void&7
)*ile %gasesteCurmatorulCcuvant%& 11 1& LL numarCcuvinte7 printf%(=umarul de cuvinte 1 KdFnFn(, numarCcuvinte&7 G
int gasesteCurmatorulCcuvant%void& E int c7
)*ile %isspace%c 1 getc*ar%&&& 7 :J sarim peste spatii J: if %c S1 .4"& E )*ile %%c 1 getc*ar%&& S1 .4" RR Sisspace%c&& 7 :J sarim peste orice diferit de .4" si spatii J: if %c S1 .4"& return 17 else return /7 G return /7 G
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. "olosind functiile (getc*ar%&( si (putc*ar%&(, sa se scrie un program C care transforma literele mici in litere mari. ncercati si o varianta de program care foloseste functiile (islo)er%&( si (toupper%&(. 2. Utilizand functiile (getc*ar%&( si (putc*ar%&( creati un program C care sa copie un fisier in alt fisier %comanda voastra proprie de copiere&. Utilizati redirectarea S 8e asemeni, precizati si cazul cand dorim sa copiem un fisier la sfarsitul unui fisier existent. 3. ,crieti in C un analizor lexical care sa recunoasca cat mai multi atomi lexicali din C. 8e exemplu, cuvintele rezervate %)*ile, do, for, ...&, identificatori, operatori %relationali, logici, artimetici, ...& si eventual alte structuri. ?poi, tipariti acelasi fisier de intrare cu exceptia spatiilor multiple si a comentariilor. 4. ,crieti un program C care citeste caractere de la tastatura si le scrie la ecran. ,crieti toate vocalele cu litere ma<uscule si consoanele cu litere mici. ?poi, scrieti un program C care citeste caractere de la tastatura si sterge vocalele din ele %afisand doar consoanele&. %?cest mod de scriere era folosit in scrisul *ieroglific al Qreciei ?ntice&. !. %(2rettM printing(& ,crieti un program C care are la intrare un fisier sursa C si il transforma intr6un program C scris frumos %eventual in stilul Iell Haboratoires&. 9ipuri fundamentale de date $.1. 8eclaratii si expresii $.2. 9ipuri fundamentale de date $.3. Caractere si tipul (c*ar( $.4. 9ipul de date (int( $.!. 9ipurile integrale (s*ort(, (long( si (unsigned( $.$. 9ipuri reale $.'. 4peratorul (sizeof%&( $.+. "unctii matematice $.-. Conversii implicite si explicite $.1/. Conversia la intreg $.11. Conversiile aritmetice uzuale $.12. Conversii explicite $.13. .rori de programare frecvente $.14. .xercitii propuse spre implementare
11111111 Capitolul $ 11111111 111111111111111111111 9ipuri fundamentale de date 111111111111111111111
666666666666666666666666666 8eclaratii si expresii 666666666666666666666666666 Variabilele si constantele sunt obiecte cu care se lucreaza intr6un program. n C, toate variabilele trebuie declarate inainte de a fi folosite. 8eclaratiile au doua scopuri5 1. spun compilatorului cat spatiu de memorie trebuie rezervat pentru memorarea acelor variabile7 2. permit compilatorului sa instruiasca masina pentru a face operatiile specifice corect. 8e exemplu, in expresia a L b, operatorul L este aplicat pentru doua variabile. ;asina executa in mod diferit adunarea pentru variabile de tip (int( si pentru variabile de tip (float(. Iineinteles, pentru programator aceste conventii sunt transparente %se mai spune ca (L( este operator de supraincarcare&. .xpresiile sunt combinatii %cu inteles& de constante, variabile si apeluri de functii. ;a<oritatea expresiilor %cum ar fi, de exemplu, variabilele& au si valoare si tip. n multe situatii, valoarea returnata depinde in principal de tipul expresiei.
66666666666666666666666666666666666666 9ipuri fundamentale de date 66666666666666666666666666666666666666 ?vem urmatoarele tipuri fundamentale de date %scriere intreaga 6 lunga&5 c*ar signed c*ar unsigned c*ar signed s*ort int signed int signed long int unsigned s*ort int unsigned int unsigned long int float double long double 9oate acestea sunt cuvinte rezervate, deci nu se pot folosi ca nume de variabile. ?lte tipuri de date, cum ar fi vectorii si pointerii, sunt derivate din tipurile fundamentale. 8e obicei, cuvantul rezervat (signed( nu se mai scrie. 8e exemplu, (signed int( este ec*ivalent cu (int(. 8e asemenea, cuvintele (s*ort int(, (long int( si (unsigned int( pot fi prescurtate, de obicei, ca (s*ort(, (long( si (unsigned(. Cu aceste conventii, tabelul de mai sus se mai poate scrie5 c*ar signed c*ar unsigned c*ar s*ort int long unsigned s*ort unsigned unsigned long float double long double 9ipurile fundamentale se pot grupa dupa functionalitate5 1. tipurile integrale sunt cele care sunt folosite pentru reprezentarea valorilor intregi7 2. tipurile reale sunt cele care sunt folosite pentru reprezentarea valorilor reale7 3. tipurile aritmetice sunt tipuri integrale sau reale. ?cestea sunt5 9ipuri integrale5 c*ar signed c*ar unsigned c*ar s*ort int long unsigned s*ort unsigned unsigned long 9ipuri reale5 float double long double
666666666666666666666666666666666 Caractere si tipul (c*ar( 666666666666666666666666666666666 n C, variabilele de orice tip integral pot fi folosite pentru reprezentarea caracterelor. n particular, variabilele de tip (c*ar( si (int( se folosesc pentru acest scop. ?m vazut in capitolul precedent ca atunci cand dorim sa comparam o variabila cu .4", atunci trebuie sa declaram acea variabila de tip (int(, si nu de tip (c*ar(. Constante cum ar fi PaP, PLP pe care le gandim ca fiind caractere sunt de tip (int(, si nu de tip (c*ar(. 0etineti ca nu exista constante de tip (c*ar( SSS 0eamintim ca toate caracterele sunt tratate ca (intregi mici(, si reciproc, intregii mici sunt tratati ca niste caractere. n particular, orice expresie integrala poate fi afisata in format intreg sau caracter.
66666666666 .xemplu5 2resupunem ca avem o (bucata( de cod C5 66666666666 c*ar c 1 PaP7 :J PaP are codul ?,C -' J: int i 1 $!7 :J $! este codul ?,C pentru P?P J:
printf%(Kc(, c L 1&7 :J este afisat b J: printf%(Kd(, c L 2&7 :J este afisat -- J: printf%(Kc(, i L 3&7 :J este afisat 8 J: n C, fiecare caracter este memorat pe un octet de memorie. 2e aproape toate masinile, un octet este compus din + biti. "ie declaratia c*ar c 1 PaP7 2utem gandi ca (c( este memorat pe un octet astfel 666666666666666666666666666666 B / B 1 B 1 B / B / B / B / B 1 B 666666666666666666666666666666 ' $ ! 4 3 2 1 / "iecare celula reprezinta un bit si fiecare bit este numerotat %incepand cu cel mai putin semnificativ&. Iitii care formeaza un octet sunt fie (on(, fie (off(, aceste stari fiind reprezentate prin 1 si / respectiv. ?cesta ne conduce sa gandim fiecare octet din memorie ca un sir de + cifre binare %se mai numesc siruri de biti&. ?stfel variabila (c( poate fi gandita ca sirul de biti /11////1 ;ai general, fiecare cuvant masina poate fi gandit ca un sir de cifre binare grupate in octeti. Un sir de cifre binare poate fi deci gandit ca un numar binar %adica in baza 2&. "ara a intra in detalii matematice %teorema bazei de numeratie& vom face doar un exemplu5
66666666666 .xemplu5 66666666666 Valoarea lui (c( este numarul /11////1 %in baza 2& 1 x 2A$ L 1 x 2A! L / x 2A4 L / x 2A3 L / x 2A2 L / x 2A1 L 1 x 2A/ care inseamna $4 L 32 L 1 1 -' in notatia zecimala %in baza 1/&. ?=, C pune la dispozitie trei tipuri referitoare la caractere5 c*ar signed c*ar unsigned c*ar 8e obicei, tipul (c*ar( este ec*ivalent cu (signed c*ar( sau (unsigned c*ar(, depinzand de compilator. "iecare din aceste trei tipuri se memoreaza pe un octet %deci poate (tine( 2!$ valori distincte&. 2entru (signed c*ar(, valorile sunt intre 612+ si 12', iar pentru (unsigned c*ar( intre / si 2!!.
6666666666666666666666666 9ipul de date (int( 6666666666666666666666666 9ipul de date (int( este cel mai folosit tip din limba<ul C. ?cest tip, impreuna cu alte tipuri integrale %cum ar fi5 (c*ar(, (s*ort( si (long(& este desemnat pentru lucrul cu valori intregi reprezentabile pe o masina. n matematica, numerele naturale sunt /, 1, 2, 3, ..., care impreuna cu cele negative %corespunzatoare& formeaza numerele intregi. 2e o masina, se pot reprezenta %folosind un tip integral& numai o submultime finita a acestor numere. 8e obicei, un cuvant se memoreaza pe un cuvant masina. ?numite calculatoare folosesc cuvante de 2 octeti %11$ biti&, altele 4 octeti %132 biti&.
66666666666 .xemple5 66666666666 1. ;asini ce folosesc cuvinte memorate pe 2 octeti5 2C 2. ;asini ce folosesc cuvinte memorate pe 4 octeti5 ?pollo, [e)lett62ac3ard, =ext, ,ilicon Qrap*ics, ,un, etc.
2resupunem ca lucram pe un calculator care lucreaza pe 4 octeti. ?ceasta implica ca un cuvant are 32 biti, deci poate (tine( 2AE32G valori distincte. Tumatate sunt folosite pentru reprezentarea numerelor negative si cealalta <umatate pentru pozitive5 6 2AE31G, 62AE31GL1,..., 62, 61, /, 1, 2, ..., 2AE31G61 8aca lucram pe un calculator unde memorarea unui cuvant se face pe 2 octeti, atunci putem memora 2AE1$G valori distincte. Valoarea cea mai mare, a tipului (int( este data de constanta ;?>=9. .vident cea mai mica valoare va fi 6;?>=961. 8aca se incearca, de exemplu, adunarea a doua numere %si se depaseste aceasta valoare&, atunci se va primi un mesa< (integer overflo)(.
6666666666666666666666666666666666666666666666666666666666666 9ipurile integrale (s*ort(, (long( si (unsigned( 6666666666666666666666666666666666666666666666666666666666666 8e obicei, tipul (s*ort( se memoreaza pe doi octeti si tipul (long( pe patru octeti. ?stfel, pe masinile in care cuvintele au patru octeti, lungimea tipului (int( este aceeasi cu lungimea tipului (long(, iar pe masinile in care cuvintele au doi octeti, lungimea tipului (int( este egala cu lungimea tipului (s*ort(. Constantele predefinite ;?>,[409 si ;?>H4=Q %in unele implementari H4=QC;?>& caracterizeaza lungimea acestor tipuri. 8e obicei, ;?>,[40912AE1!G si ;?>H4=Q12AE31G. ?stfel, daca (s( este o variabila de tip (s*ort(, atunci 6 ;?>,[409 D1 s D1 ;?>,[40961 8aca (l( este o variabila de tip (long(, atunci 6 ;?>H4=Q D1 s D1 ;?>H4=Q61 n ceea ce priveste tipul (unsigned(, acesta este memorat pe acelasi numar de octeti ca si tipul (int(. 8aca (u( este o variabila de tip (unsigned(, atunci / D1 u D1 2J;?>=961
6666666666666666 9ipuri reale 6666666666666666 ?=, C contine trei tipuri reale5 (float(, (double( si (long double(. Variabilele de acest tip vor putea tine valori reale, cum ar fi5 /.//1 2./ 3.141!- ?ceasta notatie se numeste notatie zecimala, deoarece contine punctul zecimal. ;ai exista si notatia exponentiala. 8e exemplu, 1.234!$'e! corespunde cu 1.234!$' x 1/A!11234!$.' 2e ma<oritatea masinilor, tipul (float( se memoreaza pe 4 octeti, iar tipul (double( pe + octeti. ?sta inseamna ca o variabila de tipul (float( poate avea $ zecimale, iar o variabila de tipul (double( poate avea 1! zecimale. ?stfel, o variabila de tipul (float( are forma /,dC1 dC2 dC3 dC4 dC! dC$ x 1/AEnG unde 63+ D1 n D1 3+. ?semanator, o variabila de tipul (double( are forma /,dC1 dC2 ... dCE1!G x 1/AEnG unde 63/+ D1 n D1 3/+. ?stfel, instructiunea x 1 123.4!1234!1234!1234!7 :J 2/ cifre semnificative J: va implica atribuirea lui x a valorii /.1234!1234!1234! x 1/A3 %1! cifre semnificative& n ?=, C, pentru varibilele de tip (long double( se aloca mai multa memorie. nsa sunt compilatoare care trateaza acest exact tip exact ca si (double(.
6666666666666666666666666666 4peratorul (sizeof%&( 6666666666666666666666666666 C pune la dispozitie operatorul (sizeof%&( pentru determinarea numarului de octeti necesari memorarii unui obiect. ?cesta are aceeasi prioritate si asociativitate ca si ceilalti operatori unari. 4 expresie de forma sizeof%obiect& returneaza un intreg car reprezinta numarul de octeti necesari pentru memorarea obiectului in memorie. Un obiect poate fi un tip, cum ar fi (int( sau (float(, sau poate fi o expresie, cum ar fi a L b, sau poate fi un sir sau o structura.
66666666666 .xemplu5 Calculul numarului de octeti pentru cateva tipuri 66666666666 #include Dstdio.*@ main%& E printf%(Hungimea catorva tipuri fundamentale.FnFn(&7 printf%( c*ar5K3d octeti Fn(, sizeof%c*ar&&7 printf%( s*ort5K3d octeti Fn(, sizeof%s*ort&&7 printf%( int5K3d octeti Fn(, sizeof%int&&7 printf%( long5K3d octeti Fn(, sizeof%long&&7 printf%( unsigned5K3d octeti Fn(, sizeof%unsigned&&7 printf%( float5K3d octeti Fn(, sizeof%float&&7 printf%( double5K3d octeti Fn(, sizeof%double&&7 printf%(long double5K3d octeti Fn(, sizeof%long double&&7 G 8in moment ce limba<ul C este flexibil in ceea ce priveste necesarul de memorie pentru tipurile fundamentale, situatiile pot sa difere de la o masina la alta. 9otusi, aceasta garanteaza ca5 sizeof%c*ar& 1 1 sizeof%s*ort& D1 sizeof%int& D1 sizeof%long& sizeof%signed& D1 sizeof%unsigned& D1 sizeof%int& sizeof%float& D1 sizeof%double& D1 sizeof%long double& (sizeof%&( nu este o functie %c*iar daca contine paranteze atunci cand ne referim la tipuri&, ci este un operator. 8e exemplu5 sizeof%a L b L '.'& este ec*ivalent cu sizeof a L b L '.'
6666666666666666666666666 "unctii matematice 6666666666666666666666666 =u exista functii matematice implicite %in compilatorul C&, ci acestea sunt descrise in biblioteci. 8e exemplu, functiile sZrt%& po)%& exp%& log%& sin%& cos%& tan%& sunt definite in biblioteca Dmat*.*@. 9oate aceste functii, cu exceptia lui (po)er%&( au un argument de tip (double( si returneaza o valoare de tip (double(. "unctia (po)er%&( are doua argumente de tip (double( si returneaza o valoare de tip (double(.
666666666666666666666666666666666666666 Conversii implicite si explicite 666666666666666666666666666666666666666 4 expresie aritmetica, cum ar fi (x L M(, are si valoare si tip. 8e exemplu, daca (x( si (M( au tipul (int(, atunci expresia (x L M( are tipul (int(. 8ar, daca (x( si (M( au ambele tipul (s*ort(, atunci (x L M( este de tip (int(, si nu (s*ort(. ?ceasta se intampla deoarece in orice expresie, (s*ort( se converteste la (int(.
6666666666666666666666666 Conversia la intreg 666666666666666666666666 Un (c*ar( sau (s*ort(, ori (signed( sau (unsigned(, ori un tip enumerare %vom reveni& poate fi folosit in orice expresie unde poate fi folosit (int( sau (unsigned int(. 8aca toate valorile tipului original pot fi reprezentate de un (int(, atunci valoarea acesteia se va converti la (int(7 altfel se va converti la (unsigned int(. ?ceasta se numeste (conversie la intreg(. 66666666666 .xemplu5 66666666666 c*ar c 1 P?P7 printf%(KcFn(, c&7 Variabila (c( apare ca argument al functiei (printf%&(. Cu toate acestea, deoarece are loc conversia la intreg, tipul expresiei (c( este (int(, si nu (c*ar(.
66666666666666666666666666666666666666 Conversiile aritmetice uzuale 66666666666666666666666666666666666666 Conversiile aritmetice pot apare cand sunt evaluati operanzii unui operator binar. 666666666666 .xemplu5 666666666666 2resupunem ca (i( este (int( si (f( este un (float(. n expresia (i L f(, operandul (i( se converteste la (float( si deci expresia (i L f( va intoarce tipul (float(. ?ceste reguli se numesc (conversii aritmetice uzuale(. ata urmatorul (algoritm(5 daca un operand este de tip (long double( atunci si celalalt operand va fi convertit la tipul (long double( altfel daca un operand este de tip (double( atunci si celalalt operand va fi convertit la tipul (double( altfel daca un operand este de tip (float( atunci si celalalt operand va fi convertit la tipul (float( altfel :JJJJJ au loc conversiile la intreg JJJJJ: daca un operand este de tip (unsigned long( atunci si celalalt operand va fi convertit la tipul (unsigned long( altfel daca un operand are tipul (long( si celalalt (unsigned( atunci 6 daca un (long( poate reprezenta toate valorile (unsigned( atunci operandul de tip (unsigned( se va converti la (long( 6 daca un (long( nu poate reprezenta toate valorile (unsigned( atunci ambii operanzi se vor converti la (unsigned long( altfel daca un operand are tipul (long( atunci celalalt operand se converteste la (long( altfel daca un operator are tipul (unsigned( atunci celalalt operand va fi convertit la (unsigned( altfel ambii operanzi vor avea tipul (int(
66666666666 .xemplu5 2resupunem ca avem declaratiile5 66666666666 c*ar c7 s*ort s7 int i7 unsigned u7 unsigned long ul7 float f7 double d7 long double ld7 ?tunci avem urmatoarele valori pentru tipurile expresiilor de mai <os5 66666666666666666666666666666666666666666666666666666666666666666666666 B .xpresie 9ip B .xpresie 9ip B 66666666666666666666666666666666666666666666666666666666666666666666666 B c 6 s : i int u J ' 6 i unsigned B B u J 2./ 6 i double f J ' 6 i float B B c L 3 int ' J s J ul unsigned long B B c L !./ double ld L c long double B B d L s double u 6 ul unsigned long B B 2 J i : l long u 6 l dependent de sistem B 66666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666 Conversii explicite 666666666666666666666666 8aca (i( este de tip (int(, atunci %double& i va converti valoarea lui (i( astfel incat expresia sa aiba tipul (double(. Variabila (i( ramane nesc*imbata. Conversiile se pot aplica si expresiilor. 66666666666 .xemple5 66666666666 %long& %P?P L 1./& x 1 %float& %%int& M L 1& %double& %x 1 ''& 4peratorul de conversie de tip %cast& este un operator unar care are aceeasi prioritate si asociativitate %de la dreapta la stanga& ca alti operatori unari.
666666666666 .xemplu5 666666666666 .xpresia %float& i L 3 este ec*ivalenta cu %%float& i& L 3 pentru ca operatorul (cast( are prioritate mai mare decat (L(.
666666666666666666666666666666666666666 .rori de programare frecvente 666666666666666666666666666666666666666 2resupunem ca suntem pe o masina care lucreaza folosind cuvinte memorate pe doi octeti. Consideram urmatorul exemplu5 66666666666 .xemplu5 66666666666 int a 1 1, b 1 1''$, c 1 32///7 printf%(KdFn(, a L b L c&7 :J eroare5 va fi afisat 631'!- J: Un mod de a repara aceasta greseala este inlocuirea instructiunii (printf%&( cu5 printf%(KdFn(, %long& a L b L c&7 :J va fi afisat 33''' J:
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. 2resupunem ca depunem o suma %depozit la termen& intr6o banca care ofera o dobanda de 3+ K %de exemplu& pe an. ,a se calculeze suma finala dupa un anumit numar de ani %se va tine cont de (dobanda la dobanda(&. 2. ,crieti o functie C utilizator care sa simuleze functia (po)er%m, n&( pentru m intreg si n natural. Cate inmultiri are functia ? 3. ,a se verifice care din urmatoarele numere este mai mare5 piAe sau eAEpiG unde (pi(13.141!-2$!3!+-'-324 si (e(12.'1+2+1+2+4!-/4!24. 4. ,a se scrie un program C care aproximeaza (pi( si (e( cu un anumit numar de zecimale. dei5 2entru calculul lui (e(, puteti folosi convergenta sirului 1LFsum 1:nS 6@ e 2entru calculul lui (pi(, puteti folosi convergenta sirului Fsum 1:3A2 6@ piA2:$ 9ipurile enumerare, (tMpedef(, si operatori pentru biti '.1. 9ipurile enumerare '.2. "olosirea lui (tMpedef( '.3. .xpresii si operatori pe biti '.4. Complement pe bit '.!. Complement fata de doi '.$. 4peratori logici binari pe biti '.'. 4peratori de deplasare stanga si dreapta '.+. ;asti '.-. Un program de impac*etare si despac*etare a cuvintelor '.1/. Hitere mari 6@ litere mici '.11. 0ecapitulare '.12. .xercitii propuse spre implementare
11111111 Capitolul '
11111111 11111111111111111111111111111111111111111 9ipurile enumerare, (tMpedef(, si operatori pentru biti 11111111111111111111111111111111111111111
2entru declararea tipurilor enumerare se foloseste cuvantul rezervat (enum(. ?cesta va implica denumirea multimii, enumerarea elementelor %numite enumeratori&, ca elemente ale multimii.
66666666666 .xemplu5 66666666666 enum zile Eluni, marti, miercuri, <oi, vineri, sambata, duminicaG7 ?ceasta declaratie creeaza tipul utilizator (enum zile(. Cuvantul rezervat (enum( este urmat de identificatorul (zile(. .numeratorii sunt identificatorii luni, marti, ... . ?cestea sunt constante de tip (int(. 2rin conventie, primul este /, si apoi restul sunt incrementati. 8eclararea variabilelor de tip (enum zile( se face astfel5 enum zile zi1, zi27 Variabilele (zi1( si (zi2( pot lua ca valori elemente ale acestui tip. 8e exemplu, zi1 1 miercuri7 va asigna variabilei (zi1( valoarea miercuri. nstructiunea if %zi1 11 zi2& E ... G va testa daca valoarea variabilei (zi1( este egala cu valoarea variabilei (zi2(. .numeratorii pot fi initializati. 8e asemeni, putem declara variabilele in timpul definirii tipului (enum(.
66666666666 .xemplu5 66666666666 enum carti Etrefla 1 1, caro, frunza, inimaG a, b, c7 8in moment ce (trefla( este initializata cu 1, rezulta ca (caro(, (frunza( si (inima( sunt initializate cu 2, 3, respectiv 4 . 66666666666 .xemplu5 66666666666 enum fructe Emere 1 ', pere, portocale 1 3, lamaiG nrCfrct7 .ste clar ca (pere( va fi initializat cu +, iar (lamai( cu 4. =umele tipului enumerare poate lipsi, insa atunci nu mai putem declara alte variabile de acel tip.
66666666666 .xemplu5 66666666666 enum Eplop, molid, bradG copaci7 ,ingura variabila de tip (enum Eplop, molid, bradG( este copaci %nu se mai poate declara alta&.
66666666666666666666666666666 "olosirea lui (tMpedef( 66666666666666666666666666666 C pune la dispozitie facilitatea (tMpedef( pentru redenumirea tipurilor de<a existente. 66666666666 .xemplu5 tMpedef int culoare7 66666666666 culoare rosu, verde, albastru7 ?cesta defineste tipul (culoare( ca fiind un sinonim al lui (int(. ?poi declaram trei variabile de tipul (culoare(.
66666666666 .xemplu5 66666666666 Vom ilustra folosirea lui (tMpedef( pentru un tip enumerare %creand o functie ce returneaza ziua urmatoare&.
enum zile Eduminica, luni, marti, miercuri, <oi, vineri, sambataG7 tMpedef enum zile zi7
zi gasesteCziuaCurmatoare%zi z& E zi ziuaCurmatoare7
s)itc*%z& E case duminica5 ziuaCurmatoare 1 luni7 brea37 case luni5 ziuaCurmatoare 1 marti7 brea37 ... case sambata5 ziuaCurmatoare 1 duminica7 brea37 G return ziuaCurmatoare7 G
4 alta versiune %mai succinta& folosind (cast( este5
enum zile Eduminica, luni, marti, miercuri, <oi, vineri, sambataG7 tMpedef enum zile zi7
zi gasesteCurmatoareaCzi%zi z& E return %%zi&%%%int& z L 1& K '&&7 G
66666666666666666666666666666666666 .xpresii si operatori pe biti 66666666666666666666666666666666666 4peratorii pe biti lucreaza cu expresii integrale reprezentate ca siruri de cifre binare. ?cesti operatori sunt dependenti de sistem. 4peratorii pe biti sunt5 4peratori logici 66666666666666666666 1. Complement pe bit %unar&5 X 2. ,i pe bit 5 R 3. ,au exclusiv pe bit 5 A 4. ,au inclusiv pe bit 5 B 4peratori de deplasare 6666666666666666666666666666 1. 8eplasare stanga 5 DD 2. 8eplasare dreapta 5 @@ Ca si ceilalti operatori, operatorii pe biti au reguli de precedenta si asociativitate care determina precis cum se evalueaza expresiile ce contin astfel de operatori. 4peratorul X este unar, restul operatorilor sunt binari si lucreaza cu tipuri integrale.
6666666666666666666666666 Complement pe bit 6666666666666666666666666 4peratorul X se numeste operator de complement %sau operator de complement pe bit&. ?cesta inverseaza reprezentarea sirului pe biti, adica / devine 1 si 1 devine /. 66666666666 .xemplu5 "ie declaratia 66666666666 int a 1 !1'17 0eprezentarea binara a lui a este5 ///1/1// //11//11 .xpresia Xa este5 111/1/11 11//11// ?ceasta are valoarea intreaga 6 !1'2
6666666666666666666666666666666 Complement fata de doi 6666666666666666666666666666666 0eprezentarea complementului fata de doi a unui numar natural este un sir de biti obtinut prin complementarierea scrierii lui n in baza 2. Considerand complementul pe biti al lui n la care adunam 1, obtinem reprezentarea complementului fata de doi a lui 6n. 4 masina care utilizeaza reprezentarea complementului fata de doi ca reprezentare binara in memorie pentru valori integrale se numeste masina complement fata de doi. 0eprezentarile complement fata de doi ale lui / si 61 sunt speciale. ?stfel valoarea / are toti bitii (off(, pe cand valoarea 61 are toti bitii (on(. =umerele negative sunt caracterizate prin aceea ca au bitul cel mai semnificativ 1. 2e masinile care utilizeaza complementul fata de doi, *ard6ul permite implementarea scaderii ca o adunare si un complement pe biti. 4peratia a 6 b este aceeasi cu a L %6b&, unde 6b se obtine considerand complementul pe biti al lui b la care adunam 1.
666666666666666666666666666666666666666 4peratori logici binari pe biti 66666666666666666666666666666666666666 Cei trei operatori R %si&, A %sau exclusiv& si B %sau inclusiv& sunt binari si au operanzi integrali. 4peranzii sunt operati bit cu bit. 9abelul de mai <os contine semantica lor5 a b a R b a A b a B b 66666666666666666666666666666666666666666666 / / / / / 1 / / 1 1 / 1 / 1 1 1 1 1 / 1
66666666666 .xemplu5 2resupunem ca avem declaratiile si initializarile 66666666666 int a 1 3333, b 1 ''''7 .xpresie 0eprezentare Valoare 66666666666666666666666666666666666666666666666666666666666 a ////11/1 /////1/1 3333 b ///1111/ /11////1 '''' a R b ////11// ///////1 3/'3 a A b ///1//11 /11//1// 4-$4 a B b ///11111 /11//1/1 +/3' X%a B b& 111///// 1//11/1/ 6+/3+ %Xa R Xb& 111///// 1//11/1/ 6+/3+ 6666666666666666666666666666666666666666666666666666666666
6666666666666666666666666666666666666666666666666666 4peratori de deplasare stanga si dreapta 6666666666666666666666666666666666666666666666666666 Cei doi operanzi ai unui operator de deplasare trebuie sa fie expresii integrale. 9ipul returnat de expresie este dat de operandul din stanga. 4 expresie de forma expresie1 DD expresie2 implica reprezentarea pe bit a lui (expresie1( sa fie deplasata catre stanga cu un numar de pozitii specificat de (expresie2(. n capatul din dreapta, vor fi adaugate /6uri.
66666666666 .xemplu5 c*ar c 1 PUP7 66666666666 666666666666666666666666666666666666666666666666666666666666666666666666 .xpresie 0eprezentare ?ctiune 666666666666666666666666666666666666666666666666666666666666666666666666 c /1/11/1/ nedeplasat c DD 1 1/11/1// deplasare la stanga cu 1 c DD 4 1/1///// deplasare la stanga cu 4 c DD 1! //////// deplasare la stanga cu 1! 666666666666666666666666666666666666666666666666666666666666666666666666 C*iar daca valoarea lui (c( se memoreaza pe un octet, intr6o expresie aceasta ia tipul (int(. 8eci valoarea expresiilor (c DD 1(, (c DD 4( si (c DD 1!( se memoreaza pe doi octeti. 4peratorul de deplasare la dreapta (@@( nu este c*iar simetric cu (DD(. 2entru expresiile integrale fara semn, din stanga se va deplasa /, iar pentru cele cu semn 1.
66666666666 .xemplu5 66666666666 2resupunem ca avem declaratiile5 int a 1 1 DD 1!7 unsigned b 1 1 DD 1!7 666666666666666666666666666666666666666666666666666666666666666666666666666 .xpresie 0eprezentare ?ctiune 666666666666666666666666666666666666666666666666666666666666666666666666666 a 1/////// //////// nedeplasat a @@ 3 1111//// //////// deplasare la dreapta cu 3 b 1/////// //////// nedeplasat b @@ 3 ///1//// //////// deplasare la dreapta cu 3 66666666666666666666666666666666666666666666666666666666666666666666666666 Ca valoare intreaga, a @@ 3 este 64/-$, iar b @@ 3 este 4/-$, lucru care este in concordanta cu notiunea de numar negativ si pozitiv din matematica. 8aca operandul din dreapta a operatorului de deplasare este negativ sau are o valoare care este egala sau depaseste numarul de biti folositi pentru reprezentarea operandului din stanga, atunci comportarea este nedefinita. 9abelul de mai <os ilustreaza regulile de precedenta %L este mai prioritar& si asociativitate %de la stanga la dreapta& referitoare la operatorii de deplasare.
66666666666 .xemplu5 2resupunem ca avem5 unsigned a 1 1, b 1 27 66666666666 666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 .xpresie .xpresie ec*ivalenta 0eprezentare Valoare 666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 a DD b @@ 1 %a DD b& @@ 1 //////// //////1/ 2 a DD 1 L 2 DD 3 %a DD %1 L 2&& DD 3 //////// /1////// $4 a L b DD 12 J a @@ b %%a L b&DD%12 J a&&@@b ////11// //////// 3/'2 666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666
66666666 ;asti 66666666 4 (masca( este o constanta sau variabila folosita pentru extragerea bitilor doriti dintr6o alta variabila sau expresie. 8in moment ce constanta (int( 1 are reprezentarea pe biti5 //////// ///////1 aceasta poate fi folosita pentru determinarea bitului cel mai nesemnificativ dintr6o expresie (int(. Codul de mai <os foloseste aceasta masca si tipareste o secventa alternativa de / si 15 int i, masca 1 17 for %i 1 /7 i D 1/7 LL i& printf%(Kd(, i R masca&7 8aca dorim sa gasim valoarea unui anume bit dintr6o expresie, putem folosi o masca care este 1 in acea pozitie si / in rest.
66666666666 .xemplu5 66666666666 2utem folosi expresia 1 DD 2 pentru a vedea al treilea bit %numarand de la dreapta&. .xpresia %v R %1 DD 2&& ? 1 5 / are valoarea 1 sau / dupa cum este al treilea bit din (v(. ?lt exemplu de masca este valoarea constanta 2!! %adica 2A+ 61&. .a are reprezentarea //////// 11111111 8eoarece doar octetul din dreapta este plasat pe (on(, atunci expresia v R 2!! va intoarce o valoare ce are reprezentare pe biti cu toti bitii din octetul din stanga (off( si cel din dreapta identic cu octetul din dreapta a lui (v(. ,punem ca 2!! este o masca pentru octetul din dreapta.
6666666666666666666666666666666666666666666666666666666666666666666666666 Un program de impac*etare si despac*etare a cuvintelor 6666666666666666666666666666666666666666666666666666666666666666666666666 ,tim ca un caracter se memoreaza pe un octet, pe cand un intreg pe doi octeti. "olosind operatorii de deplasare, putem comprima doua caractere intr6un intreg.
void bitCprint%int a& E int i7 int n 1 sizeof%int& J C[?0CI97 int masca 1 1 DD %n61&7
for %i 1 17 i D1 n7 LLi& E putc*ar%%%a R masca& 11 /& ? P/P 5 P1P&7 a DD1 17 if %i K C[?0CI9 11 / RR i D n& putc*ar%P P&7 G G
int pac3%c*ar a, c*ar b& E int p 1 a7 p 1 %p DD C[?0CI9& B b7 return p7 G
c*ar unpac3%int p, int 3& :J 3 1 /, 1 J: E int n 1 3 J C[?0CI97 :J n 1 /, + J: unsigned masca 1 2!!7
masca DD1 n7 return%%p R masca& @@ n&7 G
void main%& E clrscr%&7 bitCprint%$!&7 printf%(Fnab 1 (&7 bitCprint%pac3%PaP, PbP&&7 putc*ar%PFnP&7 getc*%&7 printf%(=umarul 24-3/ este impac*etarea caracterelor Kc si Kc(, unpac3%24-3/,1&, unpac3%24-3/,/&&7 getc*%&7 G
66666666666666666666666666666666 Hitere mari 6@ litere mici 66666666666666666666666666666666 0eluam un exemplu dintr6un capitol precedent si anume transformarea literelor mari in mici folosind operatori de deplasare.
void main%& E clrscr%&7 int c7 )*ile %%c 1 getc*ar%&& S1 .4"& E if %isupper%c&& :: sau %c@1P?P RR cD1PUP& putc*ar%c B %1 DD !&&7 else putc*ar%c&7 G G
66666666666666666 0ecapitulare 66666666666666666 n cele ce urmeaza, vom preciza cum se calculeaza valoarea unui numar pozitiv, respectiv negativ %in memoria calculatorului&. "ie declaratia int a7 Consideram reprezentarea sa in baza 2 CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCC BCCCCCCBCCCCCCBCCCCCCCCCCCCCCBCCCB BCCCBCCCBCCCCCCCCCCCCCCCCCBCCCB bCE1$G bCE1!G . . . . . . . bC- bC+ bC' . . . . . . . bC1 8aca bCE1$G 1 / atunci a 1 sumaCE<11GAE1!G bC<J2A< altfel consideram reprezentarea in baza 2 a complementului lui a %Xa& CCCCCCCCCCCCCCCCCCCCCCCCCCCCCCC CCCCCCCCCCCCCCCCCCCCCCCCCCCCC BCCCCCCCBCCCCCCBCCCCCCCCCCCCBCCCCB BCCCCBCCCCBCCCCCCCCCCCCCCCBCCCCB bPCE1$G bPCE1!G . . . . . bPC- bPC+ bPC' . . . . . . bPC1 unde bPC< 1 1 6 bC<7 Xa 1 sumaCE<11GAE1!G bPC<J2A<7 6a 1 Xa L 17 a 1 6%Xa L 1&7 sfarsit.
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. %Tocul *artie, pumn, farfece& 2resupunem ca avem doi <ucatori care folosesc mana dreapta pentru reprezentarea a trei obiecte5 *artie 1 palma intinsa pumn 1 mana stransa sub forma de pumn foarfece 1 doua degete departate %semnul Victoriei& .i isi arata simultan mana dreapta in una din aceste configuratii %de mai multe ori&. 8aca ei arata acelasi lucru, este remiza %nu castiga nimeni&. 8aca nu se aplica una din urmatoarele trei reguli5 a& [artia acopera pumnul. %deci palma intinsa castiga fata de pumn& b& 2umnul sparge foarfecele. c& "oarfecele taie *artia. ,a se simuleze acest <oc, facand un numar arbitrar de evenimente precizand scorul final. ,e cere sa se <oace persoana6calculator, si varianta a doua calculator6calculator. 2. 4 ruleta este o masina care selecteaza la intamplare un numar intre / si 3! la intamplare. Tucatorul poate paria pe un numar par:impar sau poate paria pe un numar oarecare. Castigul unui pariu par:impar se premiaza cu 2:1 dolari, cu exceptia celor in care ruleta alege /. 8aca <ucatorul (prinde( numarul selectat de ruleta, atunci este platit cu 3! ... 1 dolari. ntrebare5 Considerand ca <ucam pariuri de 1 dolar, cate parieri trebuie sa facem astfel incat sa pierdem 1/ dolari ? 3. "olosind functia (bitCprint( construiti un tabel %cu trei coloane& care sa contina n, reprezentarea binara a lui 2An, reprezentarea binara a lui 2An61, pentru n 1 /, 1, 2, ..., 32. ?poi, afisati un tabel %tot cu trei coloane& care sa contina n, 1/An si 1/An61 pentru n 1 /, 1, 2, ..., ' %in baza zece&. Ce asemanare observati ? 4. Uilele secolului 2/ pot fi notate folosind intregi in forma (zi:luna:an(. 8e exemplu, 1:':-3 inseamna 1 iulie 1--3. ,crieti o functie care memoreaza ziua, luna si anul compact, astfel5 a& pentru zile %maxim 31& sunt suficienti ! biti7 b& pentru luna %12& sunt suficienti 4 biti7 c& pentru ani %1//& sunt suficienti ' biti7 "unctia trebuie sa aiba la intrare ziua, luna si anul ca intregi si trebuie sa returneze data (impac*etata( pe un (intreg( pe 1$ biti. ,crieti inca o functie care face (despac*etarea(. !. "olosind operatori pe biti, scrieti programe C care5 a& testeaza daca un numar de tip (int( sau (long( este divizibil cu +. Qeneralizare %divizibilitate cu 2An&7 b& testeaza daca un numar este pozitiv sau negativ7 c& calculeaza pentru un n dat, multiplii de 2, 4, ... Qeneralizare7 d& calculeaza pentru un n dat, Nn:2O, Nn:4O, ... Qeneralizare7 e& calculeaza mAn, folosind reprezentarea in baza 2 a lui n si metoda (divide et impera( %vezi exercitiul 2 din capitolul $&. $. ,a se calculeze suma cifrelor unui numar cu n cifre. "unctii, pointeri si clase de memorare +.1. 8eclararea si atribuirea pointerilor +.2. ?dresare si indirectare +.3. 2ointeri catre (void( +.4. ?pel prin adresa %referinta& +.!. 0eguli pentru stabilirea domeniului +.$. Clase de memorare +.'. Clasa de memorare (auto( +.+. Clasa de memorare (extern( +.-. Clasa de memorare (register( +.1/. Clasa de memorare (static( +.11. Variabile externe statice +.12. nitializari implicite +.13. 8efinitii si declaratii de functii +.14. Calificatorii de tip (const( si (volatile( +.1!. .xercitii propuse spre implementare
11111111 Capitolul + 11111111 1111111111111111111111111111 "unctii, pointeri si clase de memorare 1111111111111111111111111111 Va amintiti ca daca o expresie este transmisa ca argument pentru o functie, atunci se creeaza o copie a valorii expresiei care se transmite. ?cest mecanism este cunoscut sub numele de apel prin valoare %(call6bM6value(& si se foloseste in limba<ul C. 2resupunem ca avem o variabila v si o functie f%&. 8aca scriem v 1 f%v&7 atunci valoarea returnata de functia f va sc*imba valoarea lui v, altfel nu. n interiorul functiei f, nu se modifica valoarea lui v. ?ceasta se datoreaza faptului ca se transmite doar o copie a lui v catre f. n alte limba<e de programare, un apel de functie poate sc*imba valoarea lui v din memorie. ?cest mecanism se mai numeste apel prin referinta %(call6bM6reference(&. =oi vom simula apelul prin referinta transmitand adresele variabilelor ca argumente in apelul functiei.
6666666666666666666666666666666666666666666666 8eclararea si atribuirea pointerilor 666666666666666666666666666666666666666666666 2ointerii sunt folositi in programe pentru accesarea memoriei si manipularea adreselor. 8e<a ne6am intalnit cu adresele variabilelor ca argumente ale functiei (scanf%&(. 8e .xemplu, putem avea5 scanf%(KdFn(, Rn&7 8aca v este o variabila, atunci Rv este o adresa %sau locatie& din memorie. 4peratorul de adresa R este unar si are aceeasi precedenta si asociativitate de la dreapta la stanga ca si ceilalti operatori unari. Variabilele pointer pot fi declarate in programe si apoi folosite pentru a lua valori adrese din memorie.
66666666666 .xemplu5 8eclaratia 66666666666 int i, Jp7 defineste i de tip (int( si p (pointer catre int(. 8omeniul legal de valori pentru orice pointer cuprinde adresa speciala / si o multime de numere naturale care sunt interpretate ca fiind adrese masina ale sistemului C. 8e obicei, constanta simbolica =UHH este / %definita in Dstdio.*@&.
66666666666 .xemple5 66666666666 1. p 1 Ri7 :J valoarea lui p este adresa lui i J: 2. p 1 /7 :J valoarea lui p este adresa speciala / J: 3. p 1 =UHH7 :J ec*ivalent cu p 1 /7 J: 4. p 1 %int J& 13/'7 :J o adresa absoluta din memorie J:
666666666666666666666666666666 ?dresare si indirectare 666666666666666666666666666666 ?m vazut ca operatorul de adresa R se aplica unei variabile si intoarce valoarea adresei sale din memorie. 4peratorul de indirectare %sau de dereferentiere& se aplica unui pointer si returneaza valoarea scrisa in memorie la adresa data de pointer. ntr6un anumit sens, acesti doi operatori sunt inversi unul altuia. 2entru a intelege mai bine aceste notiuni, sa vedem pe un exemplu ce se intampla in memorie5 66666666666 .xemplu5 66666666666 2resupunem ca avem declaratiile5
int i 1 ''', Jp 1 Ri7
?tunci, in memorie avem5 =ume 9ip Valoare ?dresa 666666666666666666666666666666666666666 B i B int B ''' B 3?3+5/"". B 666666666666666666666666666666666666666 :F B B B %Jp 11 i& J B 66666666 %p 1 Ri& B B R B F: 666666666666666666666666666666666666666666666666 B p B int J B 3?3+5/"". B 3?3+5/""? B 666666666666666666666666666666666666666666666666 =ume 9ip Valoare ?dresa
;entionam ca adresa unei variabile este dependenta de sistem %C aloca memorie acolo unde poate&.
66666666666 .xemplu5 66666666666 float x, M, Jp7 p 1 Rx7 M 1 Jp7 ;ai intai (p( se asigneaza cu adresa lui (x(. ?poi, (M( se asigneaza cu valoarea unui obiect la care pointeaza p %adica Jp&. ?ceste doua instructiuni de asignare se pot scrie M 1 JRx7 care este ec*ivalent cu M 1 x7 ?m vazut mai sus ca un pointer se poate initializa in timpul declararii sale. 9rebuie sa avem totusi gri<a ca variabilele din membrul drept sa fie de<a declarate.
6666666666 .xemplu5 Unde este greseala ? int Jp 1 Ra, a7 6666666666 9abelul de mai <os ilustreaza modul de evaluare a expresiilor cu pointeri.
6666666666 .xemplu5 6666666666 2resupunem ca avem declaratiile5 int i 1 3, < 1 !, Jp 1 Ri, JZ 1 R<, Jr7 double x7 666666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 666666666666666666666666666666666666666666666666666666666666666666666 p 11 R i p 11 %R i& 1 p 1 i L ' p 1 %i L '& gresit J J R p J %J %R p&& 3 r 1 R x r 1 %R x& gresit ' J J p : J Z L ' %%%' J %J p&&& : %J Z&& L ' 11 J %r 1 R <& J1 J p %J %r 1 %R <&&& J1 %J p& 1! 66666666666666666666666666666666666666666666666666666666666666666666 ,pre deosebire de C traditional, in ?=, C, singura valoare intreaga care poate fi asignata unui pointer este / %sau constanta =UHH&. 2entru asignarea oricarei alte valori, trebuie facuta o conversie explicita %cast&. n cele ce urmeaza, vom scrie un program care ilustreaza legatura dintre valoarea unui pointer si adresa lui.
printf%(Valoarea lui i5 KdFn(, Jp&7 printf%(?dresa lui i5 Klu sau KpFn(, Ri, Ri&7 printf%(?dresa lui i5 Klu sau KpFn(, p, p&7 printf%(Valoarea lui p5 Klu sau KpFn(, p, p&7 printf%(?dresa lui p5 Klu sau KpFn(, Rp, Rp&7 getc*%&7 G
Hocatia curenta a unei variabile din memorie este dependenta de sistem. 4peratorul J %din expresia Jp& va afisa valoarea scrisa la adresa care este egala cu valoarea lui p. ?dresa lui i %valoarea lui p& va fi afisata ca fiind ceva de genul 3?3+5/"". care reprezinta un numar scris in baza 1$ %in care cifrele sunt /, 1, ..., -, ?, I, C, 8, ., "& si are valoarea 3J1$A'L1/J1$A$L3J1$A!L+J1$A4L 1!J1$A2L1!J1$L14 1 -'$'!2$3+ 8e observat ca un pointer se memoreaza intotdeauna pe patru octeti indiferent de tipul variabilei catre care se face referirea. .xplicati de ce ?
666666666666666666666666666 2ointeri catre (void( 666666666666666666666666666 n C traditional, pointerii de tipuri diferite sunt considerati compatibili ca asignare. n ?=, C, totusi, un pointer poate fi asignat altuia doar daca au acelasi tip, sau cand unul dintre ei este de tipul (void(. 8e aceea, putem gandi (void J( ca un tip pointer generic.
6666666666 .xemple5 2resupunem ca avem declaratiile 6666666666 int Jp7 float JZ7 void Jv7 6666666666666666666666666666666666666666666666666666666666 B ?signari legale B ?signari ilegale B 6666666666666666666666666666666666666666666666666666666666 B p 1 /7 p 1 17 B B p 1 %int J& 17 v 1 17 B B p 1 v 1 Z7 p 1 Z7 B B p 1 %int J& Z7 B 666666666666666666666666666666666666666666666666666666666 Vom discuta in capitolele ulterioare despre functiile (calloc%&( si (malloc%&(, care produc alocare dinamica a memoriei pentru vectori si structuri. .le returneaza un pointer catre (void(, de aceea putem scrie5 int Ja7 a 1 calloc%...&7 n C traditional, trebuie sa facem conversie explicita5 a 1 %int J& calloc%...&7
66666666666666666666666666666666666 ?pel prin adresa %referinta& 66666666666666666666666666666666666 ?m vazut ca C foloseste mecanismul apelului prin valoare %(call6bM6value(& in cazul apelurilor functiilor si anume se fac copii ale parametrilor actuali care se transmit functiilor. n cele ce urmeaza, vom descrie mecanismul apelului prin adresa si astfel se va asigura modificarea valorii variabilei transmise. 2entru aceasta, vom utiliza pointeri. 66666666666 .xemplu5 66666666666 #include Dstdio.*@
void intersc*imba%int J, int J&7
void main%& E int a 1 3, b 1 '7
printf%(Kd KdFn(, a, b&7 intersc*imba%Ra, Rb&7 printf%(Kd KdFn(, a, b&7 G
void intersc*imba%int Jp, int JZ& E int tmp7
tmp 1 Jp7 Jp 1 JZ7 JZ 1 tmp7 G .fectul apelului prin adresa este realizat prin5 1. 8eclararea parametrului functiei ca fiind un pointer7 2. "olosirea unui pointer de indirectare in corpul functiei7 3. 9ransmiterea adresei unui argument cand functia este apelata.
6666666666666666666666666666666666666666666666 0eguli pentru stabilirea domeniului 6666666666666666666666666666666666666666666666 8omeniul unui identificator este partea din textul unui program unde identificatorul este cunoscut sau accesibil. ?ceasta idee depinde de notiunea de (bloc(, care este o instructiune compusa cu declaratii. 0egula de baza in stabilirea domeniului este aceea ca identificatorii sunt accesibili numai in blocul unde sunt declarati si necunoscuti in afara granitelor blocului. Unii programatori folosesc acelasi nume de identificatori prezenti in anumite blocuri. 66666666666 .xemplu5 66666666666 E int a 1 27 printf%(KdFn(, a&7 E int a 1 '7 printf%(KdFn(, a&7 G printf%(KdFn(, LLa&7 G Un program ec*ivalent ar fi5 E int aCafara 1 27 printf%(KdFn(, aCafara&7 E int aCinauntru 1 '7 printf%(KdFn(, aCinauntru&7 G printf%(KdFn(, LLaCafara&7 G
6666666666666666666666666 Clase de memorare 6666666666666666666666666 4rice variabila si functie are doua atribute5 tipul si clasa de memorare .xista patru clase de memorare in C, automata, externa, registru si statica si sunt date de urmatoarele cuvinte rezervate5 auto extern register static Cea mai cunoscuta clasa de memorare este (auto(.
6666666666666666666666666666666666 Clasa de memorare (auto( 6666666666666666666666666666666666 Variabilele declarate in interiorul functiilor sunt implicit automate. 8e aceea, clasa (auto( este cea mai cunoscuta dintre toate. 8aca o instructiune compusa %bloc& incepe cu declararea unor variabile, atunci aceste variabile sunt in domeniu in timpul acestei instructiuni compuse %pana la intalnirea semnului G&.
66666666666 .xemplu5 66666666666 auto int a, b, c7 auto float f7 8eclaratiile variabilelor in blocuri sunt implicit automate. Ha executie, cand se intra intr6un bloc, se aloca memorie pentru variabilele automate. Variabilele sunt considerate locale acestui bloc. Cand se iese din acest bloc, sistemul elibereaza zona de memorie ocupata de acestea si deci valorile acestor variabile se pierd. 8aca intram din nou in acest bloc, atunci se aloca din nou memorie pentru aceste variabile, dar vec*ile valori sunt necunoscute.
6666666666666666666666666666666666666 Clasa de memorare (extern( 6666666666666666666666666666666666666 4 metoda de transmitere a informatiei in blocuri si functii este folosirea variabilelor externe. 8aca o variabila este declarata inafara functiei, atunci acesteia i se aloca permanent memorie si spunem ca ea apartine clasei de memorare (extern(. 4 variabila externa este considerata globala tuturor functiilor declarate dupa ea, si c*iar dupa iesirea din blocuri sau functii, ea ramane permanent in memorie. 66666666666 .xemplu5 66666666666 #include Dstdio.*@
int a 1 1, b 1 2, c 1 37 int f%void&7
void main%& E printf%(K3dFn(, f%&&7 printf%(K3dK3dK3dFn(, a, b, c&7 G
int f%void& E int b, c7 :J b si c sunt locale, deci b, c globale sunt mascate J:
a 1 b 1 c 1 47 :J valoarea lui a se modifica J: return%a L b Lc&7 G
.xplicatia este foarte simpla. Ha inceput se memoreaza cate 2 octeti pentru (a(, (b(, (c(. Cand a<ungem la functia (f%&(, memoram inca cate doi octeti pentru (b( si (c( %notate la fel din intamplare&. Ha intoarcerea in functia apelanta, aceste (b( si (c( noi nu mai exista pentru ca erau locale functiei (f%&(. ,a vedem mai exact ce se intampla in memorie5 nainte de apelul functiei (f%&(5 =ume 9ip Valoare ?dresa 666666666666666666666666666666666666666 B a B int B 1 B 3?3+5/"". B 6666666666666666666666666666666666666666 6666666666666666666666666666666666666666 B b B int B 2 B 3?3+5/""C B 6666666666666666666666666666666666666666 6666666666666666666666666666666666666666 B c B int B 3 B 3?3+5/""? B 6666666666666666666666666666666666666666 n timpul executiei functiei (f%&( %dupa a 1 b 1 c 1 4&5 =ume 9ip Valoare ?dresa 666666666666666666666666666666666666666 B a B int B 4 B 3?3+5/"". B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B b B int B 2 B 3?3+5/""C B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B c B int B 3 B 3?3+5/""? B 666666666666666666666666666666666666666 66666666666666666666666666666666666666 B b B int B 4 B 3?3+5/""+ B 66666666666666666666666666666666666666 66666666666666666666666666666666666666 B c B int B 4 B 3?3+5/""$ B 66666666666666666666666666666666666666 Ha intoarcerea in functia (main%&(5 =ume 9ip Valoare ?dresa 666666666666666666666666666666666666666 B a B int B 4 B 3?3+5/"". B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B b B int B 2 B 3?3+5/""C B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B c B int B 3 B 3?3+5/""? B 66666666666666666666666666666666666666 8eci, cuvantul rezervat (extern( spune compilatorului (cauta peste tot, c*iar si in alte fisiere S(. ?stfel, programul precedent se poate rescrie5 in fisierul (fisier1.c(5
#include Dstdio.*@
int a 1 1, b 1 2, c 1 37 :J variabile externe J: int f%void&7
void main%& E printf%(K3dFn(, f%&&7 printf%(K3dK3dK3dFn(, a, b, c&7 G in fisierul (fisier2.c(5
int f%void& E extern int a7 :J cauta6l peste tot J: int b, c7
a 1 b 1 c 1 47 :J valoarea lui a se modifica J: return%a L b Lc&7 G
8eci, putem conc*ide ca informatiile se pot transmite prin variabile globale %declarate cu extern& sau folosind transmiterea parametrilor. 8e obicei se prefera al doilea procedeu. 9oate functiile au clasa de memorare externa. 8e .xemplu, extern double sin%double&7 este un prototip de functie valid pentru functia (sin%&(, iar pentru definitia functiei, putem scrie5 extern double sin%double x& E .. G
66666666666666666666666666666666666666 Clasa de memorare (register( 66666666666666666666666666666666666666 Clasa de memorare (register( spune compilatorului ca variabilele asociate trebuie sa fie memorate in registri de memorie de viteza mare, cu conditia ca aceasta este fizic si semantic posibil. 8aca limitarile resurselor si restrictiile semantice %cateodata& fac aceasta imposibila, clasa de memorare register va fi inlocuita cu clasa de memorare implicita (auto(. 8e obicei, compilatorul are doar cativa astfel de registri disponibili. ;ulti sunt folositi de sistem si deci nu pot fi alocati. "olosirea clasei de memorare (register( este o incercare de a mari viteza de executie a programelor. 8e regula, variabilele dintr6o bucla sau parametrii functiilor se declara de tip (register(. 66666666666 .xemplu5 66666666666 E register int i7 for %i 1 /7 i D H;97 LLi& E . . . . . G G :J la iesirea din bloc, se va elibera registrul i J: 8eclaratia register i7 este ec*ivalenta cu register int i7 8aca lipseste tipul variabilei declarata intr6o clasa de memorare de tip (register(, atunci tipul se considera implicit (int(.
66666666666666666666666666666666666 Clasa de memorare (static( 66666666666666666666666666666666666 8eclaratiile (static( au doua utilizari distincte si importante5 a& permite unei variabile locale sa retina vec*ea valoare cand se reintra in bloc %sau functie& %caracteristica ce este in contrast cu variabilele (auto( obisnuite&7 b& folosita in declaratii externe are alta comportare %vom discuta in sectiunea urmatoare&7 2entru a ilustra a&, consideram .xemplul5 66666666666 .xemplu5 66666666666 void f%void& E static int contor 1 /7
LLcontor7 if %contor K 2 11 /& . . . . . else . . . . . G
2rima data cand functia este apelata, (contor( se initializeaza cu /. Cand se paraseste functia, valoarea lui (contor( se pastreaza in memorie. Cand se va apela din nou functia (f%&(, (contor( nu se va mai initializa, ba mai mult, va avea valoarea care s6a pastrat in memorie la precedentul apel. 8eclararea lui (contor( ca un (static int( in functia (f%&( il pastreaza privat in (f%&( %adica numai aici i se poate modifica valoarea&. 8aca ar fi fost declarat in afara acestei functii, atunci si alte il puteau accesa.
6666666666666666666666666666666 Variabile externe statice 6666666666666666666666666666666 =e vom referi acum la folosirea lui (static( ca declaratie externa. ?ceasta pune la dispozitie un mecanism de (izolare( foarte important pentru modularitatea programelor. 2rin (izolare( intelegem vizibilitatea sau restrictiile de domeniu. 8eosebirea dintre variabile externe si cele externe static este ca acestea din urma sunt variabile externe cu restrictii de domeniu. 8omeniul este fisierul sursa in care ele sunt declarate. ?stfel, acestea sunt inaccesibile pentru functiile definite anterior in fisier sau definite in alte fisiere, c*iar daca functiile folosesc clasa de memorare (extern(. 66666666666 .xemplu5 66666666666 void f%void& E . . . . . :J v nu este accesibil aici J: G
static int v7 :J variabila externa statica J:
void g%void& E . . . . . :J v poate fi folosit aici J: G Vom mai prezenta un .xemplu de generare a numerelor aleatoare bazata pe metode de congruente liniara %\nut*, 8., ..5 (9*e ?rt of Computer 2rogramming(, 2nd ed., vol. 2, (,eminumerical ?lgorit*ms(, 0eading ;ass. ?ddison6YesleM, 1-+1&.
static unsigned seed 1 =9?HC,..87 :J externa, dar locala acestui fisier J: unsigned random%void& E seed 1 %;UH92H.0 J seed L =C0.;.=9& K ;48UHU,7 return seed7 G
double probabilitM%void& E seed 1 %;UH92H.0 J seed L =C0.;.=9& K ;48UHU,7 return %seed : "H4?9=QC;48UHU,&7 G
"unctia (random%&( produce o secventa aleatoare %aparenta& de numere intregi situate intre / si ;48UHU,. "unctia (probabilitM%&( produce o secventa aleatoare %aparenta& de valori reale intre / si 1. 4bservam ca un apel al functiei (random%&( sau (probabilitM%&( produce o noua valoare a variabilei (seed( care depinde de cea vec*e. 8in moment ce (seed( este o variabila externa statica, aceasta este locala acestui fisier si valoarea sa se pastreaza de la un apel la altul. 2utem acum crea functii in alte fisiere care apeleaza aceste numere aleatoare fara sa avem gri<a efectelor laterale. 2rezentam, in continuare, un ultim .xemplu de utilizare a lui (static( ca specificator de clasa de memorare pentru functii. "unctiile declarate (static( sunt vizibile doar in fisierul unde au fost declarate. 66666666666 .xemplu5 66666666666 void f%int a& E . . . . . :J g%& este disponibil aici, dar nu si in alte fisiere J: G
static int g%void& E . . . . . G
66666666666666666666666666 nitializari implicite 66666666666666666666666666 n C, variabilele externe si statice care nu sunt explicit initializate de catre programator, sunt initializate de catre sistem cu /. ?ceasta include siruri, siruri de caractere, pointeri, structuri si inregistrari %union&. 2entru siruri %de caractere&, aceasta inseamna ca fiecare element se initializeaza cu /, iar pentru structuri si (union( fiecare membru se initializeaza tot cu /. n contrast cu aceasta, variabilele (registru( si (auto( nu se initializeaza de catre sistem, ci pornesc cu valori (garbage( %adica cu ce se gaseste la momentul executiei la acea adresa&.
66666666666 .xemplu5 2rocesarea caracterelor 66666666666 4 functie care utilizeaza (return( poate returna o singura valoare. 8aca dorim sa trasmitem mai multe valori pentru mediul apelant, atunci trebuie sa transmitem adresele unor variabile. Vrem sa procesam un sir de caractere %in stilul (top6do)n(& astfel5 6 citeste caractere de la intrare pana cand avem .4"7 6 sc*imba litere mici in litere mari7 6 scrie pe fiecare linie trei cuvinte separate de un singur spatiu7 6 numara caracterele si literele de la intrare.
#include Dstdio.*@ #include DctMpe.*@
#define =0CCUV=9. 3 int procesare%int J, int J, int J&7
void main%& E int c, numarCcaractere 1 /, numarClitere 1 /7
)*ile %%c 1 getc*ar%&& S1 .4"& if %procesare%Rc, RnumarCcaractere, RnumarClitere& 11 1& putc*ar%c&7 printf%(FnKsK!dFnKsK!dFnFn(, (=umar de caractere5(, numarCcaractere, (=umar de litere5 (, numarClitere&7 G
int procesare%int Jp, int JnCcCp, int JnClCp& E static int contor 1 /, ultimCcaracter 1 P P7
if %isspace%ultimCcaracter& RR isspace%Jp&& return /7 if %isalp*a%Jp&& E LLJnClCp7 if %islo)er%Jp&& Jp 1 toupper%Jp&7 G else if %isspace%Jp&& if %LLcontor K =0CCUV=9. 11 /& Jp 1 PFnP7 else Jp 1 P P7 LLJnCcCp7 ultimCcaracter 1 Jp7 return 17 G
6666666666666666666666666666666666666666 8efinitii si declaratii de functii 666666666666666666666666666666666666666 2entru compilator, declaratiile functiilor sunt date in multe moduri5 6 apelul functiei 6 definitia functiei 6 prototipuri si declaratii explicite 8aca un apel de functie cum ar fi f%x& apare inainte de a fi declarata atunci compilatorul presupune declaratia implicita int f%&7 n stilul C traditional, declararea functiilor se face astfel5 int f%x& double x7 E . . . . . G .ste responsabilitatea programatorului de a transmite o variabila de tip (double(. n stilul ?=, C, aceasta s6ar scrie5 int f%double x& E . . . . . G n acest caz, compilatorul stie tipul argumentelor din functia (f%&(. 8e .xemplu, daca un (int( este transmis ca parametru, atunci el va fi convertit automat la (double(. .xista cateva limitari pentru definitiile si prototipurile functiilor. Clasa de memorare a functiei, daca este prezenta, poate fi (extern( sau (static(, dar nu ambele7 (auto( si (register( nu se pot folosi. ,ingura clasa care se poate folosi in lista de tipuri a parametrilor este (register(. 2arametrii nu se pot initializa.
66666666666666666666666666666666666666666666666666 Calificatorii de tip (const( si (volatile( 66666666666666666666666666666666666666666666666666 Comitetul ?=, a adaugat cuvintele rezervate (const( si (volatile( pentru limba<ul C %acestea nu sunt disponibile in limba<ul C traditional&. 8e obicei, (const( este plasat intre clasa de memorare si tipul variabilei. 66666666666 .xemplu5 static const int 3 1 37 66666666666 Citim aceasta (3 este o constanta de tip int cu clasa de memorare static(. 8eoarece (3( are tipul (const(, atunci putem initializa (3(, dar nu mai poate fi reasignat %incrementat sau decrementat&. C*iar daca variabila este calificata ca fiind (const(, aceasta nu se poate folosi pentru precizarea lungimii unui sir. 66666666666 .xemplu5 66666666666 const int n 1 37 int vNnO7 :J gresit J: 8eci o variabila calificata (const( nu este ec*ivalenta cu o constanta simbolica. Un pointer necalificat nu poate fi asignat cu adresa unei variabile calificata (const(.
6666666666 .xemplu5 66666666666 const int a 1 '7 int Jp 1 Ra7 :J gresit J: ;otivul este ca (p( este un pointer obisnuit catre (int( si l6am putea folosi mai tarziu in expresii de genul (LLJp(. 9otusi, utilizand pointeri, putem sc*imba valoarea lui a %ceea ce contravine conceptului de constanta&.
66666666666 .xemplu5 66666666666 const int a 1 '7 const int Jp 1 Ra7 =u vom putea modifica valoarea lui (a(, utilizand (Jp(. 2ointerul (p( nu este constant %putem face pLL&. 2resupunem ca vrem ca (p( sa fie constant, si nu (a(. Consideram declaratiile5 int a7 int J const p 1 Ra7 Ultima declaratie spune ca (p este un pointer constant catre int, si valoarea sa initiala este adresa lui a(. ?poi, nu mai putem asigna o valoare lui p, dar putem da valori lui (Jp(. Consideram acum un .xemplu si mai interesant5
666666666666 .xemplu5 666666666666 const int a 1 '7 const int J const p 1 Ra7 Ultima declaratie spune ca p este un pointer constant catre o constanta intreaga. =ici (p(, nici (Jp(, nu mai pot fi reasignate. n contrast cu (const(, calificatorul (volatile( este rar folosit. Un obiect (volatile( este unul ce poate fi modificat intr6un mod nespecificat de catre *ard.
66666666666 .xemplu5 Consideram declaratia 66666666666 extern const volatile int realCtimeCcloc37 Clasa de memorare (extern( inseamna (cauta6l oriunde, in acest fisier sau in alte fisiere(. Calificatorul (volatile( presupune ca obiectul poate fi modificat de *ard. 8in moment ce apare si calificatorul (const(, inseamna ca obiectul nu poate fi modificat din program.
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. 8aca (i( si (<( sunt de tip (int(, iar (p( si (Z( sunt pointeri catre (int(, precizati care dintre urmatoarele asignari sunt corecte5 p 1 Ri7 p 1 RJRi7 i 1 %int& p7 Z 1 Rp7 JZ 1 R<7 i 1 %JR&<7 i 1 JRJR<7 i 1 %Jp&LL L JZ7 2. ,crieti o functie C care sa faca o permutare circulara a cinci variabile. %1,2,3,4,!& 6@ %2,3,4,!,1&. 3. "ie codul C int v 1 ', Jp 1 Rv, JJZ 1 Rp7 printf%(KpFnKdFnKpFnKpFnKdFnKpFnKpFnKpFnKdFn(, Rv, JRv, Rp, JRp, JJRp, RZ, JRZ, JJRZ, JJJRZ&7 .xplicati de ce anumite numere se repeta S 4bservati ca am folosit combinatia (JR(, si nu (RJ(. .xplicati daca exista situatii unde (RJ( este corect semantic. 4. ,crieti un program C care arata pe cati octeti sunt memorati pointerii catre tipurile fundamentale de date. Ce observati ? ,iruri si pointeri -.1. ,iruri uni6dimensionale -.2. nitializarea sirurilor -.3. ndexul unui sir -.4. 0elatia dintre vectori si pointeri -.!. 2ointeri aritmetici si lungimea elementelor -.$. 9rimiterea sirurilor ca argumente pentru functii -.'. ,iruri multidimensionale -.+. Vectori 26dimensionali -.-. Vectori 36dimensionali -.1/. nitializarea vectorilor -.11. ?locarea dinamica a memoriei -.12. .xercitii propuse spre implementare
111111111 Capitolul - 111111111 1111111111111 ,iruri si pointeri 1111111111111 Un sir %se mai spune si vector& este o secventa de date ce contine articole de acelasi tip, indexate si memorate contiguu. 8e obicei, sirurile se folosesc pentru reprezentarea unui numar mare de valori omogene %in capitolul urmator vom studia sirurile de caractere&. 4 declaratie obisnuita de sir aloca memorie incepand de la adresa de baza. =umele sirului este un pointer constant la aceasta adresa de baza. 4 alta notiune pe care o vom explica este transmiterea sirurilor ca argumente in functii.
6666666666666666666666666666666 ,iruri uni6dimensionale 6666666666666666666666666666666 666666666666 .xemplu5 666666666666 2resupunem ca vrem sa lucram cu trei intregi5 int a1, a2, a37 9otusi, daca avem mai multe numere este anevoios sa declaram numerele in acest fel. ,olutia consta in utilizarea unui sir %de lungime trei& de intregi. int aN3O7 .lementele acestui sir vor fi accesate astfel5 aN/O aN1O aN2O 8eci numarul 3 reprezinta lungimea sirului, elementele sale fiind indexate incepand cu numarul /. ?ceasta este o trasatura a limba<ului C. 4 declaratie de sir uni6dimensional este un tip urmat de un identificator urmat la randul lui de paranteze patrate ce cuprind o expresie integrala constanta. Valoarea expresiei constante, care trebuie sa fie pozitiva, se numeste lungimea sirului si ea specifica numarul de elemente ale sirului. 2entru memorarea elementelor intr6un sir, compilatorul rezerva un spatiu de memorie corespunzator, pornind de la adresa de baza. 8imensiunea spatiului de memorie este egala cu numarul de elemente ale sirului inmultit cu numarul de octeti necesari memorarii unui element al sirului.
666666666666 .xemplu5 666666666666 Vom scrie un mic program care initializeaza un sir, tipareste valorile sale si insumeaza elementele sirului.
#include Dstdio.*@ #define = !
void main%& E int aN=O7 :J aloca spatiu de memorie pentru aN/O, aN1O, aN2O, aN3O si aN4O J: int i, suma 1 /7
for %i 1 /7 i D =7 LLi& :J initializeaza sirul J: aNiO 1 ' L i J i7 for %i 1 /7 i D =7 LLi& :J tipareste sirul J: printf%(aNKdO 1 Kd (, i, aNiO&7 for %i 1 /7 i D =7 LLi& :J insumeaza elementele sirului J: suma L1 aNiO7 printf%(Fnsuma 1 KdFn(, suma&7 :J tipareste suma lor J: G
,a vedem ce se intampla in memorie ? =ume 9ip Valoare ?dresa 666666666666666666666666666666666666666 B aN4O B int B 23 B 3?3+5/"". B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B aN3O B int B 1$ B 3?3+5/""C B 666666666666666666666666666666666666666 666666666666666666666666666666666666666 B aN2O B int B 11 B 3?3+5/""? B 666666666666666666666666666666666666666 6666666666666666666666666666666666666 B aN1O B int B + B 3?3+5/""+ B 6666666666666666666666666666666666666 6666666666666666666666666666666666666 B aN/O B int B ' B 3?3+5/""$ B 6666666666666666666666666666666666666
8eci vectorul %sirul& (a( se va memora incepand de la adresa 3?3+5/""$. 8eci (a 1 RaN/O(. ,e recomanda definirea lungimii unui sir ca o constanta simbolica %folosind directiva (#define(&.
666666666666666666666666666 nitializarea sirurilor 666666666666666666666666666 ,irurile pot apartine claselor de memorare (auto(, (extern(, (static( sau (constant(, dar nu pot fi (register(. Ca si variabilele simple, sirurile pot fi initializate in timpul declararii lor. nitializarea sirurilor se face folosind acolade si virgule. 666666666666 .xemplu5 666666666666 float xN'O 1 E61.1, /.2, 33./, 4.4, !./!, /./, '.'G7 ?sta inseamna, ec*ivalent5 xN/O 1 61.17 xN1O 1 /.27 . . . . . xN$O 1 '.'7 8aca lista de valori de initializare este mai mica decat numarul de elemente ale sirului, atunci elementele ramase se initializeaza cu /. 8aca un sir declarat (extern( sau (static( nu este initializat, atunci sistemul initializeaza toate elementele cu /. Vectorii declarati constanti sau automatic %cei impliciti& sunt initializati cu valori (garbage( %adica cu valorile existente in momentul executiei in memorie la acele adrese&. C traditional permite doar initializarea vectorilor declarati (extern( sau (static(, pe cand ?=, C permite initializarea sirurilor automate si constante. 8aca un sir este declarat fara precizarea lungimii si initializat cu o serie de valori, atunci lungimea sa se considera implicit numarul de valori initiale.
666666666666 .xemplu5 666666666666 8eclaratiile int aNO 1 E3, 4, !, $G7 si int aN4O 1 E3, 4, !, $G7 sunt ec*ivalente.
666666666666666666666 ndexul unui sir 66666666666666666666 2resupunem ca avem declaratia int i, aNlungimeO7 2entru accesarea unui element din sir, vom scrie (aNiO(, sau mai general (aNexpresieO(, unde (expresie( este o expresie integrala. (i( de mai sus se numeste index al sirului (a( si poate avea valori intre / si (lungime61(. 8aca indexul depaseste acest domeniu, compilatorul va da eroare in timpul executiei programului.
for %i 1 /7 i D 2$7 LLi& :J initializarea vectorului cu / J: literaNiO 1 /7 )*ile %%c 1 getc*ar%&& S1 .4"& :J numararea literelor J: if %isupper%c&& LLliteraNc 6 P?PO7 for %i 1 /7 i D 2$7 LLi& :J tiparirea rezultatelor J: E if %i K $ 11 /& printf%(Fn(&7 printf%(K!c5K4d(, P?P L i, literaNiO&7 G printf%(FnFn(&7 G ?cest program citeste de la tastatura sau dintr6un fisier %folosind indirectarea& un sir de caractere si numara in vectorul (litera( fiecare aparitie %in parte& a literelor.
66666666666666666666666666666666666666666 0elatia dintre vectori si pointeri 66666666666666666666666666666666666666666 ?m vazut ca numele unui sir %de exemplu (a(& este o adresa, deci poate fi privit ca valoare a unui pointer. 8eci sirurile si pointerii pot fi priviti oarecum la fel in ceea ce priveste modul cum sunt folositi pentru accesarea memoriei. Cu toate acestea, sunt cateva diferente %subtile si importante&. Cum numele unui sir este o adresa fixa %particulara&, atunci aceasta o putem gandi ca un pointer constant. Cand este declarat un sir, compilatorul trebuie sa aloce o adresa de baza si un spatiu suficient de memorie care trebuie sa contina toate elementele sirului. ?dresa de baza a unui sir este locatia initiala din memorie unde sirul este memorat7 aceasta coincide cu adresa primului element %de index /& al sirului.
666666666666 .xemplu5 2resupunem ca avem declaratiile5 666666666666
#define = 1// int aN=O, Jp7 ?tunci sistemul va rezerva octetii %sa zicem& numerotati 3//, 3/2, ..., 4-+ ca fiind adresele elementelor aN/O, aN1O, ..., aN--O nstructiunile p 1 a7 si p 1 RaN/O7 sunt ec*ivalente si vor asigna lui (p( valoarea 3// %ca adresa de memorie&. ?ritmetica pointerilor pune la dispozitie o alternativa pentru indexarea sirurilor. nstructiunile p 1 a L 17 si p 1 RaN1O7 sunt ec*ivalente si va asigna lui (p( valoarea 3/2 %adresa, bineinteles&.
666666666666 .xemplu5 2resupunem ca avem un sir ale carui elemente au de<a valori. 2entru a face suma elementelor, putem folosi pointeri. 666666666666 suma 1 /7 for %p 1 a7 p D RaN=O7 LLp& suma L1 Jp7
6666666666666666666666666666666666666666666666666666666 2ointeri aritmetici si lungimea elementelor 6666666666666666666666666666666666666666666666666666666 2ointerii aritmetici reprezinta una din trasaturile puternice ale limba<ului C. 8aca variabila (p( este pointer catre un tip particular, atunci expresia (p L 1( reprezinta adresa masina pentru memorarea sau accesarea urmatoarei variabile de acest tip. n mod similar, expresiile p L i LLp p L1 i au sens. 8aca (p( si (Z( sunt pointeri catre elemente de tip vector, atunci (p 6 Z( intoarce valoarea (int( si reprezinta numarul de elemente dintre (p( si (Z(. C*iar daca expresiile pointer si expresiile aritmetice seamana, exista diferente mari intre cele doua tipuri de expresii.
66666666666 .xemplu5 66666666666 void main%& E double aN2O, Jp, JZ7 p 1 RaN/O7 :J pointeaza catre baza sirului J: Z 1 p L 17 :J ec*ivalent cu Z 1 RaN1O7 J: printf%(KdFn(, Z 6 p&7 :J se va tipari 1 J: printf%(KdFn(, %int& Z 6 %int& p&&7 :J se va tipari + J: G
66666666666666666666666666666666666666666666666666666666666666 9rimiterea sirurilor ca argumente pentru functii 66666666666666666666666666666666666666666666666666666666666666 ntr6o definitie de functie, un parametru formal care este declarat ca un sir este de fapt un pointer. Cand este trimis un sir, atunci se trimite de fapt adresa de baza %evident prin (call6bM6value(&. .lementele vectorului nu sunt copiate. Ca o conventie de notatie, compilatorul permite folosirea parantezelor patrate %N,O& in declararea pointerilor ca parametri. 66666666666 .xemplu5 ,uma elementelor unui sir de tip vector 66666666666 int suma%int aNO, int n& :J n dimensiunea sirului J: E int i, s 1 /7 for %i 1 /7 i D n7 LLi& s L1 aNiO7 return s7 G n antetul functiei precedente, declaratia5 int aNO7 este ec*ivalenta cu int Ja7 2e de alta parte, declaratiile de mai sus nu sunt ec*ivalente daca se utilizeaza in alta parte5 6 prima se refera la creearea unui pointer constant %fara spatiu de memorie&7 6 a doua va crea o variabila pointer. 2resupunem ca (v( este declarat ca fiind un sir de 1// de elemente de tip (int(. 8upa ce am atribuit valori elementelor sale, putem utiliza functia (suma%&( pentru a aduna anumite valori ale lui (v(. 6666666666666666666666666666666666666666666666666666666666666666 B ?pel B Ce se calculeaza si se returneaza ? B 6666666666666666666666666666666666666666666666666666666666666666 suma%v, 1//& vN/O L vN1O L ... L vN--O suma%v, ++& vN/O L vN1O L ... L vN+'O suma%RvN'O, 36'& vN'O L vN+O L ... L vN3 6 1O suma%v L ', 2 J 3& vN'O L vN+O L ... L vN2 J 3 L $O 6666666666666666666666666666666666666666666666666666666666666666
66666666666 .xemplu5 ,ortare cu bule 6 (Iubble sort( 66666666666 ?lgoritmii eficienti de sortare au, de obicei, 4%nJlog n& operatii. ;etoda sortarii cu bule este ineficienta din acest punct de vedere deoarece are 4%nA2& operatii. 9otusi, pentru siruri de lungime mica, numarul de operatii este acceptabil. Un cod (elegant( ar fi5 void intersc*imba%int J, int J&7
void bubble%int aNO, int n& :J n este lungimea lui aNO J: E int i, <7
for %i 1 /7 i D n 6 17 LLi& for %< 1 n 6 17 i D <7 66<& if %aN< 6 1O @ aN<O& intersc*imba%RaN< 6 1O, RaN<O&7 G
66666666666666666666666666666666 ,iruri multidimensionale 66666666666666666666666666666666 Himba<ul C permite siruri de orice tip, inclusiv siruri de siruri. 2utem obtine siruri de dimensiune 2, 3, ... . 66666666666 .xemple5 66666666666 int aN1//O7 D6 sir de dimensiune 1 int bN2ON'O7 D6 sir de dimensiune 2 int cN!ON3ON2O7 D6 sir de dimensiune 3 2ornind de la adresa de baza, toate elementele sirului sunt memorate contiguu in memorie. 2rin definitie un tablou bidimensional este de fapt un tablou unidimensional ale carei elemente sunt fiecare in parte cite un tablou. 2rin urmare, indicii se scriu astfel aNiON<O in loc de aNi, <O ca in ma<oritatea limba<elor. n plus un tablou bidimensional poate fi tratat in mai multe moduri decat in alte limba<e. .lementele sunt memorate pe linii, ceea ce inseamna ca indicele din dreapta variaza primul in asa fel incit elementele sunt accesate in ordinea memoriei.
666666666666666666666666666666 Vectori 26dimensionali 66666666666666666666666666666 2resupunem ca avem un vector 26dimensional cu elemente intregi. int aN3ON!O7 ncepand cu adresa de baza, compilatorul va aloca spatiu contiguu pentru 1! intregi. ?tunci putem gandi acest vector ca o matrice, astfel5 col1 col2 col3 col4 col! lin1 aN/ON/O aN/ON1O aN/ON2O aN/ON3O aN/ON4O lin2 aN1ON/O aN1ON1O aN1ON2O aN1ON3O aN1ON4O lin3 aN2ON/O aN2ON1O aN2ON2O aN2ON3O aN2ON4O 2entru aNiON<O avem expresiile, de exemplu, ec*ivalente5 J%aNiO L <& %J%a L i&&N<O J%%J%a L i&& L <& J%RaN/ON/O L !Ji L <& 2utem gandi (aNiO( ca a (i(6a coloana a lui (a( %numarand de la /&, si (aNiON<O( ca elementul din linia (i(, coloana (<( a sirului %numarand de la /&. =umele sirului %(a(& este tot una cu (RaN/O(7 acesta este un pointer catre un sir de ! intregi. ?dresa de baza este (RaN/ON/O(, si nu (a(. Ultimul exemplu de mai sus reflecta functia de corespondenta in memorie dintre valoarea pointerului si indicele sirului. Cand un vector multidimensional este un parametru formal in definitia unei functii, toate dimensiunile, exceptand prima trebuie specificate.
66666666666 .xemplu5 66666666666 2resupunem ca sunt date elementele vectorului (a(. "unctia de mai <os se poate folosi pentru suma elementelor unui sir. ?tentie S 9rebuie specificat numarul de coloane. int suma%int aNON!O& E int i, <, suma 1 /7
for %i 1 /7 i D 37 LLi& for %< 1 /7 < D !7 LL<& suma L1 aNiON<O7 return suma7 G n antetul functiei, urmatoarele declaratii sunt ec*ivalente5 int aNON!O int %Ja&N!O int aN3ON!O Constanta 3 actioneaza ca o reminiscenta a omului, dar compilatorul nu tine cont de ea. =ou venitii in C sunt uneori confuzi in legatura cu deosebirea dintre un tablou bidimensional si un tablou de pointeri cum ar fi (a( din exemplul de mai sus. "iind date declaratiile int aN1/ON1/O7 int JbN1/O7 utilizarile lui (a( si (b( pot fi similare, in sensul ca aN!ON!O si bN!ON!O sunt ambele referinte legale ale aceluiasi (int(. ?vanta<e pentru utilizarea vectorilor %dezavanta<e pentru pointeri&5 6 (a( este un tablou in toata regula5 toate cele 1// celule de memorie trebuie alocate, iar pentru gasirea fiecarui element se face calculul obisnuit al indicelui7 6 pentru (b(, oricum prin declararea sa se aloca 1/ pointeri7 fiecare trebuie facut sa pointeze un tablou de intregi. 2resupunind ca fiecare pointeaza cate 1/ elemente din tablou, atunci vom obtine 1// celule de memorie rezervate, plus cele 1/ celule pentru pointeri. ?stfel tabloul de pointeri utilizeaza sensibil mai mult spatiu si poate cere un procedeu explicit de initializare. ?vanta<e pentru utilizarea pointerilor %dezavanta<e pentru vectori&5 6 accesarea unui element se face indirect prin intermediul unui pointer, in loc sa se faca prin inmultire si adunare7 6 liniile tabloului pot fi de lungimi diferite. ?ceasta inseamna ca nu orice element al lui b este constrins sa pointeze pe un vector de 1/ elemente, unii pot pointa pe cate 2 elemente, altii pe cate 2/ si altii pe niciunul.
66666666666666666666666666666 Vectori 36dimensionali 66666666666666666666666666666 Vectorii de dimensiune mai mare decat 3 lucreaza intr6un mod similar. 8aca avem declaratia int aN'ON-ON2O7 atunci compilatorul va aloca spatiu pentru 'J-J2 intregi. ?dresa de baza a sirului este (RaN/ON/ON/O(, iar functia de corespondenta in memorie este specificata de aNiON<ON3O care este ec*ivalent cu J%RaN/ON/ON/O L -J2Ji L 2J< L 3&
66666666666666666666666666666 nitializarea vectorilor 66666666666666666666666666666 .xista mai multe moduri de a initializa un vector multidimensional. 666666666666 .xemplu5 Urmatoarele declaratii sunt ec*ivalente5 666666666666 int aN2ON3O 1 E1, 2, 3, 4, !, $G7 int aN2ON3O 1 EE1, 2, 3G, E4, !, $GG7 int aNON3O 1 EE1, 2, 3G, E4, !, $GG7 ndexarea se face dupa linii. 8aca nu sunt suficiente elemente care sa initializeze vectorul, atunci restul elementelor sunt initializate cu /. 8aca prima componenta lipseste, atunci compilatorul extrage lungimea din numarul de perec*i de acolade interioare. 666666666666 .xemplu5 Consideram initializarea5 666666666666 int aN2ON2ON3O 1 E EE1, 1, /G, E2, /, /GG, EE3, /, /G, E4, 4, /GG G7 4 initializare ec*ivalenta poate fi data si astfel5 int aNON2ON3O 1 EEE1, 1G, E2GG, EE3G, E4, 4GGG7 8e obicei, daca un sir declarat (auto( nu este explicit initializat, atunci elementele sirului vor contine valori (garbage(. ,irurile (static( si (external( sunt initializate implicit cu /. ata un mod simplu de a initializa toate valorile unui vector cu /5 int aN2ON2ON3O 1 E/G7
666666666666666666666666666666666666666 ?locarea dinamica a memoriei 666666666666666666666666666666666666666 C pune la dispozitie pentru alocarea memoriei functiile (calloc%&( si (malloc%&( din biblioteca standard. ?ceste functii au prototipul declarat in Dstdlib.*@. ?cest lucru va permite rezervarea memoriei pentru un vector %de exemplu& in care ii aflam dimensiunea abia la rularea in executie %pana acum declararam dimensiunea unui vector cu #define&. Un apel de tipul calloc%n, dimensiuneCtip& va returna un pointer catre un spatiu din memorie necesar pentru memorarea a (n( obiecte, fiecare pe (dimensiuneCtip( octeti. 8aca sistemul nu poate aloca spatiul cerut, atunci acesta va returna valoarea =UHH. n ?=, C, tipul (sizeCt( este dat ca (tMpedef( in Dstdlib.*@. 8e obicei, tipul este (unsigned(. 8efinitia tipului este folosita in prototipurile functiilor (calloc%&( si (malloc%&(5 void Jcalloc%sizeCt, sizeCt&7 void Jmalloc%sizeCt&7 8eoarece pointerul returnat de aceste functii are tipul (void(, acesta poate fi asignat altor pointeri fara conversie explicita %cast&. 9otusi unele sisteme nu accepta aceasta conversie, deci ea trebuie facuta explicit. 4ctetii rezervati de (calloc%&( sunt automat initializati cu /, pe cand cei rezervati cu (malloc%&( nu sunt initializati %deci vor avea valori (garbage(&. =umele (calloc(, respectiv (malloc(, provine de la (contiguous allocation(, respectiv (memorM allocation(.
66666666666 .xemplu5 2rogram care citeste dimensiunea unui sir interactiv 66666666666 #include Dstdio.*@ #include Dstdlib.*@
void main%& E int Ja, i, n, suma 1 /7
printf%(FnKs(, (Citirea dimensiunii unui sir interactiv.FnFn8ati numarul de elemente a sirului5 (&7 scanf%(Kd(, Rn&7 a 1 calloc%n, sizeof%int&&7 :J aloca spatiu pentru n intregi J: :J daca da eroare de conversie de tip, atunci adaugati dupa semnul 1, conversia %int J& J: for %i 1 /7 i D n7 LLi& scanf%(Kd(, RaNiO&7 for %i 1 /7 i D n7 LLi& suma L1 aNiO7 free%a&7 :J eliberarea spatiului J: printf%(FnKsK'dFnKsK'dFnFn(, (=umarul de elemente5 (, n, (,uma elementelor 5 (, suma&7 G 2rototipul functiei (free%&( se gaseste in Dstdlib.*@ si este void free%void Jptr&7 ,patiul alocat de (calloc%&( si (malloc%&( ramane ocupat pana cand este eliberat de catre programator. ?cesta nu se elibereaza cand se iese dintr6o functie %in care s6a facut rezervarea de memorie&. n programul de mai sus, instructiunea a 1 calloc%n, sizeof%int&&7 este ec*ivalenta cu a 1 malloc%n J sizeof%int&&7 ,ingura diferenta este deci initializarea cu / in cazul functiei (calloc%&(.
666666666666 .xemplu5 .xemplu de citire interactiva a dimensiunii si a elementelor unei matrice de intregi
for %i 1 /7i D =7 LLi& for %< 1 /7< D =7 LL<& E printf%(aNKdONKdO1(, i, <&7 scanf%(Kd(, ptrLL&7 G G
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. ,crieti o functie care insumeaza elementele de rang %index& impar, respectiv par, ale unui vector cu elemente de tip (double(. ,ugestie5 functia poate incepe cam asa void suma%double aNO, int n, :J n 6 lungimea sirului a J: double Jimpar, double Jpar& E . . . . . 2. ;odificati programul de sortare cu bule astfel incat terminarea iteratiilor sa aiba loc cand nu se mai fac intersc*imbari de elemente. 3. Calculati valoarea unui determinant asociat unei matrice patratice. n cazul in care determinantul este nenul, calculati inversa matricei. 4. Calculati inversa unei permutari cu un numar constant de variabile suplimentare ,iruri de caractere si pointeri 1/.1. ;arcatorul (sfarsit de sir de caractere( F/ 1/.2. "olosirea pointerilor pentru procesarea unui sir 1/.3. 9rimiterea argumentelor catre (main%&( 1/.4. Hucrul cu sirurile din biblioteca standard 1/.!. Unde este eroarea ? 1/.$. .xercitii propuse spre implementare
111111111 Capitolul 1/ 111111111 1111111111111111111111 ,iruri de caractere si pointeri 1111111111111111111111 Un caracter dintr6un sir de caractere (a( poate fi accesat folosind indexul sirului %aNiO, de exemplu& sau folosind pointeri la caracter.
666666666666666666666666666666666666666666666666666666 ;arcatorul (sfarsit de sir de caractere( F/ 666666666666666666666666666666666666666666666666666666 2rin conventie, un sir de caractere se termina prin marcatorul %santinela, delimitator& F/, sau caracterul nul. 8e exemplu, sirul (abc( este memorat pe 4 caractere, ultimul fiind F/. 8eci numarul de elemente al sirului este 3, iar dimensiunea 4. 66666666666 .xemplu5 66666666666 #define ;?>Y408 1// void main%& E c*ar )N;?>Y408O7 . . . . . G nitializarea %citirea& unui sir se poate face in mai multe moduri5 1. nitializarea fiecarui element cu cate un caracter5 )N/O 1 P?P7 )N1O 1 PIP7 )N2O 1 PCP7 )N3O 1 PF/P7 2. "olosind functia (scanf%&(5 scanf%(Ks(, )&7
"ormatul (Ks( este folosit pentru citirea unui sir de caractere. 8istingem trei pasi5 6 pozitionare pe primul caracter al sirului7 6 se citesc toate caracterele diferite de D.nter@ si se introduc in ()(7 6 citirea se face pana cand intalnim .4"7 acum se plaseaza la sfarsitul sirului PF/P. 8in moment ce numele unui sir este un pointer la adresa de baza a sirului, expresia ()( este ec*ivalenta cu (R)N/O(. 8aca sirul citit are mai multe caractere decat cele rezervate, atunci se va obtine o eroare. ?tentie S PaP si (a( sunt diferite. 2rima este o constanta caracter, iar a doua este o constanta sir de caractere. 66666 666666 (a( 1 B PaP B PF/P B 66666 666666 3. ,irurile se pot initializa la fel ca si caracterele c*ar sNO 1 (abc(7 sau ec*ivalent c*ar sNO 1 EPaP, PbP, PcP, PF/PG7 4. 2utem folosi si un pointer catre un sir constant, dar interpretarea este diferita5 c*ar Jp 1 (abc(7 Va reamintim ca numele unui sir poate fi tratat ca un pointer catre adresa de baza a sirului din memorie. Constanta (abc( este memorata de catre compilator. n acelasi timp, aceasta este (un nume de sir(. ?sadar, diferenta dintre un sir initializat cu o constanta sir si un pointer initializat tot cu o constanta sir este ca sirul contine caractere individuale urmate de caracterul (F/(, in timp ce pointerul este asignat cu adresa sirului constant din memorie.
66666666666 .xemplu5 Utilizarea sirurilor de caractere %ca vectori&. 66666666666 Citim o linie de caractere dintr6un sir, le tiparim in ordine inversa si adunam literele din sir.
printf%(Fn,alutS Care este numele tau? (&7 for %i 1 /7 %c 1 getc*ar%&& S1 PFnP7 LLi& E nameNiO 1 c7 if %isalp*a%c&& sum L1 c7 G nameNiO 1 PF/P7 printf%(FnKsKsKsFnKs(, (;a bucur ca te6am intalnit (,name,(.(, (=umele tau scris invers este (&7 for %66i7 i @1 /7 66i& putc*ar%nameNiO&7 printf%(FnKsKdKsFnFnKsFn(, (si numele tau are (, sum,( litere .(, (Ha revedere. (&7 G
666666666666666666666666666666666666666666666666666666666666 "olosirea pointerilor pentru procesarea unui sir 666666666666666666666666666666666666666666666666666666666666 Vom discuta despre folosirea pointerilor pentru procesarea unui sir si cum se pot folosi acestea pentru a fi transmise ca parametri unei functii. Vom scrie un exemplu de program interactiv care citeste intr6un sir o linie de caractere introdusa de utilizator. 2rogramul va crea un nou sir si6l va tipari. 666666666666 .xemplu5 666666666666 #include Dstdio.*@ #define ;?>H=. 1//
void main%& E c*ar linieN;?>H=.O, Jsc*imba%c*ar J&7 void citesteCin%c*ar J&7
printf%(Fn8ati un sir5(&7 citesteCin%linie&7 printf%(FnKsFnFnKsFnFn(, (?sa arata sirul dupa sc*imbare5(, sc*imba%linie&&7 G
void citesteCin%c*ar sNO& E int c, i 1 /7
)*ile %%c 1 getc*ar%&& S1 .4" RR c S1 PFnP& sNiLLO 1 c7 sNiO 1 PF/P7 G
JpLL 1 PFtP7 for % 7 Js S1 PF/P7 LLs& if %Js 11 PeP& JpLL 1 P.P7 else if %Js 11 P P& E JpLL 1 PFnP7 JpLL 1 PFtP7 G else JpLL 1 Js7 Jp 1 PF/P7 return sirCnou7 G 66666666666 ntrebare5 8e ce vectorul (sirCnou( a fost declarat static ? 66666666666 8eoarece numele (sirCnou( este tratat ca un pointer catre adresa de baza a sirului. "iind declarat (static(, acesta se pastreaza in memorie si dupa ce se iese din functia (sc*imba%&(. ?cest lucru nu s6 ar fi intamplat si daca, de exemplu, sirul ar fi fost declarat (auto(. 66666666666 .xemplu5 "unctie C pentru numararea cuvintelor unui sir de caractere 66666666666 #include DctMpe.*@
int numarareCcuvinte%c*ar Js& E int contor 1 /7
)*ile %Js S1 PF/P& E )*ile %isspace%Js&& :J sarim spatiile goale J: LLs7 if %Js S1 PF/P& :J gasim un cuvant J: E LLcontor7 )*ile %Sisspace%Js& RR Js S1 PF/P& :J sarim peste cuvant J: LLs7 G G return contor7 G
6666666666666666666666666666666666666666666666666666 9rimiterea argumentelor catre (main%&( 6666666666666666666666666666666666666666666666666666 C pune la dispozitie siruri de orice tip, inclusiv siruri de pointeri. 2entru scrierea de programe care folosesc argumente in linia de comanda, trebuie sa folosim siruri de pointeri catre caractere. 2entru aceasta, functia (main%&( foloseste doua argumente, numite generic (argc( si (argv(. 66666666666 .xemplu5 66666666666 #include Dstdio.*@
void main%int argc, c*ar JargvNO& E int i7
printf%(argc 1 KdFn(, argc&7 for %i 1 /7 i D argc7 LLi& printf%(argvNKdO 1 KsFn(, i, argvNiO&7 G
Variabila (argc( precizeaza numarul de argumente din linia de comanda. ,irul (argv( este un sir de pointeri catre caracter si poate fi gandit ca vector de siruri de caractere. 8eoarece elementul (argvN/O( contine intotdeauna numele comenzii, rezulta ca valoarea lui (argc( va fi mai mare sau egala cu 1. Compilam programul de mai sus si obtinem executabilul (prog1.exe(. 8aca dam comanda prog1 atunci pe ecran se va afisa argc 1 1 argvN/O 1 prog1 8aca dam comanda prog1 fisier1 fisier2 atunci pe ecran se va afisa argc 1 3 argvN/O 1 prog1 argvN1O 1 fisier1 argvN2O 1 fisier2 2arametrul (argv( s6ar fi putut declara si astfel c*ar JJargv7 ?cesta este un pointer catre pointer catre (c*ar( si acesta poate fi gandit ca un sir de pointeri catre (c*ar(, care la randul lor pot fi ganditi ca vector de siruri de caractere. 4bservati ca nu alocam spatiu in memorie pentru sirurile din linia de comanda. ?cest lucru este facut de insusi sistemul C cand atribuie valori pentru argumentele (argc( si (argv(.
66666666666666666666666666666666666666666666666666666 Hucrul cu sirurile din biblioteca standard 66666666666666666666666666666666666666666666666666666 Iiblioteca standard Dstring.*@ contine multe functii utile pentru lucrul cu siruri de caractere. ,irurile ce sunt argumente trebuie terminate cu PF/P si toate returneaza un intreg sau o valoare a unui pointer catre (c*ar(. Cateva functii utile pentru lucrul cu siruri de caractere 666666666666666666666666666666666666666666666666666666666666666666 6 c*ar Jstrcat%c*ar Js1, const c*ar Js2&7 "unctia primeste doua argumente, le concateneaza si pune rezultatul in (s1(. 2rogramatorul trebuie sa verifice daca (s1( are suficient spatiu pentru pastrarea rezultatului. ,e returneaza sirul (s1(. 6 int strcmp%const c*ar Js1, const c*ar Js2&7 ,unt trimise doua siruri de caractere si se returneaza un intreg care este mai mic strict, egal sau mai mare strict decat / dupa cum (s1( este mai mic, egal sau mai mare lexicografic decat (s2(. 6 c*ar JstrcpM%c*ar Js1, const c*ar Js2&7 ,irul (s2( este copiat in (s1( pana cand se intalneste PF/P. Ceea ce se gaseste in (s1( se suprascrie. ,e presupune ca (s1( are suficient spatiu pentru pastrarea rezultatului. ,e returneaza valoarea lui (s1(. 6 unsigned strlen%const c*ar Js&7 2astreaza numarul de caractere inaintea lui PF/P. 6666666666666666666666666666666666666666666666666666666666666666 ?ceste functii sunt scrise in C si sunt foarte scurte. Variabilele din ele sunt de obicei declarate (register( pentru a face executia mai rapida.
6666666666 .xemplu5 "unctia (strlen%&( %o varianta&. 6666666666 unsigned strlen%const c*ar Js& E register int n 1 /7
for % 7 Js S1 PF/P7 LLs& LLn7 return n7 G 66666666666666666666666666666666666666666666666666666666666 B 8eclaratii si initializari B 66666666666666666666666666666666666666666666666666666666666 B c*ar s1NO 1 (tara noastra frumoasa si bogata(, B B s2NO 1 (facultatea de informatica(7 B 66666666666666666666666666666666666666666666666666666666666 B .xpresie B Valoare B 66666666666666666666666666666666666666666666666666666666666 B strlen%s1& B 31 B B strlen%s2 L +& B 1' B B strcmp%s1, s2& B numar pozitiv B 66666666666666666666666666666666666666666666666666666666666 B nstructiune B Ce se va tipari ? B 66666666666666666666666666666666666666666666666666666666666 B printf%(Ks(, s1 L 13&7 B frumoasa si bogata B B strcpM%s2 L 11, s1 L 2!&7B B B strcat%s2, (Fn(&7 B B B printf%(Ks(, s2&7 B facultatea bogata B 66666666666666666666666666666666666666666666666666666666666
6666666666666666666666666 Unde este eroarea ? 6666666666666666666666666 1. c*ar sN14O7 strcpM%s, (Ce mai faci ?Fn(&7 2. c*ar sN14O7 scanf%(Ks(, Rs&7
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. "olosind (argc( si (argv( %si eventual optiunea 6c& tipariti cu litere ma<uscule argumentele din (argv(. 2. ,crieti o functie proprie (strncmp%&( %extrageti din [elp definitia si prototipul&. 3. 2resupunem ca avem declaratia si initializarea5 c*ar JpN2ON3O 1 E (abc(, (defg(, (*i(, (<3lmno(, (pZrstuv)(, (xMz( G7 Completati urmatorul tabel %incercati intai sa nu rulati programul C&. 66666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare B 6666666666666666666666666666666666666666666666666666666666666666 B JJJp B pN/ON/ON/O B PaP B B JJpN1O B B B B JJ%pN1O L 2& B B B BJ%J%p L 1& L 1&N'O B B eroare B B%J%J%p L 1& L 1&&N'OB B B B J%pN1ON2O L 2& B B B 66666666666666666666666666666666666666666666666666666666666666666 4. "olosind (scanf%&( cititi ' siruri de caractere, dupa care folosind (strcmp%&( sortati6le alfabetic %eventual cu (bubble sort(&. !. %J& ,crieti un program similar cu exercitiul 4 care sorteaza si afiseaza argumentele din linia de comanda. 8irective preprocesor si metodologie de programare 11.1. "olosirea lui #include 11.2. "olosirea lui #define 11.3. ,intaxa (dulce( 11.4. ;acrouri cu argumente 11.!. Unde este greseala ? 11.$. 8efinitii de tipuri si macrouri din Dstddef.*@ 11.'. ,ortare folosind (Zsort%&( 11.+. Un exemplu de utilizare a macrourilor cu argumente 11.-. Compilare conditionala 11.1/. ;acrouri predefinite 11.11. 4peratorii # si ## 11.12. ;acroul (assert%&( 11.13. "olosirea lui #error si #pragma 11.14. =umerele liniilor unui program 11.1!. .xercitii propuse spre implementare
111111111 Capitolul 11 111111111
111111111111111111111111111111111111111 8irective preprocesor si metodologie de programare 111111111111111111111111111111111111111 666666666666666666666666666 "olosirea lui #include 666666666666666666666666666 ?m discutat de<a folosirea directivelor de preprocesare #include Dstdio.*@ #include Dstdlib.*@ 4 alta forma pentru #include este #include (numeCfisier( 2reprocesorul va inlocui aceasta linie cu o copie a fisierului precizat. ;ai intai cautarea se face in directorul curent, apoi in alte locuri dependente de sistem. 8aca directiva este de forma #include DnumeCfisier@ atunci preprocesorul va cauta in alte locuri %deci nu in directorul curent&. 8e exemplu, sub U=>, fisierele *eader standard %cum ar fi (stdio.*(, (stdlib.*(& se gasesc de obicei in directorul :usr:include ,ub ;,684,, aceste fisiere se gasesc in directorul :include
66666666666666666666666666 "olosirea lui #define 66666666666666666666666666 8irectivele de preprocesare declarate cu (#define( au doua forme5 6 #define identificator sirCatomi 6 #define identificator%id,...,id& sirCatomi 4 definitie lunga %care nu dorim sa o scriem pe aceeasi linie poate fi continuata pe linia urmatoare punand un F %bac3slas*& la sfarsitul liniei curente&. n primul caz, compilatorul va inlocui fiecare aparitie a (identificatorului( prin (sirCatomi( in restul fisierului %de la pozitia curenta in <os& cu exceptia celor care sunt incadrate intre g*ilimele sau apostroafe. 66666666666 .xemple5 66666666666 #define =0C,.CC2.CU %$/ J $/ J 24& #define 2 3.141!-2$!3 #define C 2--'-2.4!+ :J viteza luminii in 3m:sec J: #define .4" %61& :J valoarea uzuala pt sfarsit de fisier J: #define ;?>=9 214'4+3$4' :J numarul intreg maxim pe 4 octeti J: #define 8;.=, 2!/ :J dimensiunea unui sir J: #define .2,H4= 1./e6- :J limita numerica J: 8eci, folosirea lui (#define( mareste claritatea si portabilitatea unui program.
66666666666666666666 ,intaxa (dulce( 66666666666666666666 ,e foloseste pentru evitarea unor greseli frecvente sau ca un moft. 666666666666 .xemplu5 #define .] 11 666666666666 ?ceasta declaratie a<uta programatorul sa nu mai confunde 1 cu 11. 666666666666 .xemplu5 #define do :J spatiu J: 666666666666 8e exemplu, acum putem simula instructiunea ()*ile( din C ca un ()*ile do( din 2ascal sau ?lgol. 8e exemplu, daca avem definitiile de sintaxa (dulce( de mai sus, putem spune ca instructiunile )*ile %i .] 1& do E . . . . . G si )*ile %i 11 1& E . . . . . G sunt ec*ivalente.
666666666666666666666666666666 ;acrouri cu argumente 666666666666666666666666666666 0evenim la forma a doua a macrourilor cu argumente5 #define identificator%id,...,id& sirCatomi 666666666666 .xemplu5 #define ,]%x& %%x& J %x&& 666666666666 dentificatorul x din #define este un parametru care va fi substituit in textul ce urmeaza. ,ubstitutia se face fara considerarea corectitudinii sintactice. 8e exemplu, ,]%' L )& este ec*ivalent cu %%' L )& J %' L )&& ntr6o maniera similara, ,]%,]%Jp&& este ec*ivalent cu %%%%Jp& J %Jp&&& J %%%Jp& J %Jp&&&& 4bservati deci ca folosirea parantezelor %de exemplu, %x&& are o importanta deosebita, altfel nu s6ar respecta ordinea de evaluare.
6666666666666666666666666 Unde este greseala ? #define ,]%x& %%x& J %x&&7 6666666666666666666666666 ;acrourile sunt folosite de obicei pentru a inlocui apelurile functiilor cu cod liniar %scurte si fara variabile suplimentare&. 66666666666 .xemplu5 ;acroul de mai <os defineste minimul a doua valori5 66666666666 #define min%x, M& %%%x& D %M&& ? %x& 5 %M&& 8upa aceasta definitie, o expresie de forma m 1 min%u, v& se poate expanda de catre preprocesor la m 1 %%%u& D %v&& ? %u& 5 %v&& "olosind aceasta definitie, putem defini minimul a patru valori, astfel #define min4%a, b, c, d& min%min%a,b&, min%c, d&& 4 macro6definitie poate folosi functii si macrouri in corpul lor.
66666666666 .xemple5 66666666666 #define ,]%x& %%x& J %x&& #define CUI%x& %,]%x& J %x&& #define "C24Y%x& sZrt%sZrt%CUI%x&&& 4 directiva de preprocesare de forma #undef identificator va anula definitia precedenta a identificatorului.
666666666666666666666666666666666666666666666666666666666 8efinitii de tipuri si macrouri din Dstddef.*@ 666666666666666666666666666666666666666666666666666666666 C pune la dispozitie facilitatea (tMpedef( pentru a asocia %redenumi& un tip cu unul specific. 66666666666 .xemplu5 tMpedef c*ar uppercase7 66666666666 8eclaratia de mai sus face tipul (uppercase( sinonim cu (c*ar(. 8e exemplu, declaratiile de mai <os sunt valide5 uppercase c, uN1//O7 "isierul *eader Dstddef.*@ contine cateva definitii de tip5 tMpedef int ptrdiffCt7 :J tip intors de diferenta pointerilor J: tMpedef s*ort )c*arCt7 :J tip caracter mare J: tMpedef unsigned sizeCt7 :J tipul sizeof J: 9ipul (ptrdiffCt( spune care este tipul returnat de o expresie implicata in diferenta a doi pointeri. n ;,684,, acesta depinde de modelul de memorie ales %tinM, s*ort, large, far, *uge&, pe cand in U=>, tipul folosit este (int(. 9ipul ()c*arCt( se foloseste pentru acele caractere care nu se pot reprezenta pe un octet %c*ar 6@ int&. 0eamintim ca operatorul (sizeof( este folosit pentru determinarea lungimii unui tip sau a unei expresii. 8e exemplu, (sizeof%double& 1 +(. 9ipul (sizeCt( este returnat de operatorul (sizeof(. Un macrou definit in Dstddef.*@ este #define =UHH /
666666666666666666666666666666666 ,ortare folosind (Zsort%&( 666666666666666666666666666666666 8aca avem o multime relativ mica de elemente, atunci putem sa folosim sortare cu bule sau metoda sortarii prin selectie directa %care sunt de ordinul 4%nA2&&. 8aca insa avem multe elemente, atunci este convenabil sa folosim metoda sortarii rapide %(Zuic3 sort(&. 2rototipul functiei (Zsort%&( se gaseste in Dstdlib.*@. ?cesta este void Zsort%void JarraM, sizeCt nCels, sizeCt elCsize, int compare%const void J, const void J&&7 ?rgumentele acestei functii au rolul5 arraM 6 sirul care va fi sortat7 nCels 6 numarul de elemente ale sirului7 elCsize 6 numarul de octeti necesar memorarii unui element7 compare 6 functia de comparare, ce se declara ca fiind int compare%const void J, const void J& "unctia de comparare are ca argumente doi pointeri catre void. ?ceasta returneaza un intreg care este mai mic, egal sau mai mare decat zero dupa cum primul argument este mai mic, egal sau mai mare decat al doilea argument.
66666666666 .xemplu5 66666666666 Vom scrie un program ce foloseste (Zsort%&(. nitializam un vector, il tiparim, il sortam cu (Zsort%&(, apoi il tiparim din nou.
int cmp%const void Jvp, const void JvZ&7 :J functia de comparare J: void init%double Ja, int n&7 void tiparesteCsir%double Ja, int n&7 void main%& E double aN=O7 init%a, =&7 tiparesteCsir%a, =&7 Zsort%a, =, sizeof%double&, cmp&7 tiparesteCsir%a, =&7 G int cmp%const void Jvp, const void JvZ& E const double Jp 1 %const double J&vp7 const double JZ 1 %const double J&vZ7 double diff 1 Jp 6 JZ7 return %%diff @1 /./& ? %%diff @ /./& ? 61 5 /& 5 L1&7 G void init%double Ja, int n& E int i7 srand%time%=UHH&&7 :J vezi rand%& J: for %i 1 /7 i D n7 LLi& aNiO 1 %rand%& K 1//1& : 1/./7 G void tiparesteCsir%double Ja, int n& E int i7 for %i 1 /7 i D n7 LLi& E if %i K $ 11 /& putc*ar%PFnP&7 printf%(K12.1f(, aNiO&7 G putc*ar%PFnP&7 G 6666666666 ntrebari5 1. Ce trebuie sa modificati pentru a obtine ordinea crescatoare a sirului ? 6666666666 2. Ce rol are (const( din declaratia lui (cmp%&( ?
6666666666666666666666666666666666666666666666666666666666666666666 Un exemplu de utilizare a macrourilor cu argumente 6666666666666666666666666666666666666666666666666666666666666666666 Vom relua problema de mai sus, dar vom folosi macrouri cu argumente. Vom scrie programul in doua fisiere, un fisier *eader (sort.*( si un fisier (sort.c(. "isierul *eader va contine directive de precompilare %#include, #define&, precum si prototipuri pentru functiile noastre. "isierul (sort.*( este5
#include Dstdio.*@ #include Dstdlib.*@ #include Dstring.*@ #include Dtime.*@ #define ; 32 #define = 11 #define parteCfractionara%x& %x 6 %int& x& #define caracterCaleator%& %rand%& K 2$ L PaP& #define realCaleator%& %rand%& K 1// : 1/./& #define =9%arraM, sz, tMpe& F if %strcmp%tMpe, (c*ar(& 11 /& F for %i 1 /7 i D sz7 LLi& F arraMNiO 1 caracterCaleator%&7 F else F for %i 1 /7 i D sz7 LLi& F arraMNiO 1 realCaleator%&7
#define 20=9%arraM, sz, sirCcontrol& F for %i 1 /7 i D sz7 LLi& F printf%sirCcontrol, arraMNiO&7 F putc*ar%PFnP&
int comparaCparteaCfractionara%const void J, const void J&7 int lexico%const void J, const void J&7
?cum, vom scrie restul codului pentru programul nostru, si anume fisierul (sort.c(. #include (sort.*(
int comparaCparteaCfractionara%const void Jvp, const void JvZ& E const float Jp 1 %const float J&vp, JZ 1 %const float J&vZ7 float x7 x 1 parteCfractionara%Jp& 6 parteCfractionara%JZ&7 return%%x D /./& ? 61 5 %x 11 /./& ? / 5 L1&7 G
int lexico%const void Jvp, const void JvZ& E const c*ar Jp 1 %const c*ar J&vp, JZ 1 %const c*ar J&vZ7 return%Jp 6 JZ&7 G
666666666666666666666666666666 Compilare conditionata 666666666666666666666666666666 2reprocesorul are directive pentru compilare conditionata. ?cestea pot fi folosite pentru dezvoltarea programelor si pentru scrierea codului mai portabil de la o masina la alta. "iecare directiva de forma #if expresieCintegralaCconstanta #ifdef identificator #ifndef identificator implica compilarea conditionata a codului care urmeaza pana la directiva de precompilare #endif 2entru compilarea codului de mai sus, in cazul lui #if trebuie ca expresia constanta sa fie diferita de zero %true&, in cazul lui #ifdef sau #ifdefined numele identificatorului trebuie sa fie definit anterior intr6o linie #define, fara interventia directivei #undef identificator n cazul lui #ifndef, numele identificatorului trebuie sa nu fie curent definit. .xpresia constanta integrala folosita intr6o directiva de precompilare nu poate contine operatorul (sizeof( sau un cast. 2oate insa, folosi operatorul de precompilare (defined( %valabil in ?=, C, dar nu si C traditional&. .xpresia defined identificator este ec*ivalenta cu defined%identificator& ?cesta se evalueaza la 1 daca identificatorul este definit, si / in caz contrar.
Uneori (printf%&( este utila in scopuri de depanare. 2resupunem ca la inceputul unui fisier am scris #define 8.IUQ 1 si in unele zone ale programului am scris #if 8.IUQ printf%(debug5 a 1 KdFn(, a&7 #endif 8aca dupa ce ne6am convins ca este bine ce se intampla si vrem sa nu mai vizualizam valoarea lui (a( in acest moment, atunci sc*imbam 8.IUQ in / %de exemplu&. 4 alta varianta ar fi sa nu initializam 8.IUQ. ,criem deci la inceputul fisierului #define 8.IUQ 2utem folosi #ifdef si #if si scriem5 #ifdef 8.IUQ . . . . . #endif
666666666666666666666666666 ;acrouri predefinite 666666666666666666666666666 n ?=, C sunt ! macrouri predefinite. =u pot fi redefinite de catre programator. .le au la inceput si sfarsit cate doua simboluri (underscore(. ;acro predefinit Valoare 6666666666666666666666666666666666666666666666666666666666666666 CC8?9.CC Un sir ce contine data curenta CC"H.CC Un sir ce contine numele fisierului CCH=.CC Un intreg reprezentand numarul liniei curente CC,98CCC 8aca implementarea1?=, C, atunci acesta reprezinta un numar diferit de zero CC9;.CC Un sir ce contine timpul curent 6666666666666666666666666666666666666666666666666666666666666666
6666666666666666666666 4peratorii # si ## 6666666666666666666666 4peratorii de preprocesare # si ## sunt valabili in ?=, C, dar nu si in C traditional. 4peratorul unar # cauzeaza transformarea in sir a unui parametru formal dintr6o macro6definitie. #define mesa<Cpentru%a, b& F printf%#a ( si ( #b (5 9e iubim SFn(& void main%& E mesa<Cpentru%Carolina, =icoleta&7 G
Ha apelul acestui macrou, fiecare parametru al acestuia este inlocuit cu argumentul corespunzator, iar # cauzeaza ca argumentele sa fie puse intre g*ilimele. ?ltfel spus, dupa preprocesare, in memorie se obtine5 void main%& E printf%(Carolina( ( si ( (=icoleta( (5 9e iubim SFn(&7 G 8eoarece sirurile constante separate prin spatiu se concateneaza, instructiunea de mai sus este ec*ivalenta cu5 void main%& E printf%(Carolina si =icoleta5 9e iubim SFn(&7 G 4peratorul binar ## este folosit la impartirea in to3enuri lexicale.
666666666666 .xemplu5 666666666666 #define >%i& x ## i >%1& 1 >%2& 1 >%3&7 va deveni dupa preprocesare x1 1 x2 1 x37
6666666666666666666666666 ;acroul (assert%&( 666666666666666666666666 ?=, C pune la dispozitie macroul (assert%&( din biblioteca standard (assert.*(. ?cest macrou poate fi folosit cand vrem sa ne asiguram ca o expresie are o anumita valoare. Vrem sa scriem o functie ale carei argumente satisfaca niste conditii. 66666666666 .xemplu5 66666666666 #include Dassert.*@ void f%c*ar Jp, int n& E . . . . . assert%2 S1 =UHH&7 assert%n @ / RR n D !&7 . . . . . G
8aca vreo asertiune esueaza, atunci sistemul va tipari un mesa< si va opri executia programului. ata o implementare posibila a lui (assert%&(. #if defined%=8.IUQ& #define assert%ignore& %%void& /& :J ignorare J: #else #define assert%expr& if %S%expr&& F E F printf%(FnKsKsFnKsKsFnKsKdFnFn, F (?ssertion failed5 (, #expr, F (in file (, CC"H.CC, F (al line (, CCH=.CC&7 F G #endif 8e remarcat ca daca =8.IUQ este definit, atunci sunt ignorate toate asertiunile. ?ceasta permite programatorului in timpul scrierii programului sa verifice pas cu pas executia programului. "unctia (abort%&( se gaseste in biblioteca standard.
6666666666666666666666666666666666666666 "olosirea lui #error si #pragma 6666666666666666666666666666666666666666 ?=, C contine si directivele de preprocesare #error si #pragma. 666666666666 .xemplu5 666666666666 #if ?C,U. D IC,U. #error (tipuri incompatibile( #endif 8aca in timpul compilarii va apare o eroare prezenta intr6o directiva #error, atunci se va afisa mesa<ul respectiv. 8irectiva #pragma se foloseste pentru folosire specifica implementarii. .a are forma generala5 #pragma atomiClexicali ?ceasta cauzeaza o comportare ce depinde de fiecare compilator C in parte.
6666666666666666666666666666666666666666 =umerele liniilor unui program 6666666666666666666666666666666666666666 4 directiva de preprocesare de forma #line constantaCintegrala (numeCfisier( va determina compilatorul sa renumeroteze liniile textului sursa astfel incat urmatoarea linie sa aiba valoarea specificata si numele fisierului sursa curent este (numeCfisier(. 8aca nu se precizeaza (numeCfisier(, atunci se va face doar numerotarea liniilor. Iineinteles, numerele asociate liniilor sunt ascunse pentru programator si apar numai la mesa<e de eroare sau avertismente.
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 6666666666666666666666666666666666666666666666 1. ,crieti propria voastra functie (Zuic3sort%&( care sa fie ec*ivalenta cu (Zsort%&( pus la dispozitie de sistemul C. 2. 8efiniti o macro6definitie pentru >40%&, numita (sau exclusiv(. Un apel >40%a,b&1true D1@ a este true si b false, sau a false si b true. ,crieti si o macro6definitie >40%a,b,c& si una >40%a,b,c,d&. 3. ,crieti un program C in care sa afisati valorile celor ! macrouri predefinite. 0ecursie 12.1. ;anipularea sirurilor folosind recursia 12.2. ;etodologia (divide6et6impera( 12.3. .xercitii propuse spre implementare
111111111111 Capitolul 12 111111111111
11111111 0ecursie 11111111 4 functie este recursiva daca se autoapeleaza, direct sau indirect. n C toate functiile se pot defini recursiv. 6666666666 .xemplu5 6666666666 #include Dstdio.*@ void numara%int n&7
void main%& E numara%1/&7 G
void numara%int n& E if %n& E printf%(Kd S (, n&7 numara%n 6 1&7 G else printf%(Qata SFn(&7 G
8upa executia acestui program, pe ecran se va tipari 1/ S - S + S ' S $ S ! S 4 S 3 S 2 S 1 S Qata S ?cest program s6ar fi putut realiza si iterativ %folosind o instructiune de tip )*ile&.
66666666666 .xemplu5 ,uma primelor n numere naturale. 66666666666 int suma%int n& E if %n D1 1& return n7 else return %n L suma%n 6 1&&7 G
8e obicei, functiile recursive urmeaza un (pattern( standard5 6 exista un caz de baza %sau mai multe&7 6 caz recursiv general %in care, in general, un intreg este trimis ca argument al apelului recursiv&7
0ecursia este un procedeu foarte puternic de rezolvare a problemelor. ,ecretul este identificarea cazului general. 2entru exemplul precedent, cand se trimite n catre functia (suma%&(, recursia activeaza n copii ale functiei inaintea intoarcerii pas cu pas catre primul apel recursiv %se mai spune ca in momentul apelului recursiv, variabilele locale (ing*eata(, ele (dezg*etandu6se( la intoarcerea din recursie&. ;ulte functii recursive se pot scrie intr6o forma iterativa %folosind structuri de tip ()*ile(, se mai spune (derecursivare(&. 0ecursia se recomanda cand problema se poate rezolva foarte usor folosind recursie si cand nu se cere o eficienta sporita in timpul executiei programului. Uneori, se recomanda recursia finala %adica dupa apelul recursiv nu mai sunt alte instructiuni si nu exista variabile locale&.
66666666666 .xemplu5 Citeste o linie si o afiseaza in ordine inversa, apoi lasa 66666666666 doua randuri goale.
#include Dstdio.*@ void tipareste%void&7
void main%& E printf%(ntroduceti o linie5 (&7 tipareste%&7 printf%(FnFn(&7 G
void tipareste%void& E c*ar c7 if %%c 1 getc*ar%&& S1 PFnP& tipareste%&7 putc*ar%c&7 G
ata o rulare in executie5 ntroduceti o linie5 iepurasu usa rupei
iepur asu usarupei 4bservati in exemplul precedent ca la fiecare apel recursiv, se memoreaza in stiva caracterul (c( legat la o valoare, care se va afisa la intoarcerea din recursie. 8eci practic, sunt (n( copii ale lui (c(, unde (n( reprezinta lungimea liniei.
66666666666 .xemplu5 66666666666 2utem complica putin exemplul precedent, in sensul ca afisam aceleasi cuvinte, dar in ordine inversa. #include DctMpe.*@ #include Dstdio.*@
void main%& E printf%(ntroduceti o linie5 (&7 tiparesteCcuvinte%&7 printf%(FnFn(&7 G
void tiparesteCcuvinte%void& E c*ar )N;?>Y408O7
citesteCcuvant%)&7 if %)N/O S1 PFnP& tiparesteCcuvant%&7 printf%(Ks (, )&7 G
void citesteCcuvant%c*ar Js& E static c*ar c 1 PF/P7
if %c 11 PFnP& JsLL 1 c7 else )*ile %Sisspace%c 1 getc*ar%&&& JsLL 1 c7 Js 1 PF/P7 G
8aca, la executie, utilizatorul scrie5 ntroduceti o linie5 noi invatam C atunci pe ecran, va apare5 C invatam noi Variabila (c( avand clasa de memorare (static(, rezulta ca valoarea ei se pastreaza de la un apel la altul. 8e altfel, initializarea lui (c( se face o singura data %cand se intra prima data in aceasta functie&. 8aca (c( ar fi fost de tip (auto(, atunci c*iar daca aveam la sfarsitul sirului PFnP, la urmatorul apel, acesta nu ar fi fost cunoscut, deci practic nu mai aveam conditie de oprire.
66666666666 .xemplu5 66666666666 n acest exemplu, vom desena (pattern6uri( pe ecran folosind functii recursive. #include Dstdio.*@ #define ,^;I4H PJP #define 4"",.9 / #define H.=Q9[ 1-
void displaM%c*ar c, int m, int n& E if %n @ /& E dra)%P P, m&7 dra)%c, n&7 putc*ar%PFnP&7 displaM%c, m L 2, n 6 4&7 G G
void dra)%c*ar c, int 3& E if %3 @ /& E putc*ar%c&7 dra)%c, 3 6 1&7 G G
"unctia (main%&( contine apelul functiei (displaM%&(, care apeleaza (dra)%&(, care la randul ei apeleaza (displaM%&(. 8eci functia (displaM%&( este recursiva. "unctia (dra)%&( tipareste 3 copii ale caracterului (c(. 2e ecran se va afisa5 J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J J
6666666666666666666666666666666666666666666666666666 ;anipularea sirurilor folosind recursia 6666666666666666666666666666666666666666666666666666 Un sir consta dintr6un numar de caractere consecutive, terminate prin caracterul PF/P. 8e fapt, putem gandi un sir ca fiind sirul nul %care consta doar din caracterul PF/P& sau un caracter urmat de un sir. ?ceasta definitie a sirului este o structura de date recursiva. 66666666666 .xemplu5 4 definitie recursiva a lungimii unui sir. 66666666666 int rCstrlen%c*ar Js& E if %Js 11 PF/P& return /7 else return %1 L rCstrlen%s L 1&&7 G .leganta acestei formulari recursive este (platita( de o pierdere in timpul executiei. 8aca sirul are lungimea 3, calcularea lungimii sale necesita 3 L 1 apeluri recursive %un compilator optimizat poate evita aceasta pierdere&.
666666666666666666666666666666666666666666 ;etodologia (divide6et6impera( 66666666666666666666666666666666666666666 0ecursia se foloseste in foarte multe cazuri pentru codificarea algoritmilor (divide6et6impera(. Un astfel de algoritm imparte problema in subprobleme, rezolvand fiecare subproblema prin recursie, apoi recombina solutiile partiale pentru a obtine intreaga solutie. Vom considera un exemplu cunoscut, si anume, determinarea minimului si maximului elementelor unui sir de intregi %publicat pentru prima data de catre ra 2o*l, (? ,orting 2roblem and ts ComplexitM(, Communications of t*e ?C;, 1!, nr. $, 1-'2& considerat cel mai bun algoritm pentru aceasta problema. Criteriul pentru (cel mai bun( a fost numarul de comparatii necesare. 2rezentam mai <os o functie C care rezolva aceasta problema %considerand dimensiunea sirului putere a lui 2&. void minmax%int aNO, int n, int JminCptr, int JmaxCptr& E int min1, max1, min2, max27
if %n 11 2& if %aN/O D aN1O& E JminCptr 1 aN/O7 JmaxCptr 1 aN1O7 G else E JminCptr 1 aN1O7 JmaxCptr 1 aN/O7 G else E minmax%a, n:2, Rmin1, Rmax1&7 minmax%a L n:2, n:2, Rmin2, Rmax2&7 if %min1 D min2& JminCptr 1 min17 else JminCptr 1 min27 if %max1 D max2& JmaxCptr 1 max27 else JmaxCptr 1 max17 G G
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. ,crieti o functie C recursiva ec*ivalenta cu (strncmp%&(. 2. ,crieti o functie C recursiva care calculeaza media aritmetica a unui sir de numere reale. 3. ,crieti o functie C recursiva care calculeaza nS, unde n este un numar natural. 4. %;utarea calului& 8ata o tabla de sa* %+ x +&, sa se scrie o functie C recursiva care descrie mutarile calului astfel incat orice pozitie sa fie parcursa o singura data. ,tructuri si liste inlantuite 13.1. 8eclararea structurilor 13.2. ?ccesarea unui membru 13.3. ?sociativitatea si precedenta operatorilor %tabelul complet& 13.4. ,tructuri, functii si asignari 13.!. nitializarea structurilor 13.$. "olosirea lui (tMpedef( 13.'. ,tructuri recursive %self6referential& 13.+. Histe liniar inlantuite 13.-. 4peratii pentru liste 13.1/. Crearea unei liste 13.11. =umarare si cautare 13.12. nserare si stergere 13.13. .xercitii propuse spre implementare
111111111 Capitolul 13 111111111
11111111111111111111 ,tructuri si liste inlantuite 11111111111111111111 9ipul structura permite programatorului sa imbine mai multe componente intr6o singura variabila. Componentele structurii au nume distincte si se numesc membrii. ;embrii unei structuri pot avea tipuri diferite. 8eci, ca si pointerii si sirurile, structurile sunt considerate un tip derivat. ?ccesarea membrilor unei structuri se face cu (.( sau cu (6@( care au cea mai inalta prioritate %ca si %& si NO&.
666666666666666666666666666666 8eclararea structurilor 666666666666666666666666666666 ,e face folosind cuvantul rezervat (struct(. ata un exemplu de declarare a cartilor de <oc5 66666666666 .xemplu5 8eclaratia de mai <os creaza tipul de data (carteCdeC<oc(5 66666666666 struct carteCdeC<oc E int numar7 c*ar culoare7 G7 ?stfel cartea 3 de trefla va avea (numar13( si (culoare1PtP(. Celelalte caractere pentru culorile cartilor sunt %frunza 6 PfP, caro 6 PcP, inima 6 PiP&. =umele structurii poate fi folosit acum pentru declararea variabilelor de acest tip. ?bia in acest moment se rezerva loc in memorie pentru aceste variabile5 struct carteCdeC<oc c1, c27 2entru accesarea membrilor lui c1 si c2, folosim operatorul (.(. 666666666666 .xemplu5 666666666666 c1.numar 1 37 c1.culoare 1 PtP7 c2.numar 1 127 c2.culoare 1 PcP7 4 constructie de forma variabilaCstructura . numeCmembru este folosita ca o variabila in acelasi mod ca o simpla variabila sau ca un element al unui sir. =umele unui membru trebuie sa fie unic intr6o structura specificata. 8in moment ce membrii trebuie intotdeauna prefixati de un identificator de variabila de structura unic, atunci nu vor fi confuzii %ambiguitati& intre doi membri cu acelasi nume, dar din structuri diferite. 666666666666 .xemplu5 666666666666 struct fruct E c*ar numeN1!O7 int calorii7 G
struct leguma E c*ar numeN1!O7 int calorii7 G
struct fruct a7 struct leguma b7
2utem accesa (a.calorii(, respectiv (b.calorii( fara ambiguitate. 2utem declara variabile de un tip structurat in timpul declararii acestuia.
666666666666 .xemplu5 666666666666 struct carteCdeC<oc E int numar7 c*ar culoare7 G c1, c2, c3N!2O7 dentificatorul (carteCdeC<oc( este numele structurii. dentificatorii (c1( si (c2( se declara ca fiind variabile de tip (struct carteCdeC<oc(, iar identificatorul (c3( ca fiind un sir de tip (struct carteCdeC<oc(. 8aca insa lipseste numele structurii, atunci singura data cand se pot declara variabile de tip structura este in momentul declararii acesteia.
666666666666 .xemplu5 666666666666 struct E c*ar Jnume7 int nrCstudent7 float medie7 G s1, s2, s37 n aceasta structura se declara trei variabile de tip structura, insa lipsind numele structurii inseamna ca nu se mai pot declara si alte variabile de acest tip. 8aca, de exemplu, scriem struct student E c*ar Jnume7 int nrCstudent7 float medie7 G7 atunci (student( este numele structurii si nu sunt variabile declarate in acest moment. ?cum putem scrie struct student temp, clasaN1//O7 si declaram (temp( si (clasa( de tip (struct student(.
6666666666666666666666666666666 ?ccesarea unui membru 6666666666666666666666666666666 n cele ce urmeaza, prezentam un exemplu de folosire a operatorului de membru (.(. 666666666666 .xemplu5 n fisierul (clCinfo.*( scriem5 666666666666 #define =0C,9U8.=9 1// struct student E c*ar Jnume7 int nrCstudent7 float medie7 G7 n alt fisier, scriem #include (clCinfo.*( void main%& E struct student temp, clasaN=0C,9U8.=9O7 . . . . . G 2utem avea instructiuni de asignare cum ar fi5 temp.medie 1 4.//7 temp.nume 1 (onescu(7 temp.nrCstudent 1 1/237 n continuare, scriem o functie care numara studentii cu media 4.//5 int esec%struct student clasaNO& E int i, contor 1 /7
for %i 1 /7 i D =0C,9U8.=97 LLi& contor L1 clasaNiO.medie 11 4.//7 return contor7 G C pune la dispozitie operatorul pointer catre structura 6@ pentru accesarea membrilor unei structuri relativ la un pointer %,imbolul 6@ este format din caracterul 6 %minus& si @ %mai mare&&. 8aca o variabila pointer este asignata cu adresa unei structuri, atunci un membru al structurii poate fi accesat printr6o constructie de forma5 pointerCcatreCstructura 6@ numeCmembru Iineinteles, o constructie ec*ivalenta este5 %JpointerCcatreCstructura&.numeCmembru 2arantezele sunt necesare deoarece operatorii (.( si (6@( au prioritate mare si se asociaza de la stanga la dreapta. ?stfel, parantezele sunt obligatorii, deoarece in caz contrar, daca in expresia de mai sus nu ar fi fost paranteze, atunci aceasta ar fi ec*ivalenta cu J%pointerCcatreCstructura.numeCmembru&
666666666666 .xemplu5 "ie urmatoarele declaratii si asignari5 666666666666 struct student temp, Jp 1 Rtemp7 temp.medie 1 1/.//7 temp.nume 1 (onescu(7 temp.nrCstudent 1 12/47 ?tunci obtinem urmatorul tabel5 6666666666666666666666666666666666666666666666666666666666666666666666666666 B .xpresie B .xpresie ec*ivalenta B Valoare conceptuala B 6666666666666666666666666666666666666666666666666666666666666666666666666666 B temp.medie B p 6@ medie B 1/.// B B temp.nume B p 6@ nume B onescu B B temp.nrCstudent B p 6@ nrCstudent B 12/4 B B %Jp&.nrCstudent B p 6@ nrCstudent B 12/4 B 6666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666666666666666666666666666666666666666666 ?sociativitatea si precedenta operatorilor %tabelul complet& 666666666666666666666666666666666666666666666666666666666666666666666666666 66666666666666666666666666666666666666666666666666666666666666666666666666666 B 4peratori B ?sociativitate B 66666666666666666666666666666666666666666666666666666666666666666666666666666 %& NO . 6@ LL %postfix& 66 %postfix& B de la stanga la dreapta B 66666666666666666666666666666666666666666666666666666666666666666666666666666 LL %prefix& 66 %prefix& S X sizeof %tip& B de la dreapta B L %unar& 6 %unar& R %adresa& J %dereferentiere& B la stanga B 666666666666666666666666666666666666666666666666666666666666666666666666666666 J : K B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 L 6 B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 DD @@ B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 D D1 @ @1 B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 11 S1 B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 R B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 A B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 B B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 RR B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 BB B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 ?5 B de la dreapta la stanga B 666666666666666666666666666666666666666666666666666666666666666666666666666666 1 L1 61 J1 :1 K1 @@1 DD1 R1 A1 B1 B de la dreapta la stanga B 666666666666666666666666666666666666666666666666666666666666666666666666666666 , %operatorul virgula& B de la stanga la dreapta B 666666666666666666666666666666666666666666666666666666666666666666666666666666 4peratorul (,( are cea mai mica prioritate dintre toti operatorii C. Virgula folosita in declaratii si in lista de argumente ale functiilor nu este operator. 666666666666 .xemple5 .xpresia a 1 1, b 1 2 este o expresie virgula. ntai se evalueaza (a 1 1(, apoi (b 1 2(, iar valoarea si tipul returnat de expresia virgula sunt cele returnate de (b 1 2(, adica valoarea (2( si tipul (int(.
Un exemplu frecvent unde apare operatorul virgula este (for(. 8e exemplu, for %i 1 /, < 1 17 i D H;97 i L1 2, < L12& . . . . . Va amintiti ca operatorul unar (sizeof( poate fi folosit pentru determinarea numarului de octeti necesar memorarii sale. 8e exemplu, expresia sizeof%struct carteCdeC<oc& va intoarce numarul de octeti necesari sistemului pentru memorarea unei variabile de tip (struct carteCdeC<oc(. 2e cele mai multe sisteme tipul returnat de expresie este (unsigned(.
66666666666666666666666666666666666 ,tructuri, functii si asignari 66666666666666666666666666666666666 C traditional permite unui pointer catre un tip structura sa fie transmis ca argument al unei functii si returnat ca o valoare. ?=, C permite c*iar unei structuri sa fie trimisa ca argument pentru functii si returnata ca valoare. 8e exemplu, daca (a( si (b( sunt structuri, atunci expresia de asignare (a 1 b( este valida. ?ceasta implica ca fiecare valoare a unui membru din structura (a( devine egala cu valoarea membrului corespunzator din structura (b(. n C, structurile, pointerii si vectorii pot fi combinati pentru crearea unor structuri de date complicate. 66666666666 .xemplu5 Iaza de date cu studenti 66666666666 n fisierul (student.*(5
#define =0C,9U8.=9 !/ #define =0CCU0,U0 1/
struct student E c*ar Jnume7 int nrCstudent7 float medie7 G7
struct data E s*ort zi7 c*ar lunaN1/O7 s*ort an7 G7
struct persoana E c*ar numeN2/O7 struct data ziCnastere7 G7
struct dateCstudent E struct persoana p7 int nrCstudent7 float medieN=0CCU0,U0O7 G7 4bservati ca (struct dateCstudent( este construita cu structuri imbricate. 8e exemplu, daca avem declaratia5 struct dateCstudent temp7 atunci expresia5 temp.p.ziCnastere.lunaN/O are ca valoare prima litera a lunii datei de nastere a studentului asociat lui (temp(. n continuare, vom scrie o functie (citesteCdate%&( pentru a introduce date in variabile de tip (struct date(. Ha apelul functiei, trebuie trimisa adresa variabilei ca argument. 66666666666 .xemplu5 66666666666 #include (student.*(
void citesteCdate%struct data Jz& E printf%(8ati ziua%int& luna%string& an%int&5 (&7 scanf%(K*dKsK*d(, Rz 6@ zi, z 6@ luna, Rz 6@ an&7 G
"ormatul K*d este folosit pentru conversia caracterelor de la tastatura la o valoare de tip (s*ort(.
6666666666666 ntrebare5 8e ce (z 6@ luna( nu contine operatorul de adresa ? 6666666666666 "unctia (citesteCdate%&( poate fi folosita pentru citirea informatiei intr6o variabila de tip (struct dateCstudent( astfel5
struct dateCstudent temp7
citesteCdate%Rtemp.p.ziCnastere&7
66666666666666666666666666666666 nitializarea structurilor 66666666666666666666666666666666 9oate variabilele externe si statice, inclusiv variabilele de structura, care nu sunt explicit initializate, sunt automat initializate de catre sistem cu zero. n C traditional, structurile statice si externe pot fi initializate de catre programator. n ?=, C, putem initializa si structuri definite (auto(. ,intaxa este similara celei folosite la siruri. 4 variabila structura poate fi urmata de semnul (1( si o lista de constante cuprinse intre acolade. 8aca nu sunt suficiente valori pentru asignarea lor, atunci membrii ramasi sunt asignati cu zero implicit. 66666666666 .xemple5 struct carteCdeC<oc c 1 E12, PtPG7 66666666666 struct complex E double real7 double imaginar7 G mN3ON3O 1 E EE1./, 6/.!G, E2.!, 1./G, E/.', /.'GG, EE'./, 6$.!G, E6/.!,1.!G,E4!.',+./GG, G7 ,e observa imediat ca linia (mN2ONO( este initializata cu /.
666666666666666666666666666666 "olosirea lui (tMpedef( 666666666666666666666666666666 "acilitatea (tMpedef( este deseori folosita pentru redenumirea unui tip structura. 66666666666 .xemple5 66666666666 tMpedef c*ar J string7 tMpedef int lungime7 tMpedef float vectorN1/O7 tMpedef double %J2"8&%double&7 8upa aceste redenumiri, putem face declaratiile5 lungime l1, l27 string s1 1 (abc(, s2 1 (xMz(7 vector x7 ?ceste declaratii sunt ec*ivalente cu5 int l1, l27 c*ar J s1 1 (abc(, s2 1 (xMz(7 float xN1/O7 :J ?tentie S ,e inlocuieste vector cu x J: Ha fel, declaratia 2"8 f7 este ec*ivalenta cu double %Jf&%double&7 .ste vorba mai sus de un pointer la o functie ce returneaza tipul (double(.
6666666666666666666666666666666666666666666666 ,tructuri recursive %self6referential& 6666666666666666666666666666666666666666666666 4 structura este recursiva daca un membru pointer se refera la tipul structurii initiale %recursie de ordinul 1, exista si ordine mai mari&. 8e obicei, structurile recursive necesita rutine explicite pentru rezervarea si eliberarea de memorie. 666666666666 .xemplu5 666666666666 struct lista E int data7 struct lista Jurmator7 G "iecare variabila de tip (struct lista( are doi membri, (data( si (urmator(. 2ictural, asta arata cam asa %in memorie&5 66666666666666 B B 6666B66@ 66666666666666 data urmator Variabila pointer (urmator( contine o adresa a unei locatii de memorie a unui element succesor (struct lista( sau valoarea speciala =UHH, definita in Dstdio.*@ ca avand valoarea constanta /. Valoarea =UHH este folosita pentru notarea sfarsitului listei. 2resupunem ca avem declaratiile struct lista a, b, c7 Vrem sa creeam o lista inlantuita formata din aceste trei variabile. ;ai intai, facem asignarile5 a.data 1 17 b.data 1 27 c.data 1 37 a.urmator 1 b.urmator 1 c.urmator 1 =UHH7 8upa aceste instructiuni, obtinem in memorie5 a b c 6666666666666666 6666666666666666 6666666666666666 B 1 B =UHH B B 2 B =UHH B B 3 B =UHH B 6666666666666666 6666666666666666 6666666666666666 data urmator data urmator data urmator
?cum putem (lega( cele trei structuri, astfel5 a.urmator 1 Rb7 b.urmator 1 Rc7
4btinem5 a b c 66666666666666 66666666666666 6666666666666666 B 1 B 666B6666@B 2 B 666B6666@B 3 B =UHH B 66666666666666 66666666666666 6666666666666666 data urmator data urmator data urmator
6666666666666666666666666666 Histe liniar inlantuite 6666666666666666666666666666 4 lista liniar inlantuita este o structura de date ce are elementele legate secvential. .xista un pointer catre primul element al listei, fiecare element al listei pointeaza catre urmatorul element al listei, avand ultimul element pointand catre =UHH. 8e obicei, o lista inlantuita se creaza dinamic. ,criem in fisierul (*eader( intitulat (list.*( urmatoarele declaratii5 #include Dstdio.*@ tMpedef c*ar 8?9?7
struct listaCinlantuita E 8?9? d7 struct listaCinlantuita Jnext7 G7
0elativ la alocarea dinamica, va reamintim ca functia (malloc%&( are un singur argument de tip (sizeCt( si intoarce un pointer catre (void( care pointeaza catre adresa de baza a spatiului de memorie alocat %evident, cauta spatiu suficient pentru un obiect&. ?stfel, daca (*ead( este o variabila de tip (H,9?(, atunci *ead 1 %H,9?& malloc%sizeof%.H.;.=9&&7 va produce o bucata din memorie menita sa memoreze un .H.;.=9 asignand adresa de baza pointerului (*ead(.
666666666666 .xemplu5 666666666666 2resupunem ca vrem sa creeam dinamic o lista liniar inlantuita pentru memorarea a trei caractere PnP, PeP si P)P. Considerand *ead 1 %H,9?& malloc%sizeof%.H.;.=9&&7 *ead 6@ d 1 PnP7 *ead 6@ next 1 =UHH7 obtinem un memorie ceva de genul5 6666666666666666 *ead 666@B PnP B =UHH B 666666666666666 d next
?l doilea element este adaugat de instructiunile5 *ead 6@ next 1 %H,9?& malloc%sizeof%.H.;.=9&&7 *ead 6@ next 6@ d 1 PeP7 *ead 6@ next 6@ next 1 =UHH7 n memorie avem5 666666666666 666666666666666 *ead666@B PnP B 666B666@B PeP B =UHH B 666666666666 666666666666666 d next d next
n sfarsit, adaugam si al treilea element5 *ead 6@ next 6@ next 1 malloc%sizeof%.H.;.=9&&7 *ead 6@ next 6@ next 6@ d 1 P)P7 *ead 6@ next 6@ next 6@ next 1 =UHH7 n memorie avem5 66666666666666 66666666666666 6666666666666666 *ead666@B PnP B 666B666@B PeP B 666B666@B P)P B =UHH B 66666666666666 66666666666666 6666666666666666 d next d next d next
66666666666666666666666666 4peratii pentru liste 66666666666666666666666666 4peratiile de baza pentru liste liniar inlantuite includ urmatoarele5 1. Crearea unei liste 2. =umararea elementelor unei liste 3. Cautarea unui element 4. nserarea unui element !. ,tergerea unui element 66666666666666666666666 Crearea unei liste 66666666666666666666666 Vom prezenta o varianta recursiva a acestei operatii, si anume vom crea o lista pornind de la un string. "unctia va returna un pointer catre primul element al listei. #include (list.*(
H,9? creare%c*ar sNO& E H,9? *ead7
if %sN/O 11 PF/P& return =UHH7 else E *ead 1 %H,9?& malloc%sizeof%.H.;.=9&&7 *ead 6@ d 1 sN/O7 *ead 6@ next 1 creare%s L 1&7 return *ead7 G G
66666666666666666666666666 =umarare si cautare 66666666666666666666666666 "unctia recursiva (numara%&( numara elementele unei liste parcurgand fiecare element pana intalneste pointerul =UHH. 8aca lista este vida, atunci se intoarce /, altfel numarul de elemente al listei. #include (list.*(
int numara%H,9? *ead& E if %*ead 11 =UHH& return / else return %1 L numara%*ead 6@ next&&7 G "unctia recursiva (cauta%&( cauta intr6o lista un element. 8aca este gasit acel element, atunci se intoarce un pointer catre acesta, altfel se intoarce pointerul =UHH. #include (list.*(
H,9? cauta%8?9? c, H,9? *ead& E if %*ead 11 =UHH& return =UHH7 else if %c 11 *ead 6@ d& return *ead7 else return %cauta%c, *ead 6@ next&&7 G
6666666666666666666666666 nserare si stergere 6666666666666666666666666 2ictural, asta ar arata cam asa %inainte de inserare&5
p1 66B p266B B B V V 66666666666666 66666666666666 ... 666@B ? B 666B666@B C B 666B666@ ... 66666666666666 66666666666666 66666666666666666 Z 666@B I B =UHH B 66666666666666666 8upa inserare, obtinem5 66666666666666 66666666666666 ... 666@B ? B B B B C B 666B666@ ... 6666666666B666 66666666666666 B A 6@6666666666B6666 Z 666@B I B B B 666666666666666 "unctia care face acest lucru este5 #include (list.*( void insert%H,9? p1, H,9? p2, H,9? Z& E p1 6@ next 1 Z7 Z 6@ next 1 p27 G ,tergerea unui element intr6o lista liniar inlantuita este foarte simpla. 2ictural, avem5 p66B B V 66666666666666 66666666666666 66666666666666 ... 666@B ? B 666B666@B I B 666B666@B C B 666B66@ ... 66666666666666 66666666666666 66666666666666 nstructiunea Z 1 p 6@ next7 va implica pointarea lui Z catre obiectul care trebuie sters. 4btinem5 p66B Z66B B B V V 66666666666666 66666666666666 66666666666666 ... 666@B ? B 666B666@B I B 666B666@B C B 666B66@ ... 66666666666666 66666666666666 66666666666666 Considerand instructiunea p 6@ next 1 Z 6@ next7 se obtine in memorie p66B Z66B B B V V 66666666666666 66666666666666 66666666666666 ... 666@B ? B B B B I B 666B666@B C B 666B66@ ... 666666666B6666 666666666666666 66666666666666 B A B B 6666666666666666666666666666666 ,e observa ca elementul I este inaccesibil %adica nu mai apartine listei&, deci nu mai este folosit. ?cesta se mai numeste (garbage( %gunoi&. .vident ca ar fi bine pentru sistem daca s6ar putea elibera aceasta locatie de memorie pentru a putea fi refolosita. .liberarea zonei de memorie se face cu functia (free%&( din biblioteca standard. 8eci, (free%Z&( face disponibila pentru sistem locatia de memorie catre care pointeaza (Z( care a fost alocata mai inainte cu (malloc%&( %sau (calloc%&(&. Cum (free%&( are ca argument de tip pointer catre (void(, rezulta ca (Z( poate fi de orice tip.
n continuare, vom scrie o functie care sterge si elibereaza toate elementele unei liste. #include (list.*( void stergeClista%H,9? *ead& E if %*ead S1 =UHH& E stergeClista%*ead 6@ next&7 free%*ead&7 G G
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. ,crieti un program C pentru simularea unui <oc de carti. ,a se faca o amestecare si o impartire a cartilor la cei n <ucatori. 2. "olosind (tMpedef(, sa se scrie trei functii C care sa calculeze suma a doi vectori, produsul scalar a doi vectori si inmultirea matricelor. 3. %4peratii cu liste& a& Concatenarea a doua liste7 b& 8eterminarea unei subliste ce contine primele 3 elemente dintr6o lista, cu eliberarea zonelor de memorie ale restului elementelor. 4. ,a se oglindeasca o lista liniara inlantuita cu numar constant de variabile suplimentare fara a folosi recursie. !. ,a se sorteze n numere folosind liste liniar inlantuite si metoda interclasarii. $. ,crieti un program C in care sa descrieti urmatoarele operatii pentru arbori binari5 creare, numarare, cautare, stergere, inserare, parcurgere %preordine, inordine, postordine&. '. ,crieti un program C in care sa descrieti aceleasi operatii de mai sus, dar pentru arbori generali %idee5 folositi legaturi de tip fiu6frate&. ntrari:iesiri si fisiere 14.1. "unctia de iesire (printf%&( 14.2. "unctia de intrare (scanf%&( 14.3. "unctiile (sprintf%&( si (sscanf%&( 14.4. "unctiile (fprintf%&( si (fscanf%&( 14.!. ?ccesarea fisierelor 14.$. ?ccesarea aleatoare a unui fisier 14.'. ,til de programare 14.+. .xercitii propuse spre implementare
1111111111 Capitolul 14 1111111111 1111111111111111 ntrari:iesiri si fisiere 1111111111111111 n acest capitol vom explica folosirea unor functii de intrare:iesire %printre care si (printf%&( si (scanf%&(&. 8e asemenea vom arata modurile de desc*idere a fisierelor %pentru procesarea lor& si cum se foloseste un pointer catre fisier. 66666666666666666666666666666666666 "unctia de iesire (printf%&( 66666666666666666666666666666666666 ?re doua proprietati importante care permit o folosire flexibila la un nivel inalt5 6 poate fi tiparita o lista de argumente de lungime arbitrara7 6 afisarea este controlata de specificari de conversie simple %sau formate&. "unctia (printf%&( primeste sirul de caractere din fisierul standard de iesire %stdout&, care este normal conectat la ecran. Hista de argumente a lui (printf%&( are doua parti5 sirulCdeCcontrol si celelalteCargumente 66666666666 .xemplu5 n cazul apelului5 66666666666 printf%(2rodusul Kd Ks WKfFn(, 2, (costa(, 3.''&7 avem sirulCdeCcontrol5 (2rodusul Kd Ks WKfFn( celelalteCargumente5 2, (costa(, 3.''
.xpresiile din PcelelalteCargumenteP sunt evaluate si convertite conform cu formatele din sirul de control si apoi plasate in sirul de iesire. Caracterele din sirul de control care nu fac parte dintr6un format sunt plasate direct in sirul de iesire. ,imbolul K introduce o specificare de conversie sau format. 4 specificare de conversie este un sir care incepe cu K si se termina cu un caracter de conversie. 9abelul de mai <os reprezinta caracterele de conversie %si modul lor de afisare& pentru functia (printf%&(5 666666666666666666666666666666666666666666666666666666666666666666666 Caracter Cum sunt afisate de argumentele corespunzatoare ? conversie 666666666666666666666666666666666666666666666666666666666666666666666 c ca un caracter d, i ca un intreg zecimal u ca un intreg zecimal fara semn o ca un intreg octal fara semn x, > ca un intreg *exazecimal fara semn e ca un numar in virgula mobila7 %ex5 '.123///eL//& . ca un numar in virgula mobila7 %ex5 '.123///.L//& f ca un numar in virgula mobila7 %ex5 '.123///& g in formatul cel mai scurt dintre (e( sau (f( Q in formatul cel mai scurt dintre (.( sau (f( s ca un sir p argumentul corespunzator este un pointer catre void7 valoarea sa se va tipari ca un intreg *exazecimal n argumentul corespunzator este un pointer catre un intreg7 argumentul nu este convertit K cu formatul KK se va afisa un singur K catre sirul de iesire7 nu avem argumente ce trebuie convertite 666666666666666666666666666666666666666666666666666666666666666666666 66666666666 .xemplu5 ata un exemplu de folosire a formatului (Kn(5 66666666666 #include Dstdio.*@ void main%& E int J pi7 printf%(;ai multe caractere Kn.Fn(, pi&7 printf%(=r.caractere 1 Kd(, Jpi&7 G 2e ecran se va afisa numarul de caractere afisate pana la aparitia formatului (Kn( %in cadrul instructiunii de afisare (printf%&( curente&, adica 2/. "unctia (printf%&( intoarce un (int( ce reprezinta numarul de caractere tiparite dupa inlocuirea corespunzatoare a specificatorilor de conversie.
66666666666 .xemplu5 66666666666 #include Dstdio.*@ void main%& E int J pi7 int a 1 printf%(;ai mult de Kd caractere Kn.Fn(, 1/, pi&7 printf%(=umarul de caractere intors de functia printf%& este KdFn(, a&7 printf%(=r.caractere 1 Kd(, Jpi&7 G
n specificarile de conversie pot fi incluse informatii de formatare explicite. 8aca ele nu apar, atunci sunt folosite cele implicite. 8e exemplu, formatul Kf cu argumentul 3.'' va afisa 3.''////. =umarul este afisat pe $ caractere la dreapta punctului zecimal %implicit&. ntre K %care specifica inceputul unei specificari de conversie& si caracterul de conversie de la sfarsit, pot apare in ordine5 6 zero sau mai multe caractere %flag& care modifica intelesul specificarii de conversie7 6 un intreg pozitiv optional care specifica minimul lungimii campului a argumentului convertit. Hocul unde un argument este tiparit se numeste (campul sau(, iar numarul de spatii folosit pentru afisarea sa se numeste (lungimea campului(. 8aca argumentul convertit are mai putine caractere decat lungimea campului specificat, atunci acesta se va completa cu spatii %la stanga sau dreapta&. 8aca argumentul convertit are mai multe caractere decat lungimea campului specificat, atunci lungimea campului se va mari cu cat este necesar. 8aca intregul care defineste lungimea campului incepe cu zero si argumentul ce se tipareste este a<ustat dreapta in campul sau, atunci pentru umplerea sa se vor folosi zerouri in loc de spatii7 6 o (precizie( optionala, care este specificata de un punct urmat de un intreg nenegativ. 2entru conversii d, i, o, u, x si > aceasta specifica numarul minim de cifre ce trebuie afisate. 2entru conversii e, . si f aceasta specifica numarul de cifre de la dreapta punctului zecimal. 2entru conversii g si Q aceasta specifica numarul maxim de cifre semnificative. 2entru conversie cu s, aceasta specifica numarul maxim de caractere ce trebuie tiparite dintr6un sir7 6 un * sau l optional, care este un modificator (s*ort( sau (long(, respectiv. 8aca * este urmat de un d, i, o, u, x sau >, atunci aceasta este o specificare de conversie relativ la (s*ort int( sau (unsigned s*ort int(. 8aca un * este urmat de n, atunci argumentul corespunzator este un pointer catre (s*ort int( sau (unsigned s*ort int(. 8aca l este urmat de d, i, o, u, x sau >, atunci specificarea de conversie se aplica unui argument (long int( sau (unsigned long int(. 8aca l este urmat de caracterul n, atunci argumentul corespunzator este un pointer catre (long int( sau (unsigned long int(7 6 H optional, care este un modificator (lung(. 8aca H este urmat de e, ., f, g sau Q, specificarea de conversie se aplica unui argument (long double(.
Caracterele (flag( sunt5 6 semnul (6( va implica alinierea spre stanga a argumentului convertit in campul sau. 8aca nu gasim nici un semn (6(, atunci alinierea argumentului convertit se face la dreapta campului. 6 semnul (L( va implica afisarea semnului (L( in cazul numerelor pozitive %functioneaza pentru d, i, e, ., f, g si Q&. 9oate numerele negative incep cu semnul minus. 6 un spatiu, care semnifica ca un numar pozitiv %ce provine dintr6o conversie unsigned& are la inceput un spatiu7 6 un (#(, care semnifica ca rezultatul trebuie convertit la o forma alternativa ce depinde de caracterul de conversie. 8aca caracterul de conversie este (o(, atunci (#( cauzeaza afisarea unui zero in fata numarului octal. ntr6o conversie x sau >, (#( cauzeaza /x, respectiv />, in fata numarului *exazecimal. n conversiile g si Q, acesta cauzeaza tiparirea unor zerouri la coada %pana la un anumit numar de zecimale, de obicei !&. n conversiile e, ., f, g sau Q, aceasta cauzeaza tiparirea punctului zecimal, c*iar si cu precizia /. 2entru alte conversii, comportarea lui (#( este nedefinita. 6 un (/( %zero&, care inseamna ca in loc de spatii sunt folosite zerouri. Cu caracterele de conversie d, i, o, u, x, >, e, ., f, g si Q, aceasta poate produce zerouri nesemnificative %in fata numarului&.
ntr6un format, lungimea campului sau precizia %sau ambele&, pot fi specificate folosind J, in loc de un intreg, lucru care indica ca o valoare se obtine dintr6o lista de argumente. 66666666666 .xemplu5 66666666666 int m, n7 double x 1 333.'''''''7 . . . . . . . . . . . :J citeste m si n %sau le calculam cumva& J: . . . . . . . . . . . printf%(x 1 KJ.JfFn(, m, n, x&7
8aca argumentul corespunzator lungimii campului are lungime negativa, atunci se considera (6( ca fiind un (flag( urmat de o valoare pozitiva. 8aca argumentul corespunzator preciziei are valoare negativa, atunci acesta se considera ca lipseste. 9abelul de mai <os contine formate de caractere si siruri %folosim g*ilimele pentru delimitarea vizuala a campului, ele nefiind afisate&.
66666666666666666666666666666666666666666666666666666666666666666666666666666666666 8eclaratii si initializari 66666666666666666666666666666666666666666666666666666666666666666666666666666666666 c*ar c 1 P?P, sNO 1 (Huna rosieS(7 66666666666666666666666666666666666666666666666666666666666666666666666666666666666 "ormat ?rgumentul Cum este afisat 4bservatii corespunzator in campul sau ? 6666666666666666666666666666666666666666666666666666666666666666666666666666666666 Kc c (?( Hungimea campului 1 implicit K2c c ( ?( Hungimea campului 2, aliniat dreapta K63c c (? ( Hungimea campului 3, aliniat stanga Ks s (Huna rosieS( Hungimea campului 11 implicit K3s s (Huna rosieS( ,patii suplimentare K.$s s (Huna r( 2recizia $ K611.+s s (Huna ros ( 2recizie +, aliniere stanga 6666666666666666666666666666666666666666666666666666666666666666666666666666666666 n tabelul de mai <os vom da exemple de folosire a altor formate %avand aceeasi conventie de afisare cu g*ilimele&.
66666666666666666666666666666666666666666666666666666666666666666666666666666666666 8eclaratii si initializari 66666666666666666666666666666666666666666666666666666666666666666666666666666666666 int i 1 1237 double x 1 /.1234!$'+-7 6666666666666666666666666666666666666666666666666666666666666666666666666666666666 "ormat ?rgumentul Cum este afisat 4bservatii corespunzator in campul sau ? 6666666666666666666666666666666666666666666666666666666666666666666666666666666666 Kd i (123( Hungimea campului 3 implicit K/!d i (//123( ?daugat /6uri nesemnificative K'o i ( 1'3( ?liniere dreapta, octal K6-x i ('b ( ?liniere stanga, *exazecimal K6#-x i (/x'b ( ?liniere stanga, *exazecimal K1/.!f x ( /.1234$( Hungimea campului 1/, precizie ! K612.!e x (1.234!'e6/1 ( ?liniere stanga, format 6e 6666666666666666666666666666666666666666666666666666666666666666666666666666666666
666666666666666666666666666666666666 "unctia de intrare (scanf%&( 666666666666666666666666666666666666 ?re doua proprietati importante care permit o folosire flexibila la un nivel inalt5 6 poate citi o lista de argumente de lungime arbitrara7 6 intrarea este controlata de specificari de conversie simple %sau formate&. "unctia (scanf%&( citeste caractere din fisierul standard (stdin(. Hista de argumente a functiei (scanf%&( are doua parti5 sirCdeCcontrol si celelalteCargumente
66666666666 .xemplu5 "ie declaratiile si apelul functiei (scanf%&(5 66666666666 c*ar a, b, c, sN1//O7 int n7 double x7 scanf%(KcKcKcKdKsKlf(, Ra, Rb, Rc, Rn, s, Rx&7 ?vem5 sirCdeCcontrol5 (KcKcKcKdKsKlf( celelalteCargumente5 Ra, Rb, Rc, Rn, s, Rx Celelalte argumente urmate de un sir de control consta dintr6o lista separata prin virgule de expresii pointer sau adrese %reamintim ca (s( este insusi o adresa&.
666666666666666666666666666666666666 8irective in sirul de control 666666666666666666666666666666666666 ,irul de control din (scanf%&( este compus din trei tipuri de (directive(5 6 caractere ordinare 6 spatii goale 6 specificari de conversie
6666666666666666666666666 Caractere ordinare 6666666666666666666666666 Caracterele din sirul de control %diferite de spatiile goale si caracterele din specificarile de conversie& sunt numite (caractere ordinare(. Caracterele ordinare trebuie sa se regaseasca %potriveasca& cu cele din sirul de la intrare.
Caracterul W este ordinar. 8eci trebuie sa intalnim W in sirul de la intrare. 8aca are loc o potrivire cu succes, atunci spatiile goale %daca exista& se vor sari, si caracterele care urmeaza se vor potrivi la o valoare %in virgula mobila&. Valoarea convertita va fi plasata in memorie la adresa variabilei (suma(.
66666666666666666666666666666666 Caractere (spatii goale( 66666666666666666666666666666666 Caracterele spatii goale din sirul de control care nu fac parte dintr6o specificare de conversie se potrivesc cu orice spatiu liber din sirul de intrare. 66666666666 .xemplu5 c*ar c1, c2, c37 66666666666 scanf%( Kc Kc Kc(, Rc1, Rc2, Rc3&7 8aca sirul de la intrare contine literele (a(, (b(, si (c(, atunci (c1(, (c2( si (c3( vor avea valorile (a(, (b(, (c( %a nu se citi g*ilimelele&. 4 directiva spatiu liber implica ca spatiile goale %daca exista& sa fie ignorate din sirul de intrare. 66666666666 .xemplu5 Urmatoarele instructiuni sunt ec*ivalente5 66666666666 scanf%( Kc Kc Kc(, Rc1, Rc2, Rc3&7 scanf%(FtKc Ft KcFnKc(, Rc1, Rc2, Rc3&7
6666666666666666666666666666666 ,pecificari de conversie 6666666666666666666666666666666 ntr6un sir de control pentru (scanf%&(, o directiva de specificare de conversie incepe cu un (K( si se termina cu un caracter de conversie. ?ceasta determina modurile de potrivire si de convertire a caracterelor din sirul de intrare %cele doua tabele de mai <os contin explicatii pentru functia (scanf%&(&5 66666666666666666666666666666666666666666666666666666666666666666666666666666666 Caracter de Caracterele din sirul de 9ipul conversie intrare cu care se potrivesc argumentului nemodificabil corespunzator 66666666666666666666666666666666666666666666666666666666666666666666666666666666 c orice caracter, inclusiv spatiu liber c*ar J d un intreg zecimal %optional cu semn& int J i zecimal, octal, *exazecimal int J %'', /'', /x'', optional cu semn& u un intreg zecimal %optional cu semn& unsigned J o un intreg octal %optional cu semn& unsigned J cifra / nu mai este necesara x, > un intreg *exazecimal %optional cu semn& unsigned J /x sau /> nu mai sunt necesare e, ., f, g, Q numar in virgula mobila %optional cu semn& float J s o secventa de caractere diferite de spatiu c*ar J p ceea ce produce Kp in (printf%&( void J J %de obicei intreg *exazecimal fara semn& n, K, N . . .O %vezi urmatorul tabel& 6666666666666666666666666666666666666666666666666666666666666666666666666666666 4bservatie. Uecimal inseamna numar intreg scris in baza 1/ %nu numar cu zecimale&.
66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 6666666666666666666666 Caracter de 4bservatii conversie nemodificabil 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 6666666666666666666666 n =u se potriveste nici un caracter din sirul de intrare. ?rgumentul corespunzator este un pointer catre (int(, in care se memoreaza numarul de caractere citite in acel (scanf%&( K Conversia de specificare KK va implica potrivirea cu un caracter K din sirul de intrare. =u are argumente corespunzatoare. N . . . O ;ultimea caracterelor dintre paranteze se numeste multime de scanare. ?ceasta determina ce se potriveste si face citirile respective. ?rgumentul corespunzator este un pointer catre baza sirului de caractere ce este suficient de mare pentru a pastra caracterele cu care s6a potrivit, apoi va adauga automat terminatorul PF/P. 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 6666666666666666666666
ntre K si caracterul de conversie poate fi5 6 caracterul J optional, care indica o suprascriere, urmata de un intreg optional care defineste lungimea maxima a sirului de intrare %care va fi deci ignorat&, urmat optional de *, l, H care modifica caracterul de conversie7 6 modificatorul *, care poate precede caracterele de conversie d, i, o, u, x sau >. ?cesta precizeaza ca valoarea convertita trebuie memorata ca un (s*ort int( sau (unsigned s*ort int(7 6 modificatorul l, care poate precede caracterele de conversie d, i, o, u, x, > sau e, ., f, g, Q. n primul caz, acesta precizeaza ca valoarea trebuie memorata ca un (long int( sau (unsigned long int(. n cel de6al doilea caz, acesta precizeaza ca valoarea convertita trebuie memorata ca un (double(7 6 modificatorul H, care poate precede caracterele de conversie e, ., f,g sau Q. ?cesta precizeaza ca valoarea convertita trebuie memorata ca un (long double(. Caracterele din sirul de intrare sunt convertite la valori in concordanta cu specificarile de conversie din sirul de control si plasate la adresa data prin expresia pointer corespunzatoare din lista de argumente. Cu exceptia unei intrari caracter, un camp de scanare consta dintr6un numar contiguu de caractere diferite de spatiu %conforme cu conversia specificata&. Campul de scanare se termina cand se gaseste un caracter neadecvat, sau s6a depasit lungimea scanarii %daca ea este precizata&, sau s6a a<uns la .4" %depinde care vine primul&. ,pecificarea Ks sare spatiile goale si apoi citeste caractere diferite de spatiu pana cand se gaseste spatiu sau .4" %depinde care vine primul&. n sc*imb, specificarea K!s sare spatiile goale, apoi citeste caracterele diferite de spatiu, dar cel mult ! caractere sau pana la .4" %depinde care vine primul&. Cand se citeste un sir de caractere, se presupune ca in memorie este de<a rezervat suficient spatiu pentru memorarea sa %cu tot cu santinela F/&. "ormatul Knc %unde (n( este o constanta intreaga& foloseste la citirea urmatoarelor n caractere, inclusiv spatii goale %se presupune ca s6a rezervat suficient spatiu in memorie pentru pastrarea lor, iar caracterul F/ nu se mai adauga&.
6666666666666666666666666666666666666666666666666666666666 =umere in virgula mobila din sirul de intrare 6666666666666666666666666666666666666666666666666666666666 =umerele in virgula mobila din sirul de intrare sunt formatate cu un semn optional %L sau 6& urmat de un sir de cifre cu un punct zecimal optional, urmat de parte exponentiala optionala. 2artea exponentiala consta din e sau ., urmate de un semn optional %L sau 6&, urmat de un sir de cifre. 66666666666 .xemple5 66666666666 '' L'.'e1 ''/./.61 L/.//3 666666666666 =u uitati5 ,irul de intrare nu este cod C %se aplica reguli diferite&. 66666666666
66666666666666666666666666666666666666 "olosirea multimii de scanare 66666666666666666666666666666666666666 4 specificare de conversie de forma KNsirO indica ca un sir special poate fi citit. ;ultimea de caractere dintre parantezele patrate se numeste (multime de scanare(. 8aca primul caracter din multimea de scanare nu este caracterul circumflex (A(, atunci sirul trebuie sa fie construit numai din caractere ce apartin multimii de scanare. 66666666666 .xemple5 1. "ormatul KNabcO va citi orice sir care contine literele (a(, (b( si (c( si se va opri daca orice alt caracter va 66666666666 apare in sirul de intrare, inclusiv un spatiu %ex. scanf%(KNabcO(, m&&. 2. n contrast, formatul KNAabcO va citi orice ce se va termina cu (a(, (b( sau (c(, dar nu si spatiu. 3. "ie codul c*ar mN3/O7 scanf%(K2-N?I FtFnO(, m&7 ?ceasta va produce citirea in vectorul de caractere (m( a unui sir de cel mult 2- caractere. ,irul consta din literele ?, I, spatiu, tab, ne)line. Ha sfarsit, se va scrie F/. 4. 2rogramatorii de obicei gandesc o linie ca un sir de caractere, inclusiv spatii si taburi, care se termina cu un ne)line. Un mod %elegant& de a citi o linie in memorie este folosirea unei multimi de scanare potrivita5 c*ar linieN2!$O7 )*ile %scanf%( KNAFnO(, linie& 11 1& printf%(KsFn(, linie&7
66666666666666666666666666666666666666666 Valoarea returnata de (scanf%&( 66666666666666666666666666666666666666666 Cand (scanf%&( este apelata, poate apare o greseala la citire. 8e exemplu, daca nu sunt caractere in sirul de intrare, atunci (scanf%&( va intoarce 61 %.4"&. 8aca apare o nepotrivire intre formatele din (scanf%&( si sirul de la intrare, atunci (scanf%&( va intoarce numarul de conversii cu succes pana in acel moment. =umarul este zero daca nu apar conversii. 8aca (scanf%&( reuseste cu succes, atunci este returnat numarul de conversii cu succes. Ha fel, acest numar poate fi zero. 66666666666 .xemplu5 66666666666 c*ar c, JsirCcontrol, sN'O, mN1+O7 int a, contor7 sirCcontrol 1 (Kd , KJs KK Kc KNabcO KJs K!s Ks(7 contor 1 scanf%sirCcontrol, Ra, Rc, s, m, RmN!O&7 Consideram ca avem la intrare sirul5 23 , ignora K C abacus citesteCaceastaJJ ?tunci5 (23( este plasat in memorie la adresa lui (a( (,( se potriveste (ignora( este un sir ignorat (K( se potriveste (C( este plasat in memorie la adresa lui (c( (abac( este plasat in sN/O,...,sN4O1PF/P (us( este un sir ignorat (cites( este plasat in mN/O,...,mN!O1PF/P (teCaceastaJJ( este plasat in mN!O,...,mN1+O1PF/P 8in moment ce au avut loc ! conversii cu succes, rezulta ca functia (scanf%&( va intoarce valoarea !.
66666666666 .xemplu5 9abelul de mai <os contine mai multe exemple de directive de control pentru functia (scanf%&(5 66666666666 666666666666666666666666666666666666666666666666666666666666666666666 8irective 9ipul argumentului Continutul 4bservatii in sirul corespunzator sirului de de control intrare 666666666666666666666666666666666666666666666666666666666666666666666 abK2c c*ar J abacus ab se potriveste ac se converteste 666666666666666666666666666666666666666666666666666666666666666666666 K3*d s*ort J 6''33 6'' se converteste 666666666666666666666666666666666666666666666666666666666666666666666 K41i long J L/x$$ L/x$ se converteste 666666666666666666666666666666666666666666666666666666666666666666666 6K2u unsigned J 6123 6 se potriveste 12 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 L Klu unsigned long J L6123 L se potriveste 6123 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 L Klu unsigned long J L 6123 L se potriveste 6123 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 L Klu unsigned long J L6 123 L se potriveste eroare, %6 nu se converteste& 666666666666666666666666666666666666666666666666666666666666666666666 K3e float J L'e62 L'e se converteste 666666666666666666666666666666666666666666666666666666666666666666666 K4f float J 'eL22 'eL22 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 K!1f double J 61.234! 61.23 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 K4Hf long double J 1234! 1234 se converteste 666666666666666666666666666666666666666666666666666666666666666666666 Kp void J J dependent poate citi ceea ce printf%& de sistem cu Kp scrie la iesire 666666666666666666666666666666666666666666666666666666666666666666666
6666666666666666666666666666666666666666666 "unctiile (sprintf%&( si (sscanf%&( 6666666666666666666666666666666666666666666 "unctiile (sprintf%&( si (sscanf%&( sunt versiuni ce folosesc siruri ale functiei (printf%&( si (scanf%&(, respectiv. 2rototipurile lor, care se gasesc in (stdio.*(, sunt5 int sprintf%c*ar Js, const c*ar Jformat, ...&7 int sscanf%const c*ar Js, const c*ar Jformat, ...&7 2unctele ... indica compilatorului faptul ca functia poate avea un numar variabil de argumente. 4 instructiune de forma5 sprintf%sir, sirCdeCcontrol, alteCargumente&7 scrie rezultatul in sirul de caractere (sir(. ntr6o maniera similara, o instructiune de forma5 sscanf%sir, sirCdeCcontrol, alteCargumente&7 citeste rezultatul din sirul de caractere (sir(.
66666666666 .xemplu5 66666666666 c*ar J sirCintrare 1 (1 2 3 ab(7 c*ar sirCiesireN1//O, tempN1//O7 int a, b, c7 sscanf%sirCintrare, (KdKdKdKs(, Ra, Rb, Rc, Rtemp&7 sprintf%sirCiesire, (Ks Ks KdKdKdFn(, temp, temp, a, b, c&7 printf%(Ks(, sirCiesire&7 ?tunci se va afisa la ecran5 ab ab 123 ?tentie S .ste responsabilitatea programatorului sa rezerve spatiu suficient pentru memorarea lui (sirCiesire( din (sprintf%&(.
666666666666666666666666666666666666666666 "unctiile (fprintf%&( si (fscanf%&( 666666666666666666666666666666666666666666 "unctiile (fprintf%&( si (fscanf%&( sunt versiunile pentru fisiere a functiilor (printf%&( si (scanf%&(. "isierul (stdio.*( contine un numar de constructii referitoare la fisiere. n acest fisier exista si tipul structura "H. a caror membrii descriu starea curenta a unui fisier. 9ot in acest fisier, sunt definiti trei pointeri la fisier. .ste vorba despre (stdin(, (stdout( si (stderr(. 666666666666666666666666666666666666666666666666666666666666666666666666 8enumirea in C =umele complet 4bservatii 666666666666666666666666666666666666666666666666666666666666666666666666 stdin standard input file conectat la tastatura stdout standard output file conectat la ecran stderr standard error file conectat la ecran 666666666666666666666666666666666666666666666666666666666666666666666666 n fisierul (stdio.*( exista prototipurile pentru functiile (fprintf%&( si (fscanf%&(5 int fprintf%"H. Jofp, const c*ar Jformat, ...&7 int fscanf%"H. Jifp, const c*ar Jformat, ...&7 %(ofp( 6 outfile pointer, iar (ifp( 6 infile pointer& 2unctele ... spun compilatorului ca functia ia un numar variabil de argumente. 4 instructiune de forma5 fprintf%pointerCcatreCfisier, sirCdeCcontrol, alteCargumente&7 va scrie in fisierul spre care pointeaza (pointerCcatreCfisier(. n particular, fprintf%stdout, ...&7 este ec*ivalent cu printf%...&7 ntr6o maniera similara, o instructiune de forma5 fscanf%pointerCcatreCfisier, sirCdeCcontrol, alteCargumente&7 va citi din fisierul spre care pointeaza (pointerCcatreCfisier(. n particular, fscanf%stdin, ...&7 este ec*ivalent cu scanf%...&7
6666666666666666666666666 ?ccesarea fisierelor 6666666666666666666666666 "isierele au cateva proprietati importante5 6 au un nume 6 trebuie inc*ise si desc*ise 6 poate fi scris in ele sau citit din ele sau adaugat la ele 6 cand sunt desc*ise avem acces la ele de la inceput la sfarsitul lor ?bstract, un fisier poate fi gandit ca un sir de caractere. 8upa ce un fisier a fost desc*is, sirul poate fi accesat folosind functii din biblioteca standard. 66666666666 .xemplu5 66666666666 #include Dstdio.*@ void main%& E int suma 1 /, val7 "H. Jifp, Jofp7 ifp 1 fopen%(fisCin(, (r(&7 :J desc*is pentru citire J: ofp 1 fopen%(fisCout(, ()(&7 :J desc*is pentru scriere J: . . . . . . G n acest exemplu, am desc*is fisierul (fisCin( pentru citire si (fisCout( pentru scriere. 8in momentul desc*iderii fisierului, pointerul catre fisier poate fi folosit exclusiv pentru referirea la intregul fisier. 8aca, de exemplu, presupunem ca fisierul (fisCin( are numere intregi, atunci iata o modalitate de a face suma lor5 )*ile %fscanf%ifp, (Kd(, Rval& 11 1& sum L1 val7 fprintf%ofp, (,uma lor este Kd.Fn(, suma&7 Ca si (scanf%&(, functia (fscanf%&( intoarce numarul de conversii cu succes. 8upa ce terminam de exploatat fisierele, putem sa le inc*idem5 fclose%ifp&7 fclose%ofp&7 Un apel de functie de forma (fopen%numeCfisier, mod&( desc*ide fisierul respectiv intr6un mod particular si returneaza un pointer catre fisier. ,unt mai multe posibilitati pentru modul de accesare a fisierului5
666666666666666666666666666666666666666666666666666666666666 ;od de acces ,emnificatie 666666666666666666666666666666666666666666666666666666666666 (r( desc*ide fisier text pentru citire ()( desc*ide fisier text pentru scriere (a( desc*ide fisier text pentru adaugare (rb( desc*ide fisier binar pentru citire ()b( desc*ide fisier binar pentru scriere (ab( desc*ide fisier binar pentru adaugare 6666666666666666666666666666666666666666666666666666666666666 "iecare dintre aceste moduri se poate termina cu (aL(. ?sta inseamna ca fisierul poate fi desc*is si pentru citire si pentru scriere. 666666666666666666666666666666666666666666666666666666666666666 ;od de acces ,emnificatie 666666666666666666666666666666666666666666666666666666666666666 (rL( desc*ide fisier text pentru citire si scriere ()L( desc*ide fisier text pentru scriere si citire . . . . . 666666666666666666666666666666666666666666666666666666666666666 8esc*iderea pentru citire a unui fisier care nu exista, sau care nu poate fi citit, va esua si functia (fopen%&( va intoarce pointerul =UHH. 8esc*iderea unui fisier pentru scriere va avea ca efect crearea unui fisier %daca acesta nu exista& sau se va suprascrie peste unul existent. 8esc*iderea unui fisier pentru adaugare va avea ca efect crearea unui fisier %daca acesta nu exista& sau se va scrie la sfarsitul sau %daca acesta exista&. 8aca scriem modul (rL( sau ()L( atunci fisierul se considera ca a fost desc*is pentru citire si scriere. Cu toate acestea citirile nu pot fi urmate de scrieri decat daca s6a a<uns la .4" sau au intervenit apeluri ale functiilor (fsee3%&(, (fsetpos%&( sau (re)ind%&(. 8e asemeni, scrierile nu pot fi urmate de citiri decat daca s6a a<uns la .4" sau au intervenit apeluri ale functiilor (fflus*%&(, (fsee3%&(, (fsetpos%&( sau (re)ind%&(.
666666666666666666666666666666666666666666 ?ccesarea aleatoare a unui fisier 666666666666666666666666666666666666666666 n plus fata de accesarea unui caracter unul dupa altul intr6un fisier %acces secvential&, noi putem accesa caractere in locuri diferite %acces aleator&. n biblioteca C, functiile (fsee3%&( si (ftell%&( sunt folosite pentru accesarea aleatoare a unui fisier. 4 expresie de forma ftell%pointerCcatreCfisier& returneaza valoarea curenta a indicatorului de pozitie in fisier. Valoarea reprezinta numarul de octeti pornind de la inceputul fisierului, numarand de la /. Cand un caracter este citit dintr6un fisier, sistemul incrementeaza indicatorul de pozitie cu 1. 9e*nic vorbind, indicatorul de pozitie in fisier este un membru a structurii catre care pointeaza (pointerCcatreCfisier(. 2ointerul catre fisier nu pointeaza catre caractere individuale din fisier %aceasta este o eroare de conceptie pe care o fac programatorii incepatori&. "unctia (fsee3%&( are trei argumente5 6 pointer catre fisier 6 offset %intreg& 6 un intreg care arata locul fata de care se calculeaza offset6ul
4 instructiune de forma fsee3%pointerCcatreCfisier, offset, mod&7 seteaza indicatorul de pozitie la o valoare care reprezinta (offset( octeti pornind de la (mod(. Valoarea lui (mod( poate fi /, 1 sau 2, insemnand ca ne referim la inceputul fisierului, pozitia curenta sau sfarsitul fisierului, respectiv. ?tentie S "unctiile (fsee3%&( si (ftell%&( sunt garantate sa lucreze numai pentru fisiere binare. n ;,6 84,, daca dorim sa lucram cu aceste functii, trebuie sa desc*idem acest fisier in acces binar. n U=>, din moment ce exista doar un singur mecanism de lucru cu fisierele, orice mod de desc*idere pentru fisier este bun.
666666666666666666666666 ,til de programare 666666666666666666666666 Un stil bun de programare va verifica daca functia (fopen%&( lucreaza asa cum ne asteptam %in orice program serios, acest lucru trebuie facut&. ata cum ar trebui sa se faca desc*iderea fisierului (fis1( in acces de citire5 if %%ifp 1 fopen%(fis1(, (r(&& 11 =UHH& E printf%(Fn=u putem desc*ide fisierul fis1. 2aSFnFn(&7 exit%1&7 G
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. "olosind (argc( si (argv( ca argumente ale functiei (main%&(, scrieti un program care copie (fisier1( in (fisier2( dubland liniile %cu exceptia lui DC0@&. 2. ,crieti un program C care citeste in variabile C dintr6un fisier text numarul de linii, respectiv coloane, si elementele unei matrice, apoi afisati matricea citita din fisier. 1!. nstrumente soft 1!.1. .xecutarea comenzilor dintr6un program C 1!.2. Variabile de mediu 1!.3. Compilatorul C 1!.4. Crearea unei biblioteci 1!.!. "olosirea lui (prof( 1!.$. Cronometrarea executiei codului C 1!.'. 2rograme de depanare 1!.+. Utilitarul (ma3e( 1!.-. Utilitarul (touc*( 1!.1/. ?lte instrumente soft utile 1!.11. .xercitii propuse spre implementare
1111111111 Capitolul 1! 1111111111 111111111111 nstrumente soft 111111111111 .xista doua tipuri de instrumente soft5 6 facilitati generale puse la dispozitie de catre sistemul de operare7 6 facilitati specifice desemnate explicit pentru a a<uta programatorul. 8in moment ce comenzile sistemului de operare pot fi executate dintr6un program C, atunci programatorul poate folosi aceste comenzi ca instrumente de soft pentru indeplinirea anumitor sarcini. Cateva instrumente sunt disponibile intr6un sistem de operare, dar nu si in altul. 8e exemplu, (ma3e( exista in U=>, iar in ;,684, este o trasatura ce se poate instala. nstrumentele de soft variaza cu timpul. ,istemele de depanare par a fi cele mai disponibile. Compilatorul C insusi poate fi considerat un instrument soft. n acest capitol vom discuta cum executam o comanda din sistemul de operare dintr6un program C. ?poi vom discuta cateva instrumente soft importante, cum ar fi5 6 compilatorul C 6 (ma3e( 6 (touc*( 6 (grep( 6 instrumente de depanare
66666666666666666666666666666666666666666666666666666666 .xecutarea comenzilor dintr6un program C 66666666666666666666666666666666666666666666666666666666 "unctia (sMstem%&( %din biblioteca C& pune la dispozitie accesarea comenzilor sistemului de operare. ?stfel, comenzile existente in sistemul de operare pot fi apelate si din programe C. 66666666666 .xemplu5 ?tat in ;,684,, cat si in U=>, exista comanda (date(. 8aca intr6un program C, scriem comanda 66666666666 sMstem%(date(&7 atunci va fi tiparita la ecran data curenta a sistemului. ,irul trimis ca argument al functiei (sMstem%&( este tratat ca o comanda a sistemului de operare. Cand se executa instructiunea, controlul este trimis catre sistemul de operare, se executa comanda si apoi controlul este trimis inapoi catre program.
66666666666 .xemplu5 n U=>, (vi( este o comanda folosita pentru editare. 2resupunem ca suntem intr6un program si vrem sa editam un fisier al carui nume se citeste de la tastatura. 2utem scrie5 c*ar comandaN;?>,90=QO7 sprintf%comanda, (vi Ks(, argvN1O&7 printf%(8am comanda vi, desc*izand fisierul KsFn(, argvN1O&7 sMstem%comanda&7 Un exemplu similar poate functiona si in ;,684, inlocuind (vi( cu alt editor de texte. 66666666666 .xemplu5 Consideram ca vrem sa dam comanda ;,684, (dir( si dorim afisarea doar cu litere mici. ?tunci putem scrie programul5 66666666666 #include DctMpe.*@ #include Dstdio.*@ #include Dstdlib.*@ #define ;?>,90=Q 1//
void main%& E c*ar comandaN;?>,90=QO, JnumeCfisCtemp7 int c7 "H. Jifp7 numeCfisCtemp 1 tmpnam%=UHH&7 sprintf%comanda, (dir @ Ks(, numeCfisCtemp&7 if %sMstem%(dir J.J(& 11 /& E sMstem%comanda&7 if %%ifp 1 fopen%numeCfisCtemp, (r(&& S1 =UHH& )*ile %%c 1 getc%ifp&& S1 .4"& putc*ar%tolo)er%c&&7 remove%numeCfisCtemp&7 G G ?tentie S ,e creeaza intai executabilul si apoi se ruleaza dupa ce s6a iesit din compilatorul C. 6666666666666 4bservatii5 2entru programele de mai sus, facem precizarile5 6666666666666 6 folosim functia (tmpnam%&( pentru creearea unui nume de fisier temporar %de obicei (tmp1.WWW(&7 daca exista de<a fisierul (tmp1.WWW( in directorul curent, atunci se creeaza fisierul (tmp2.WWW(, s.a.m.d.&7 6 apelam functia (sistem%&( pentru redirectarea iesirii comenzii (dir( in acel fisier temporar7 6 apoi tiparim continutul fisierului la ecran sc*imband literele mari in mici7 6 in final, stergem din memorie fisierul temporar folosind functia (remove%&(.
6666666666666666666666666 Variabile de mediu 6666666666666666666666666 Variabilele de mediu sunt disponibile atat in U=>, cat si in ;,684,. ?fisarea lor la ecran se poate face cu urmatorul program5 #include Dstdio.*@
void main%int argc, c*ar JargvNO, c*ar JenvNO& E int i7 for %i 1 /7 envNiO S1 =UHH7 LLi& printf%(KsFn(, envNiO&7 G ?mbii parametri %argv si env& sunt de tip pointer catre pointer catre (c*ar(. 8eci, putem sa6i gandim ca siruri de pointeri catre (c*ar( sau (vectori de siruri de caractere(. ,istemul memoreaza spatiu pentru ele. Ultimul element din fiecare astfel de sir este pointerul =UHH. .vident programul de mai sus foloseste doar vectorul (env(. 2e sistemele U=>, programul va afisa5 2?9[1:usr:local:bin5:bin5:usr:bin5:usr:>110$:bin5:*ome:stefan:bin [4;.1:*ome:stefan ,[.HH1:bin:bas* 9.0;1vt22/ U,.01stefan . . . . . Ha stanga semnului (1( sunt deci variabilele de mediu, iar la dreapta valorile lor, care trebuie gandite ca siruri de caractere. 2e sistemele ;,684,, programul va afisa5 204;291W2WQ 2?9[1U5.7^5.7>5.7Y5.7V5.7U5.795.7,5.705.7]5.725. C4;,2.C1^5C4;;?=8.C4; . . . . . ?mbele sisteme %U=> si ;,684,& pun la dispozitie comenzi pentru afisarea variabilelor de mediu. n U=>, se pot folosi comenzile (env( sau (printenv( %pe unele sisteme si comanda (set(&, iar in ;,684, comanda (set(. 2rin conventie, variabilele de mediu sunt de obicei scrise cu litere mari. ntr6un program C, putem accesa variabilele de mediu prin al treilea argument al functiei (main%&( sau putem folosi functia (getenv%&( din biblioteca standard. 2rototipul sau, care se gaseste in Dstdlib.*@, este dat prin5 c*ar Jgetenv%const c*ar Jname&7 8aca sirul trimis ca argument este o variabila de mediu, atunci functia intoarce sirul %pointer catre (c*ar(& pus la dispozitie de catre sistem ca valoare a variabilei. 8aca sirul trimis ca argument nu este variabila de mediu, atunci se returneaza =UHH. 666666666666 .xemplu5 666666666666 printf%(KsKsFnKsKsFnKsKsFnKsKsFnKsKsFn(, (=ume utilizator5 (, getenv%(U,.0(&, (=ume login5 (, getenv%(H4Q=?;.(&, (,*ell5 (, getenv%(,[.HH(&, (.nv5 (, getenv%(.=V(&, (8irector [ome5 (, getenv%([4;.(&&7 n U=>, anumite variabile de mediu, cum ar fi H4Q=?;., ,[.HH, [4;., sunt puse la dispozitie de catre sistem %adica sunt nemodificabile&. 2entru a initializa altele, scriem setenv =?;. (?bcd efg*( in fisierul nostru (.login(.
66666666666666666666 Compilatorul C 66666666666666666666 .xista multe compilatoare de C si un sistem de operare poate pune la dispozitie un numar mare de astfel de compilatoare. ata cateva posibilitati5 666666666666666666666666666666666666666666666666666666666666666666666666666666666 Comanda Compilator C apelat 666666666666666666666666666666666666666666666666666666666666666666666666666666666 cc Compilator C creat de Iell Haboratories cc Compilator C creat de CraM 0esearc* %U=C4,& cc Compilator C creat de [e)lett62ac3ard %[26U>& cc Compilator C creat de ,ilicon Qrap*ics %0>& acc Compilator C creat de ,un ;icrosMstems %,un4,& gcc Compilator Q=U C creat de "ree ,oft)are "oundation *c Compilator [ig* C creat de ;eta)are occ Compilator 4regon C creat de 4regon ,of)are Zc Compilator ]uic3 C creat de ;icrosoft tc Compilator 9urbo C, sistem integrat, creat de Iorland tcc Compilator 9urbo C, versiune linie comanda, Iorland 66666666666666666666666666666666666666666666666666666666666666666666666666666666 n cele ce urmeaza, vom preciza modul de apel si optiunile acestora in U=>. ;ulte dintre ele sunt valabile si in ;,684,. 8aca avem un program complet intr6un singur fisier, sa zicem (pgm.c(, atunci comanda5 cc pgm.c va traduce codul C din (pgm.c( in cod obiect executabil si6l va scrie in fisierul (a.out( %n ;,6 84,, fisierul executabil se numeste (pgm.exe(&. Comanda (a.out( executa programul. Consideram acum comanda5 cc 6o pgm pgm.c
?ceasta cauzeaza scrierea codului executabil direct in fisierul (pgm(, suprascriind6ul in cazul in care acesta exista de<a %n ;,684, optiunea similara este 6e&. Comanda (cc( lucreaza de fapt in trei faze5 6 apelul preprocesorului 6 apelul compilatorului 6 apelul incarcatorului %editorului de legaturi&
0olul incarcatorului este de a pune %lega& impreuna bucatile furnizate de compilator pentru a face fisierul executabil final. 4ptiunea 6c se foloseste numai pentru compilare %pentru apelul preprocesorului si compilatorului&, nu si a incarcatorului. ?ceasta optiune este utila daca avem un program scris in mai multe fisiere. Consideram comanda cc 6c main.c fis1.c fis2.c 8aca nu sunt erori, fisierele obiect corespunzatoare vor fi create si vor avea extensia (.o( %n ;,6 84,, ele au extensia (.ob<(&. 2entru creearea unui fisier executabil, putem compila anumite fisiere cu extensia (.c( si (.o( %combinate&. 2resupunem ca avem o eroare in (main.c(. 8upa corectarea ei, putem da comanda5 cc 6o pgm main.c fis1.o fis2.o "olosirea fisierului cu extensia (.o( in locul celui cu extensia (.c( reduce timpul de compilare. n plus fata de extensia (.c( si (.o(, putem folosi fisiere cu extesia (.s( care sunt create de asamblor sau de compilator cu optiunea (6,( %cand folosim biblioteci create de ar*ivator&. Iibliotecile, de obicei, au extensia (.a( %n ;,684, ele au extensia (.lib(&.
66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 666 Cateva optiuni folositoare pentru compilatorul C 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 666 6c 8oar compilare, genereaza fisiere cu extensia (.o( 6g Qenereaza cod pentru depanator 6o nume 2une codul executabil in fisierul (nume( 6p Qenereaza cod pentru profiler 68 nume1def 2une la inceputul fiecarui fisier cu extensia (.c( linia #define nume def 6. ?peleaza preprocesorul, dar nu si compilatorul 6 dir %i mare& Cauta fisierele (#include( din directorul (dir( 6; Creaza un (ma3efile( 6;; Creaza un (ma3efile(, dar nu include toate dependentele din fisierele *eader standard 64 Qenereaza cod optimizat 6, Qenereaza cod de asamblare in fisiere cu extensia (.s( 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 66
6666666666666666666666666666666 Crearea unei biblioteci 6666666666666666666666666666666 ;ulte sisteme de operare pun la dispozitie facilitati de creare si gestionare a bibliotecilor. n U=>, acest lucru se face cu ar*ivatorul si se apeleaza cu comanda (ar(. n ;,684,, acest lucru se realizeaza cu bibliotecarul si este o aplicatie ce se poate instala. Iibliotecarul ;icrosoft este (lib(, in timp ce bibliotecarul 9urbo C Iorland este (tlib(. 2rin conventie, numele fisierelor din biblioteci au extensia (.a( in U=> si (.lib( in ;,684,. n cele ce urmeaza vom discuta situatia din U=>, dar ideea generala se poate aplica oricarui bibliotecar. n U=>, ar*ivatorul (ar( poate fi folosit pentru combinarea unui grup de fisiere intr6unul singur numit (biblioteca(. Iiblioteca C standard este un exemplu in acest sens. 2e multe sisteme U=>, aceasta este fisierul (:lib:libc.a( sau poate exista in mai multe fisiere. ncercati comanda5 ar t :lib:libc.a C*eia (t( este folosita pentru tiparirea numelor %sau titlurilor& fisierelor din biblioteca. 8aca dorim numararea acestor titluri %pentru ca sunt foarte multe& putem da comanda5 ar t :lib:libc.a B )c 6666666666666 4bservatie5 2e unele sisteme U=>, biblioteca C nu este intitulata astfel. 8e exemplu, pe (fenrir(, puteti incerca alt 6666666666666 exemplu de biblioteca5 ar t :lib:libp)db.a B )c
66666666666666666666666666 "olosirea lui (prof( 66666666666666666666666666 n U=>, daca folosim optiunea (6p( pentru compilator, atunci se produce cod suplimentar, care poate lua locul in fisiere obiect sau fisiere executabile produse de compilator. Cand programul este apelat, codul suplimentar produce informatii care pot fi folosite pentru generarea (profilului( unei executii. nformatiile pentru (profile( sunt scrise automat in fisierul (mon.out(. ?cest fisier nu poate fi citit de utilizatori. 2entru a obtine informatiile din (mon.out(, programatorul trebuie sa dea comanda prof pgm unde (pgm( este numele programului.
666666666666666666666666666666666666666666666 Cronometrarea executiei codului C 666666666666666666666666666666666666666666666 ;ulte sisteme de operare pun la dispozitie functii pentru folosirea ceasului intern. ?ccesul la ceasul masinii este posibil in ?=, C printr6un numar de functii a caror prototipuri sunt descrise in Dtime.*@. "isierul *eader contine de asemenea un numar de alte constructii, printre care si definitiile lui (cloc3Ct( si (timeCt(. 8e obicei, aceste definitii de tipuri sunt date prin5 tMpedef long cloc3Ct7 tMpedef long timeCt7 si aceste tipuri sunt folosite in prototipurile functiilor. ata trei functii utile pentru cronometrarea timpului5 cloc3Ct cloc3%void&7 timeCt time%timeCt Jp&7 double difftime%timeCt time1, timeCt time/&7 Cand un program este executat, sistemul de operare tine minte timpul procesorului ce este folosit. Cand este apelata functia (cloc3%&(, valoarea returnata de sistem este cea mai buna aproximare a timpului folosit de program pana in acel punct. Unitatile %de masura& ceasului pot varia de la o masina la alta. ;acro6ul #define CH4C\,C2.0C,.C $/ :J dependent de masina J: este pus la dispozitie in *eader6ul Dtime.*@D:>;2@ Dp@D>;2@. ?cesta poate fi folosit pentru conversia valorii returnate de (cloc3%&( catre secunde. "unctia (time%&( intoarce numarul de secunde care au trecut de la 1 ianuarie 1-'/ %sunt posibile si alte unitati, aceasta fiind una din ele&. 4 folosire uzuala a acestei functii este5 srand%time%=UHH&&7 ?pelul se refera la generatorul de numere aleatoare. 8aca trimitem doua valori produse de (time%&( catre functia (difftime%&(, atunci va fi returnata diferenta exprimata in secunde de tip (double(.
666666666666666666666666666666 2rograme de depanare 666666666666666666666666666666
Un program de depanare permite programatorului sa urmareasca linie cu linie executia codului si de a verifica valorile unor variabile sau expresii. ?cest lucru este extrem de folositor %mai ales cand un program nu functioneaza conform asteptarilor&. Humea programarii este plina de programe de depanare. 8e exemplu, in U=> exista programul (dbx( %care insa nu este asa grozav&. 2rogramul C (fis.c( trebuie compilat cu optiunea (6g( %debugging&, dupa care se lanseaza comanda (dbx fis.c(. 2ana la comanda (Zuit(, toate comenzile sunt interne lui (dbx(. Vizualizarea lor se poate face cu (dbx *elp(. n lumea ;,684,, programele de depanare sunt in general incorporate. 8e exemplu, firmele ;icrosoft si Iorland produc programe de depanare excelente.
?tat pentru programator, cat si pentru masina, este ineficient si costisitor sa pastram un program C mare intr6un singur fisier care necesita compilari repetate. 4 strategie mult mai buna este scrierea programului in mai multe fisiere cu extensia (.c( si compilarea lor separata. Utilitarul (ma3e( poate fi folosit pentru a pastra (urmele( fisierelor sursa si de a produce acces usor la biblioteci si la fisierele *eader asociate. ?ceasta facilitate este prezenta in U=>, iar in ;,684, este o proprietate ce se poate instala.
66666666666666666666666 Utilitarul (touc*( 66666666666666666666666 Utilitarul (touc*( este disponibil intotdeauna in U=> si uneori disponibila sub ;,684, %de obicei, este disponibila acolo unde este instalat (ma3e(&. Utilitarul (touc*( este folosit pentru a actualiza data unui fisier. ?cesta este util cand folosim (ma3e( cand se compara timpurile fisierelor care trebuie compilate.
66666666666 .xemplu5 8aca punem data curenta la un fisier (aaa.*( folosind comanda5
touc* aaa.* atunci fisierul (aaa.*( are data cea mai recenta decat toate fisierele (.*(, (.c(, (.o(. ?cum, dand comanda (ma3e( toate fisierele cu extensia (.c( vor fi recompilate si fisierele obiect lin3editate pentru a crea noul fisier executabil.
,istemul de operare pune la dispozitie multe instrumente soft pentru programatori. ata o lista cu cateva instrumente soft ce se gasesc in U=> %unele c*iar si in ;,684,&5 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 Comanda 4bservatii 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 cb "olosit pentru transformarea codului C in (prettM print( diff 9ipareste liniile care difera in doua fisiere grep Cauta un (pattern( intr6unul sau mai multe fisiere indent ?lt (prettM printer( cu mai multe optiuni )c =umara liniiile, cuvintele si caracterele dintr6un fisier %sau mai multe& 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 Utilitarul (cb( citeste din (stdin( si scrie in (stdout(. Utilitarul (indent( este mai puternic. 2oate fi gasit pe versiunile U=> Ier3eleM si ,un.
66666666666 .xemplu5 cb D pgm.c Utilitarele (diff(, (grep( si ()c( pot fi folosite de oricine, nu numai de programatori. Cu toate ca sunt utilitare U=>, ele sunt de obicei disponibile si in ;,684, %in special (grep(, foarte folositor programatorilor&. n final, sa mentionam ca C poate fi folosit in con<unctie si cu alte instrumente de nivel inalt %unele dintre ele limba<e (adevarate(&5 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 Utilitar 4bservatii 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 a)3 Himba< de procesare si scanare a pattern6urilor cs* ?cest (s*ell( %ca si (s*(, (3s*(& este programabil lex Qenereaza cod C pentru analiza lexicala sed .ditor de texte care preia comenzile sale dintr6un fisier Macc (^et anot*er compiler6compiler(, folosit la generarea de cod C 66666666666666666666666666666666666666666666666666666666666666666666666666666666666666666 4 importanta deosebita o au (lex( si (Macc( %cu versiunile (pclex( si (pcMacc( pentru ;,684,&. Versiuni mai recente, cum ar fi, (flex( sau (bison(, sunt disponibile de la "ree ,oft)are "oundation, nc. .le lucreaza atat sub U=>, cat si sub ;,684,.
66666666666666666666666666666666666666666666666 .xercitii propuse spre implementare 66666666666666666666666666666666666666666666666 1. ,crieti un program C care implementeaza strategiile (bubble sort(, respectiv (Zuic3sort(, si folosind functii (de timp( comparati timpii de executie ale celor doua metode. 2. "olosind comanda (sMstem%&( scrieti un program C care apeleaza un editor de texte %salvati fisierul (fis.txt(&, apoi listati fisierul (fis.txt( la imprimanta