Documente noi - cercetari, esee, comentariu, compunere, document
Documente categorii

Initiere in c

INITIERE IN C


Sa incepem cu o introducere rapida in C. Scopul nostru este sa preezentam elementele esentiale ale limbajului in programe reale, fara insa a ne impotmoli in detalii, reguli formale si exceptii. In acest punct al expunerii nu incercam sa fim completi si nici macar foarte precisi (mentionam totusi ca exemplele vor sa fie corecte). Dorim sa va aducem cit mai repede posibil in punctul in care veti fi capabili sa scrieti programe utile si, pentru aceasta, ne-am concentrat asupra fundamentelor: variabile si constante, aritmetica, controlul fluxului, functii si rudimentede operatii de I/O. Am lasat deoparte intentionat din acestcapitol acele caracteristici ale limbajului C care sint de importanta vitala in scrierea programelor mai mari. Acestea includ pointerii, structurile, majoritatea din bogatul set de operatori ai lui C, anumite instructiuni de control al fluxului si o multime de detalii.



Acestmodde abordare are neajunsurile lui, desigur. Cel mai notabil este acela ca povestea completa a caracteristicilor oricarui limbaj de programare nu este gasita intr-un singur loc, iar o initiere in el, fiind scurta, poate induce in eroare. Deoarece exemplele nu pot folosi intreaga putere a lui C, ele nu sintatit de concise si de elegante pe cit ar putea fi. Am incercat sa minimalizam aceste efecte, dar fiti atenti!

Unalt neajuns este acela ca in capitolele urmatoare vom repeta in mod necesar cite ceva din acest capitol. Speram ca aceasta repetitie va va ajuta mai mult decit va va plictisi. In orice caz,programatorii experimentati vor fi capabili sa extrapoleze din materialul din acest capitol propriile lor nevoi de programare. Incepatorii vor putea scrie mici programe, similare celor prezentate de noi. Ambele grupe pot folosiacest capitol drept cadru pentru descrierile riguroase care incep cu Capitolul 2.

1.1 Sa incepem


Singurulmod de a invata un nou limbaj de programare este de a scrie programe in el. Primul program pe care-l vom scrie este acelasi pentru toate limbajele:


Tipariti cuvintele


hello, world


Acesta este primul obstacol; pentru a sari peste el, trebuie sa fiti in stare sa creati undeva textul program, sa-l compilati cu succes, sa-l incarcati, sa-l executati si sa aflati textul tiparit acolo undeeste iesirea calculatorului dumneavoastra. In C, programul pentru a tipari 'hello, world' este:


main ()



Cumruleazaacest program,depinde de sistemul pe care-l folositi, Drept exemplu specific, pe sistemul de operare RSX, trebuie sa creati acest program sursa intr-un fisier al carui nume se termina in '.C', de exemplu 'hello.C' apoi sa-l compilati cu comenzile:

>cc hello

>as hello

Daca n-ati gresit nimic, de exemplu sa fi uitat un caracter sau sa fi inversat doua caractere, compilarea se va desfasura silentios si va produce un fisier obiect numit 'hello.obj'. Lansindu-l in

executie dupa linkeditare cu comenzile

>tkb hello=hello,lb:[1,1]clib/lb

>run hello

va produce

hello, world

caiesirea sa. Pe alte sisteme, regulile vor fi diferite; verificati-le cu expertul local.


Exercitiul 1.1. Executati acest program pe sistemul dumneavoastra. Incercati sa vedeti ce mesaje de eroare obtineti, lasind la o parte parti din program.


Si acum citeva explicatii despre programul insusi. Un program C, oricare i-ar fi marimea, consta din una sau mai multe 'functii' care specifica operatiile efective de calculat care trebuiesc facute. Functiile din C sint similare cu functiile si subrutinele dintr-un program Fortran sau cu procedurile din PL/1, Pascal,etc.In exemplul nostru, 'main' este o astfel de functie. In mod normal aveti libertatea de a da functiilor ce nume doriti, dar 'main' este un nume special - programul dumneavoastrase va executa de la inceputul lui 'main'. Aceasta inseamna ca fiecare program trebuie sa aibe un 'main' undeva, ca 'main' va invoca in mod obisnuit alte functii pentru a-si realiza scopul, unele venind din acelasi program iar altele din biblioteci ce contin functii scrise anterior.


Ometoda de a comunica date intre functii este prin argumentele functiilor. Parantezele care urmeaza dupa numele functiei includ lista de argumente. In cazul nostru, 'main' este o functie fara argumente ceea ce se indica prin '()'. Acoladele'' includ instructiunile care alcatuiesc functia.Ele sint analoage lui 'DO-END' din PL/1 sau lui 'begin-end' din ALGOL, PASCAL, etc. O functie este apelata prin nume, urmate de o lista de argumente in paranteze. Nu exista instructiunea CALL ca in FORTRAN sau PL/1.Parantezele trebuie sa fie prezente chiar daca nu exista argumente.

Linia care spune:


printf('hello, worldn');


este un apel de functie, care cheama o functie numita 'printf' cu argumentul ('hello, worldn').'printf' este o functie din biblioteca care tipareste pe terminal (daca nu este specificata o alta destinatie).In acest caz, ea tipareste sirul de caractere care alcatuiesc argumentul.


O secventa alcatuita din orice numar de caractere cuprinse intre doua ghilimele '' se numeste sir de caractere sau constanta sir. Pentru moment, singura folosire a sirurilor de caractere va fi ca argumentele pentru 'printf' si alte functii.


Secventa 'n' din sir este notatia din C pentru caracterul 'linie noua', care, cind este tiparit, avanseaza cursorul terminalului la marginea din stinga a urmatoareilinii.Dacauitati 'n' (un experiment care merita facut), veti observa ca iesirea dumneavoastra nu se termina cu o linie noua. Singurul mod de a aveacaracterul'linie noua' in 'printf'este'n' ca argument. Daca incercati ceva de tipul


printf('hello, world

');


compilatorul C va va tipari un diagnostic neprietenos despre ghilimele absente.


'printf'nufurnizeaza o linie noua in mod automat, asa ca apelurile multiple pot fi folosite pentru a tipari o linie pe etape. Primul nostru program poate fi scris la fel de bine si astfel:


main()



pentru a produce o iesire identica. Sa notam ca 'n' reprezinta un singur caracter.O 'secventa scape' ca de exemplu 'n' este ingeneralunmecanism extensibil pentru reprezentarea caracterelor greu deobtinut sau invizibile. Printre alte secvente escape, limbajul C poseda: t pentru tab, b pentru backspace, ' pentru apostrof dublu si pentru backspace.


Exercitiul 1.2. Experimentati sa vedeti ce se intimpla cind sirul argument din 'printf' contine 'x' un x este un caracter oarecare care nu a fost listat mai sus.


1.2. Variabile si aritmetica

Urmatorul program tipareste tabela de temperaturi Fahrenheit si echivalentele lor in centigrade sau grade Celsius, folosind formula: C = (5 / 9) * (F - 32).


0 -17.8

20 -6.7

404.4

60 15.6


260 126.7

280 137.8

300 148.9

Iata acum si programul:


/* Print Fahrenheit-Celsius table

for f = 0, 20, , 300 */

main()


}


Primele doua linii :


/* Print Fahrenheit-Celsius table

for f = 0, 20, , 300 */


sint un comentariu, care in acest caz explica pe scurt ce fac programul. Orice caracterecuprinse intre '/*' si '*/' sint ignorate de compilator;ele pot fi folosite liberpentrua face programul mai usor de inteles. Comentariile pot apare oriunde poate aparea un spatiu sau o linie noua.


In limbajul C, toate variabilele trebuie declarate inainte de a fi folosite, deobicei la inceputul liniei, inaintea oricarei instructiuni executabile. Daca veti uita o declaratie, veti primi un diagnostic de la compilator. O declaratie consta dintr-un 'tip' si o lista de variabile care au acel tip, ca in:


int lower, upper, step;

float fahr, celsius;


Tipul'int' implica faptul ca variabilele listate sint intregi; 'float' denota virgula mobila, adica numere care pot avea parte fractionara. Precizia atit pentru 'int' cit si pentru 'float' depinde de calculatorul pe care-l folositi. PentruPDP-11, de exemplu, un 'int' este un numar cu semn de 16 biti, adica un numar cuprins intre -32768 si +32767 . Un numar 'float' este o cantitate ce se reprezinta pe 32 de biti ceea ce revine la aproximativ sapte cifre semnificative, cu magnitudinea cuprinsa aproximativ intre 10 ^ -38 si 10 ^ +38. Capitolul 2 da olista a acestor marimi pentru alte calculatoare.

Pelinga tipurile 'int' si 'float', limbajul C poseda si alte tipuri de date fundamentale :


'char'caracter - un singur octet

'short' intreg scurt

'long'intreg lung

'double' numar flotant dubla precizie


Marimea acestor obiecte este deasemenea dependenta de calculator; detalii se dau in Capitolul 2. Exista deasemenea 'tablouri', 'structuri' si 'uniuni' de asemenea tipuri de baza, 'pointeri' la ele si 'functii' care le returneaza si cu toate ne vom intilni in aceasta carte.

Calculul efectiv in programul de conversie temperatura incepe cu asignarile:


lower = 0;

upper = 300;

step = 20;

fahr = lower;


care seteaza variabilele pe valorile lor de start. Instructiunile individuale se termina cu punct si virgula.Fiecare linie a tabelei este calculata in acelasi fel, asa ca vom folosi o bucla care se repeta odata pe linie; acesta este scopul instructiunii 'while':


while (fahr <= upper)


Este testata conditia din paranteza. Daca ea este adevarata (fahr este mai mic sau egal cu upper), este executat corpul buclei (toate instructiunile incluse intre parantezele).Apoiconditia este retestata si,daca este adevarata, corpuleste executat din nou . Cind testul devine fals (fahr este mai mare decit upper), bucla se termina si executia continua cu instructiunea care urmeaza buclei. Deoarece in acest program nu mai exista alte instructiuni care sa succeada bucla, executia lui se termina.

Corpul unei buclewhile poate fi alcatuit din mai multe instructiuni incluse intre acolade, ca in programul de mai sus sau dintr-o singura instructiune, fara paranteze, ca in exemplul de mai jos:


while(i<j)

i = 2 * i;


In ambele cazuri, instructiunile controlate de 'while' sint decalate cu un tab, asa ca se observa de la prima privire ce instructiuni se gasesc in interiorul buclei. Decalarea scoate in evidenta structura logica a programului. Cu toate ca limbajul C estedestulde liberal in ceea ceprivestepozitionarea instructiunilor, o tabulare potrivita si folosirea spatiilor albe sint critice in scrierea programelor usor citibile si de catre altii decit autorul lor.

Recomandam scrierea unei singure instructiuni pe un rind si lasarea de spatii (uzual) in jurul operatorilor. Pozitia acoladelor este mai putin importanta; noi am ales unul dintre stilurile cele mai populare. Alegeti-va un stil care va convine, apoi folositi-l consecvent.


Temperatura celsius este calculata si asignata lui 'celsius' prin instructiunea:


celsius = (5.0 / 9.0) * (fahr - 32.0);


Ratiunea pentru folosirea lui (5.0/9.0) in locul mai simplei 5/9 este aceea ca in C, ca si in multe alte limbaje,impartirea intreaga trunchiaza rezultatul, asa ca orice parte fractionara este eliminata. Astfel 5/9 este zero si tot asa ar fi fost toate temperaturile. Un punct zecimal intr-o constanta indica faptul ca aceasta este flotanta si deci 5.0/9.0 este 0.5555 ceea ce am si dorit. Am scris deasemenea 32.0 in loc de 32, chiar daca deoarece 'fahr' este 'float', 32 ar fi convertit automat in 'float' inainte de scadere. Ca o problema de stil,este bine sa scriem constantele flotante cu punct zecimal explicit chiar cindau valoriintregi;aceastaaccentueaza naturalorflotanta pentru cititoriiumani si ne asigura ca si compilatorulva gindi in acelasi mod ca si noi.


Reguliledetaliatepentru conversiile deintregiin flotante sint date in Capitolul 2. Acum sa notam doar ca asignarea


fahr = lower;


si testul


while (fahr <= upper)


vor lucra amindoua asa cum ne asteptam 'int' este convertit in 'float' inainte de executia operatiei.


Acestexemplu arata deasemenea putin mai multe despre modul de lucru al lui 'printf'. Ea este o functie de conversie de format cu scop general, care va fi descrisa complet in Capitolul 7. Primul sau argument este un sir de caractere ce se vor tipari, fiecare caracter % indicind argumentele (al doilea, al treilea) cese vasubstitui si forma in care se vor tipari. De exemplu, in instructiunea


printf('%4.0f %6.1fn', fahr, celsius);


specificatiade conversie '%4.0f' spune ca un numar flotant va fi tiparit intr-un spatiu de cel putin patrucaractere, cu zero cifre dupa punctul zecimal. '%6.1f' descrie un alt numar care va ocupa cel putin sase spatii, cu o cifra dupapunctul zecimal,analog cu F6.1 din FORTRAN sau F(6,1) din PL/1. Parti dinspecificator pot fi omise:'%6f' arata ca numarul are o lungime de cel putin 6 caractere;'%.2f' cere doua pozitii dupa punctul zecimal, dar lungimea lui nu este supusa restrictiilor; '%f' spune doar sa se tipareasca numarul caflotant. 'printf' recunoaste deasemenea: '%d' pentru intregi zecimali, '%o' pentru numere octale,'%x' pentru hexazecimale, '%c' pentru un caracter, '%s' pentru sir de caractere si '%%' pentru insusi

semnul '%'.

Fiecare constructie cu % in primul argument al lui 'printf' face pereche cu al doilea, al treilea, argument. Aceste perechi trebuie sa corespunda ca numar si tip, altfel veti avea surpriza

unor rezultate lipsite de inteles.


Fiindca veni vorba, 'printf' NU face parte din limbajul C. Nu exista definite in C intrari si iesiri. Nu e nimic magic in legatura cu 'printf' ea este pur si simplu o functie utila care face parte din biblioteca standard de rutine care sint in mod normal accesibile programelor C. Cu scopul de a ne concentra asupra limbajului C, nu vom spune prea multe despre operatiile de I/O pina in Capitolul 7.In particular,vom amina descrierea intrarilor cu format pina atunci.Dacaaveti de introdus numere, cititi descrierea functiei 'scanf' din Capitolul 7,sectiunea 7.4; 'scanf' este foarte asemanatoare cu 'printf' atit doar ca ea citeste intrari in loc sa scrie iesiri.




Exercitiul 1.3. Modificati programul de conversie temperaturi pentru a scrie un antet la inceputul tabelei de conversie.


Exercitiul 1.4. Scrieti un program care sa tipareasca tabela corespunzatoare Celsius - Fahrenheit.


1.3. Instructiunea For


Asa cum probabil va asteptati, exista o multime de moduri pentru a scrie un program; haideti sa incercam o alta varianta a programului de conversie de temperatura :


main() /* Fahrenheit-Celsius table */



Aceasta va produce aceleasi rezultate dar, cu siguranta, arata altfel decit prima. O modificare esentiala este eliminarea majoritatii variabilelor; a ramas numai 'fahr',declarata ca 'int' (observati specificatorul '%d' in printf). Limitele inferioara si superioara si marimea pasului apar doar ca si constante in instructiunea'for',ea insasi oconstructienoua,iar expresia care calculeaza temperatura Celsius apare acum ca al treilea argument din 'printf' in loc de a fi o instructiune de asignare separata.

Aceasta ultima schimbare este un exemplu pentru o regula generala in C - in orice context in care este permisa folosirea valorii unei variabile de un anumit tip, se poate folosi oexpresie de acel tip. Deoarece al treilea argument al lui 'printf' trebuie sa fie o valoare flotanta pentru a se potrivi cu '%6.1f', orice expresie flotanta poate apare pe locul ei.


Instructiunea'for' este o bucla,o generalizarealui 'while'. Daca o comparati cu 'while', aceasta afirmatie va va fi clara. Ea contine trei parti separate prin punct si virgula. Prima parte


fahr = 0


seface o data,inainte ca bucla propriu-zisa sa inceapa. A doua parte este testul sau conditia care controleaza bucla:


fahr <= 300


Este evaluata aceasta conditie; daca ea este adevarata, este executat corpul buclei (la noi, o singura 'printf'). Urmeaza apoi pasul de reinitializare


fahr = fahr + 20


careeste executat si apoi conditia este reevaluata. Bucla se termina atunci cind conditia devine falsa.La fel ca si la instructiunea 'while', corpul buclei poate fi alcatuit dintr-o singura instructiune sau dintr-un grup de instructiuniinclus intre acolade. Partile de initializare si reinitializare pot fi o singura expresie.


Alegerea intre 'while' si 'for' este arbitrara, bazata pe ceea ce ne pare noua a fi mai clar. Instructiunea 'for' este potrivita in mod uzual pentru buclele in care initializarea si reinitializareasintinstructiuni unice si logic inruditedeoarece este mai compacta decit 'while' si pastreaza instructiunile de control al buclei intr-un singur loc si impreuna.


Exercitiul 1.5. Modificati programul de conversie temperatura pentru a tipari tabela in ordine inversa, adica de la 300 de grade la zero.


1.4. Constante simbolice


Vom face o observatie finala inainte de a parasi pentru todeauna programul de conversie de temperatura.E o practica proasta aceea de a inmorminta 'numere magice' ca 300 sau 20, intr-un program; eletransmit putina informatie cuiva carevaciti programul mai tirziu si este greu sa le modificam intr-o maniera sistematica.Dinfericire,C poseda o modalitate de a evita astfel de numere magice.Cu ajutorul constructiei '#define', sepot defini la inceputul programului nume sauconstante simbolice,caresint un sir particular de caractere.Dupa aceea, compilatorulva inlocui toateaparitiile nepuse intre ghilimele ale numelui, prin sirul corespunzator. Inlocuirea efectiva a numelui poate fi orice text; ea nu se limiteaza la numere.


#define LOWER 0 /* lower limit of the table */

#define UPPER 300/* upper limit */

#define STEP 20 /* step size */

main() /* Fahrenheit-Celsius table */



Cantitatile LOWER,UPPER si STEP sint constante, asa incit ele nu apar in declaratii.Numele simbolice se scriu in mod normal cu litere mari, asa ca ele pot fiusordistinse de numele de variabile care se scriu cu litere mici. Sa notam ca la sfirsitulunei definitii NU se pune punct si virgula. Deoarece intreaga linie de dupa numele definit estesubstituita, in instructiunea 'for' ar exista prea multe punct si virgule.


1.5. O colectie de programe utile


Vomconsidera in cele ce urmeaza o familie deprograme inrudite pentru efectuarea de operatii simple asupra datelor alcatuite din caractere. Vom vedea ca multe programe sintdoar versiuni extinse ale prototipurilor pe care le vom discuta aici.



Introducere si extragere de caractere


Biblioteca standard poseda functii pentru citirea si scrierea unui caracter la un moment dat. 'getchar()' aduce urmatorul caracter de intrare de fiecare data cind este apelata si returneaza acel caracter ca si valoare a ei. Adica, dupa


c=getchar()


variabila 'c' contine urmatorul caracter de intrare. Caracterele vin in mod normal de la terminal,dar aceasta nu ne intereseaza pina in Capitolul 7.

Functia 'putchar(c)' este complementara lui 'getchar()':


putchar(c)


tipareste continutul variabilei 'c' pe un mediu de iesire, in mod normal, tot pe terminal. Apelurile la 'putchar' si 'printf' pot fi intercalate; iesirea va apare in ordinea in care s-au facut apelurile. Ca si in cazul lui 'printf',nu exista nimic special relativ la 'getchar' si 'putchar'. Ele nu sint parti ale limbajului C, dar sint universal disponibile.


Copiere de fisiere


Date 'getchar' si 'putchar', veti putea scrie o cantitate surprinzatoare de cod util, fara a sti nimic despre operatiile de I/O. Cel mai simplu program este acela care-si copiaza intrarea in iesire, caracter cu caracter. Schitindu-l:


citeste_un_caracter

while (caracterul_nu_este_semnal_de_sfirsit_de_fisier)

tipareste_caracterul_chiar_citit

citeste_un_nou_caracter


Convertind aceasta in limbajul C, obtinem:


main()/* copy input to output; 1st version */


}


Operatorul relational '!=' inseamna 'diferit de'. Principala problema este detectarea sfirsitului de intrare. Prin conventie, 'getchar' returneaza o valoare care nu este un caracter valid atunci cind intilneste sfirsitul intrarii;in acest mod, programele pot detecta cind s-au terminat intrarile.Singura complicatie,o neplacere serioasa de fapt este aceea ca exista doua conventii ce se folosesc uzual pentru valoarea sfirsitului de fisier.Noi am evitat aceasta folosind deobicei numele simbolic de EOF pentru aceasta valoare, oricare ar fi fost ea. In practica, EOF poate fi sau -1 sau0, asa ca programul trebuie sa fie precedat de una din declaratiile de mai jos:


#define EOF -1

sau

#define EOF 0


pentru ca el sa lucreze corect. Folosind constanta simbolica EOF pentru a reprezenta valoarea pe care o returneaza getchar cind intilneste sfirsitul de fisier,ne asiguram ca numai un singur lucru din program depinde de valoarea numerica specificata.

De asemenea il declaram pe 'c' ca fiind 'int', nu 'char', pentru ca el sa poata pastra valoarea pe care oreturneaza 'getchar'. Cum vom vedea in Capitolul 2, aceasta valoare este normal un 'int', deoarece ea trebuie sa fie capabila sa-l reprezinte si pe EOF in plus fata de toate char-urile posibile.

Programulde copiere ar putea fi de fapt scris mult mai concis de catre un programator experimentat in limbajul C. In C, o asignare ca


c = getchar()


poatefifolosita intr-o expresie; valoarea sa este pur si simplu valoarea ce se asigneaza partii stingi. Daca asignarea unui caracter lui c se pune in partea de test a unui 'while',programul de copiat fisiere poate fi scris astfel:


main() /* copy input to output; 2nd version */



Programul citeste un caracter, il asigneaza lui 'c' si apoi testeaza daca acesta a fost semnalul de sfirsit de fisier. Daca nu a fost, corpul buclei 'while' esteexecutat,tiparindu-se caracterul sibucla se repeta. Cind semnalul de sfirsit de fisier este atins in fine,bucla 'while' se termina, termininduse totodata si programul 'main'.


Aceasta versiune centralizeaza intrarile - nu mai apare decit un singur apel la 'getchar'- si restringe programul.Plasarea unei asignari intr-untest constituie unul din locurile unde C permite o concizie uluitoare. (Este posibil sa mergeti si mai departe, creind un cod impenetrabil, tendinta pe care noi incercam sa nu o incurajam).


Este important sa recunoastem caparantezele ce includ asignarea sint absolut necesare.Ponderea lui '!=' este mai mare decit aceea a lui '=' ceea ce inseamna ca, in absenta parantezelor, testul relational '!=' va fi facut inaintea asignarii '='. Asa ca instructiunea


c = getchar() != EOF


este echivalenta cu


c = (getchar() != EOF)


Aceasta are un efect nedorit, prin setarea lui 'c' pe 0 sau 1, dupa cum apelul lui 'getchar ' a intilnit sau nu sfirsitul de fisier. (Mai multe despre acestea se vor vedea in Capitolul 2).


Contorizarea caracterelor


Urmatorul program va contoriza caracterele;el este o mica elaborare a programului de copiere.


main() /* count characters in input */



Instructiunea


++nc;


ne introduce un nou operator '++' care inseamna, increment cu 1. Se putea scrie si 'nc = nc+1', dar '++nc' este mai concisa si adesea mai eficienta. Exista un operator corespunzator, '--' pentru decrementare cu 1. Operatorii '++' si '--' pot fi atit operatori prefix, cit si sufix ('nc++'); aceste doua forme au valori diferite in expresii asa cum se va arata in Capitolul 2, dar '++nc' si 'nc++' il incrementeaza amindoi pe 'nc'.

Programulde contorizare de caractere acumuleaza numarul de caractere intr-o variabila 'long' in loc de 'int'. La PDP-11, valoarea maxima pentru un intreg este 32767 si s-ar putea ca sa dam pesteo depasire de contor daca-l declaram intreg; pe Honeywell si pe IBM, 'long' si 'int' sint sinonime si mult mai mari.Specificatoruldeconversie'%ld'semnaleazalui 'printf' ca argumentul corespunzator este un intreg 'long'. Pentru a face fata la numere chiar si mai mari, se poate folosi o declaratie de 'double' ('float' de lungime dubla). Vom folosi,deasemenea, instructiunea 'for' in locul lui 'while' pentru a ilustra un alt mod in scrierea buclei.


main() /* count characters in input */



'printf' foloseste '%f' atit pentru 'float' cit sipentru 'double'; '%.0f' suprima tiparirea partii fractionare inexistente.


Corpul  buclei 'for' este in cazul acesta vid, deoarecetoata munca este facuta in partile de test sireinitializare.Dar regulile gramaticale ale limbajului C pretind ca o instructiune 'for' sa aiba un corp. Punctul si virgula ce apare izolat pe o linie, in mod tehnic o instructiune nula, este pus tocmai pentru a satisface aceasta cerere. Noi l-am pus pe o linie separata tocmai pentru a-l face mai vizibil.


Inaintedea parasi programul de contorizare caractere, sa observam ca daca intrarea nu contine nici un caracter, testul din 'while' sau 'for' esueaza la primul apel la getchar si deci rezultatul programului este zero, ceea ce este corect. Aceasta este o observatie importanta. Unul din lucrurile frumoase care se potspunedespre 'while' si despre 'for' este cela ca ele testeaza la inceputul buclei,inainte de a prelucra corpul buclei. Daca nu este nimic de facut, nimic nu se face, chiar daca aceasta inseamna ca nu se va parcurge corpul buclei niciodata.Programelevor actiona inteligent atunci cind vor minui intrari de tipul 'nici un caracter'. Instructiunile 'while' si 'for' ne asigura ca vor face lucruri rezonabile si in conditii la limita.


Contorizarea liniilor

Urmatorulprogram contorizeaza liniile pe care le primeste ca intrare. Liniile de intrare se presupun a fi terminate cu un caracter 'linie noua' n adaugat cu sfintenie la fiecare linie scrisa.


main() /* contorizarea liniilor in intrare */



Corpul buclei 'while' consta acum dintr-un 'if',care la rindul ei controleaza incrementarea ++nl. Instructiunea 'if' testeaza conditia din paranteza si, daca este adevarata, se executa instructiunea(sau grupul de instructiuni dintre acolade)care urmeaza. Am aliniat iarasi, ca sa aratam ce este controlat de cine (ce).


Semnuldublude egal '==' este in C notatia pentru 'este egal cu' (ca si .EQ. din FORTRAN). Acest simbol este folosit pentru a distinge testul de egalitate de egal simplu (=) folosit pentru asignare. Deoarece asignarea este cam de doua ori mai frecventa in C decit testul de egalitate, este normal ca si operatorul de asignare sa fie jumatate din cel de egalitate, ca lungime.




Oricecaractersingur poate fi scrisintreapostrofuri, pentru a produce valoarea numerica a caracterului in codul de carctere al calculatorului; acesta se numesteconstantade caracter.Asa de exemplu, 'A' este o constanta de caracter; in setul de caractere ASCII,valoarea sa este 65, reprezentarea interna a caracterului A. Desigur 'A' este de preferat lui 65: semnificatia lui este evidenta si independenta de orice set particular de caractere.


Secventeleescape folosite in sirurile de caractere sint si ele legale in constantele de caracter, asa ca in teste si in expresii aritmetice 'n' tine locul caracterului 'linie noua'. Sa notam ca 'n' este un singur caracter si, in expresii,este echivalent cu un singur intreg; pe de alta parte, 'n' este unsir de caractere care,intimplator,contine un singur caracter. Subiectul comparatiei intre siruri si caractere este discutat mai departe in Capitolul 2.


Exercitiul 1.6. Scrieti un program care sa numere blankurile, taburile si new-line-urile.


Exercitiul 1.7. Scrieti un program care sa copieze intrarea in iesire,inlocuind fiecare sir de unul sau mai multe blankuri cu un singur blank.


Exercitiul 1.8. Scrieti un program caresa inlocuiasca fiecare tab printr-o secventa >,backspace,- careseva tipari ca '->' s fiecare backspace prin secventa similara '<-'. Aceasta face taburile si backspace-urile vizibile.


Contorizarea de cuvinte

Al patrulea program din seria de programe utile va contoriza linii, cuvinte si caractere,un singur cuvint fiind definit ca oricesecventa de caractere care nu contine blanc,tabsau linienoua(acesta este de fapt un schelet al programului utilitar 'wc' din UNIX).


#define YES 1

#define NO0

main() /*contorizare linii, cuvinte si caractere la intrare*/



printf('%d %d %d'n', nl, nw, nc);

}


Defiecaredata cind programul intilneste primul caracter al unui cuvint, il contorizeaza. Variabila 'inword' inregistreaza de cite ori programul este intr-un cuvint sau nu ; initial el 'nu este intr-un cuvint ' si variabilei i s-a asignatvaloarea NO. Preferam constantele simbolice YES si NO valorilor literale 1 si 0 deoarece ele fac programul mai usor citibil. Desigur ca intrun program mic ca acesta diferenta este mica,dar intr-un program mai mare cresterea in claritate merita micul efort suplimenar de a-l scrie in acest mod delainceput. Veti vedea deasemenea ca este mai usor sa efectuati modificari masive in programe in care numerele apar numai ca si constante simbolice.


Linia


nl = nw = nc = 0;


seteaza toate cele trei variabile pe zero. Acesta nu este un caz special ci doar o consecinta a faptului ca oasignare asociaza de la dreapta spre stinga. Este ca si cind am fi scris;


nc = (nl = (nw = 0));


Operatorul || inseamna SAU, asa ca linia


if(c == ' ' || c == 'n' || c == 't');


spuneca'daca c este un blanc sau c este o linie noua sau c este un tab'. (Secventa escapet estereprezentarea vizibila a caracterului tab).Exista un operatorcorespunzator && pentru SI. Expresiile conectate prin && sau || sint evaluate de la stinga la dreapta si evaluarea se opreste atunci cind se cunoaste adevarul sau falsul expresiei. Astfel daca c contine un blanc, nu mai este nevoie sa testam daca el contine o line noua sau un tab, asa ca testele acestea nu se mai fac. In particular, aceasta nu este important aici, dar este foarte semnificativ in multe situatii complicate, asa cum vom vedea in curind.


Exemplul nostru foloseste deasemeneainstructiunea 'else', care specifica o actiune alternativa ce trebuie executata daca partea de conditie unei instructiuni 'if' este falsa.


Forma generala este:


if (expresie)

instructiune1

else

instructiune2


Una si numai una din instructiunile asociate cu if-else se executa. Daca 'expresia' este adevarata,se executa 'instructiunea-1'; daca nu, se executa 'instructiunea-2'.Fiecare 'instructiune'poate fi, de fapt, mult mai complicata. In exemplul nostru instructiuea de dupa 'else' este un 'if' care controleaza doua instructiuni in paranteze.


Exercitiul 1.9. Cum veti testa programul de contorizare cuvinte? Care sint unele dintre limitele lui ?


Exercitiul 1.10. Scrieti un program care sa tipareasca cuvintele introduse,cite unul pe linie.


Exercitiul 1.11. Revizuiti programul de contorizare cuvinte pentru a folosi o mai buna definitie a'cuvintului',de exemplu o secventa de litere, cifre si apostrofuri care incepe cu o litera.


1.6. Tablouri

Vom scrie acum un program care va contoriza aparitiile fiecarei cifre, a fiecarui caracter de spatiere (blanc, tab, linie noua) si a tuturor celorlalte caractere. Desigur, este un program artificial, dar ne va permite sa ilustram mai multe aspecte ale lui C intr-un singur program.


Exista 12 categorii de intrari, asa ca ne este mai convenabil sa folosim un tablou pentru a tine numarul de aparitii a fiecarei cifre, decit sa folosim 10 variabile individuale. Iata acum o versiune a acestui program:


main() /* contorizeaza cifre, spatii albe, alte caractere */



Declaratia


int ndigit[10];


spunecandigit este un tablou de 10 intregi. Indiciide tablou intodeauna incep de la zero in C (spre deosebire de FORTRAN sau PL/1 unde incepe de la unu), asacaelementele tabloului sint ndigit[0], ndigit[1] , ,ndigit[9]. Acestea se reflecta in buclele 'for', care initializeaza si tiparesc tabloul. Un indice poate sa fie orice expresie intreaga, inclusiv desigur variabilele intregi ca 'i', sau constantele intregi. Acestprogram particular se bazeaza mult pe proprietatile reprezentarii drept caractere a cifrelor. De exemplu, testul


if (c >= '0' && c <= '9')


determina daca un caracter din c este cifra. Daca el este cifra, valoare numerica a acelei cifre este


c - '0'


Acest algoritm functioneaza bine numai daca '0', '1', etc sint pozitive si in ordine crescatoare, si intre '0' si '9' nu se gaseste altceva decit cifre. Din fericire,aceastaeste adevarulpentrutoate seturile de caractere conventionale.


Prindefinitie,calculelearitmetice care implica tipuri 'char' si 'int', convertesc totul in tipul 'int' inainte de prelucrare, asa ca variabilele si constantele de tip 'char' sint esential identice cu tipul 'int' in contexte aritmetice. Acest fapt este aproape natural si convenabil; de exemplu:c-'0' este o expresie intreaga cu o valoare intre 0 si 9 corespunzatoare caracteruluidintre '0' si '9' depus in c, si deci este un indice valid pentru tabloul ndigit.


Decizia se ia asupra caracterului (daca el este o cifra, un caracter de spatiere sau altceva) in secventa:


if (c >= '0' && c <= '9')

++ndigit[c-'0'];

else if (c == ' ' || c == 'n' || c == 't')

++nwhite;

else

++nother;


Constructia de tipul


if (conditie)

instructiune

else if (conditie)

instructiune

else

instructiune


aparefrecvent in programe ca o modalitate de a exprima deciziile multiple. Codul se citeste simplu de sus in jos pina cind o conditie este indeplinita; in acest punct,se executa partea corespunzatoare de 'instructiune' si intreaga constructie este terminata.(Desigur ca 'instructiune' pot fi mai multe instructiuni incluse intre paranteze). Daca nici una din conditii nu este indeplinita, instructiunea care urmeaza dupa ultimul 'else' este executata daca este prezenta. Daca 'else' final si 'instructiune' lipsesc (ca in programul nostru), nu are loc nici o actiune. Pot exista un numar arbitrar de constructii de tipul


else if (conditie)

instructiune


grupateintre 'if'-ul initial si 'else'-ul final. Ca o chestiune de stil, va sfatuim sa formati aceste constructii asa cum le-am facut si noi, astfel incit deciziile lungi sa nu ajunga pe marginea din dreapta a paginii.


Instructiunea 'switch', care va fi prezentata in Capitolul 3, reprezinta un alt mod de a scrie o decizie multipla si este potrivita, in particular, cind conditia care se testeaza este simpla sau cind o expresie de caractere sau de intregi se potriveste cu o constanta dintr-un sir dat. Prin contrast, vom prezenta o versiune 'switch' a acestui program in Capitolul 3.


Exercitiul 1-12. Scrieti un program pentru a tipari histograma lungimilor cuvintelor care apar la intrare.Este cel mai usor sa desenati histograma orizontal; o orientare verticala este mai laborioasa.


1.7. Functii

In C o functie este echivalenta cu o subrutina sau cu o functie din FORTRAN sau cu o procedura din PL/1 sau PASCAL, etc. O functie reprezinta un mod convenabil dea incapsula anumite calcule intr-o cutie neagra care poate fi apoi folosita farasa ne mai pese de ce se afla inauntru. Functiile sint singura modalitate de a face fata la complexitatea potentiala a programelor mari. Cu functii scrise asa cum trebuie,este posibil sa ignoram 'cum' este facuta o anumita treaba; ne este suficient sa stim 'ce' anumita treaba este facuta. Limbajul C este proiectat pentrua face folosirea lor usoara, convenabila si eficienta; vetiobserva adesea o functie lunga numai de citeva rinduri, apelata o singura data, numai fiindca ea clarifica anumite portiuni de cod.


Pina acum am folosit numai functii ca printf, getchar si putchar, care au fost scrise de altii pentru noi;este momentulsa ne scriem si noi propriile noastre functii. Deoarece limbajul C nu poseda un operator de exponentiere ca ** din FORTRAN sau PL/1, vom ilustra mecanismul de definire de functii scriind ofunctie putere 'power(m,n)' care va ridica un intreg la o putere intreaga pozitiva in n. Adica, valoarea lui power(2,5) este 32. Desigur ca aceasta functie nu realizeaza toata treabalui** deoarece minuieste numai puteri pozitive ale intregilor mici, dar cel mai bine,este bine sa aprofundam un lucru la un moment dat.

Iata acum functia 'power' si un program principal care o foloseste, asa ca puteti vedea deodata intreaga structura.


main() /* testeaza functia power */


power(x,n) /* ridica pe x la puterea a n-a ; n > 0 */

int x, n;



Orice functie are o aceeasi forma:


nume (lista de argumente, daca exista)

declaratii de argumente, daca exista



Functiilepot apare in orice ordine si intr-un fisier sursa sau in doua. Bineinteles,daca sursa apare in douafisiere, veti avea mai multe de spus la compilare si incarcare decit daca e un singur fisier dar asta este o problema a sistemuluide operaresi nu un atribut al limbajului. Pentru moment vom presupuneca ambele functii se gasesc intr-un acelasi fisier, asa ca ceea ce ati invatat despre executia programelor C nu se modifica.Functia 'power' este apelata de doua ori in linia


printf('%d %d %dn', i, power(2,i), power(-3,i));


Fiecareapel trimite doua argumente lui power, care de fiecare data returneaza un intreg care trebuie formatat si tiparit. Intr-o expresie power(2,i) este un intreg, la fel ca si 2 si i. (Nu toate functiile produc o valoare intreaga; vom vedea aceasta in Capitolul 4). In 'power' argumentele trebuie sa fie declarate corespunzator cu tipul lor cunoscut. Aceasta este facuta de linia


int x,n;


care urmeaza liniei cu numele functiei. Declaratiile de argumente urmeaza sa se situeze intre lista de argumente siacolada stingadeschisa


Argumentuln este folosit ca o variabila temporara, si este decrementat pina cind devine zero; nu mai este nevoie de variabila i. Ceea ce se face cu n in interiorul lui power nu are nici un efect asupra argumentului cu care a fost apelata power initial.


Cind este necesar, este posibil sa aranjam ca o functie sa modifice o variabila in rutina apelanta. Apelandul trebuie sa dea adresa variabilei de setat (in mod tehnic, sa creeze un pointer la variabila),iar functia apelata trebuie sa declare argumentul ca fiind un pointer si sa refere variabila reala in mod indirect prin el. Vom discuta in detaliu aceste probleme in Capitolul 5.


Cind numele unui tablou este folosit ca si argument, valoarea transmisa functiei este locatia sau adresa de inceput a tabloului. (Nu se face nici o copiere de elemente de tablou). Indiciind aceasta valoare, functia poate avea acces si altera orice element al tabloului. Acesta este subiectul urmatoarei sectiuni.


1.9. Tablouri de caractere

In mod probabil, cel mai comun tip de tablouri in limbajul C este tabloul de caractere. Pentru a ilustra folosirea tablourilor de caractere si a functiilor care le manipuleaza, vom scrie un program care citeste un set de linii si o tipareste pe cea mai lunga.



Schita lui este destul de simpla:


while (mai exista o alta linie)

if (este mai lunga decit linia anterioara)

salveaza-o pe ea si lungimea ei

tipareste linia cea mai lunga


Aceastaschitane arata clar ca programul se imparte in bucati. O bucata citeste o linie noua, o alta bucata o testeaza, o alta o salveaza iar restul controleaza procesul.

Deoarece lucrurile se impart asa de frumos, ar fi mai bine sa le scriem la fel. Pentru aceeasta,vom scrie la inceput o functiegetlinecare va citi urmatoarea linie de la intrare; ea este generalizare a functiei getchar. Pentru a face functia utila si in alte contexte, vom incerca sa o scriem cit mai flexibil. In mod minim, getline va trebui sa returneze un semnal despre posibilul sfirsit de fisier; proiectind-o mai general, ea va trebui sa returneze lungimea liniei sau zero daca se intilneste sfirsitul de fisier. Zero nu este niciodata o lungime valida de linie, deoarece orice linie are cel putin un caracter, chiar si o linie ce contine numai caracterul 'linie noua' are lungimea 1.

Cind gasim o linie care este mai lunga decit linia cea mai lunga gasita anterior, trebuie sa o salvam undeva. Aceasta sugereaza o a doua functie, copy, pentru a salva noua linie intr-un loc sigur.

In final, avem nevoie de un program principal care sa controleze functiile getline si copy. Iata rezulatul:


#define MAXLINE 1000 /* lungimea maxima a liniei */

main() /* gaseste linia cea mai lunga */


if (max > 0) /* s-a citit cel putin o linie */

printf('%s', save);

}


getline (s, lim) /* citeste linia in s, returneaza lungimea */

char s[];

int lim;

s[i] = '0';

return(i);



copy(s1, s2) /* copiaza pe s1 in s2; s2 suficient de mare */

char s1[], s2[];



main si getline comunica intre ele printr-o pereche de argumente si o valoare returnata. In getline, argumumentele sint declarate prin liniile:


char s[];

int lim;


carespunca primul argument este un tablou iar al doilea un intreg. Lungimea tabloului s nu este specificata in getline deoarece ea este determinata in main. 'getline' foloseste instructiunea return pentru a trimite o valoare inapoi apelantului,la fel cum facea si functia power.Unele functii returneaza o valoare utila;altele,de exemplu copy, sint folosite numai pentru efectul lor si nu returneaza nici o valoare.


getline pune caracterul 0 (caracterul nul, a carui valoare este zero) la sfirsitul tabloului pe care il creaza, pentru a marca sfirsitul sirului de caractere. Aceasta conventie este folosita de asemenea si de catre compilatorul C; cind o constanta sir de tipul


'hellon'


este scrisa intr-un program C, compilatorul isi creaza un tablou de caractere continind carcterele sirului si terminat cu 0, astfel incit o functie, de exemplu printf, poate sa-i determine sfirsitul.


----- ----- --------- ----- -------

| h | e | l | l | o | n | 0 |

----- ----- --------- ----- -------


Specificatorul de format %s din printf se asteapta la un sir reprezentat tocmai in aceasta forma. Daca examinati functia copy, veti descoperi ca si ea se bizuie de fapt pe terminarea argumentului sau de intrare s1 cu un 0 si ea copiaza acest caracter in argumentul de iesire s2. (Toate acestea presupun ca 0 nu este parte a unui text normal).

Este demn de mentionat in trecere ca, un program, chiar si atit de mic ca acesta, prezinta unele probleme delicate de proiectare. De exemplu, ce ar face main daca ar intilni o linie mai mare decit limita sa? getline lucreaza bine, adica se va opri atunci cind tabloul este plin chiar daca nu a intilnit nici un caracter 'linie noua'. Testind lungimea si ultimul caracter returnat, main poate determina cind a fost linia prea lunga si apoi sa actioneze cum vrea. Pentru a scurta programul, am ignorat acest aspect.

Nu exista vre-o cale pentru utilizatorul lui getchar de a sti inainte cit va fi de lunga o linie de intrare,asa ca getline verificadaca nu s-a produs o depasire. Pe dealta parte, utilizatorul lui copy stie intodeauna (sau poate descoperi) cit este de mare sirul, asa ca nu trebuie sa adaugam la functie o verificare de erori.


Exercitiul 1.14. Revizuiti rutina main din programul precedent astfel incit ea sa tipareasca corect lungimea unei linii de intrare de o lungime arbitrara,si atita text cit este posibil de tiparit.


Exercitiul 1.15. Scrieti un program care sa tipareascatoate liniile mai lungi de 80 de caractere.


Exercitiul 1.16. Scrieti un program care sa elimine blancurile nesemnificative (cele de dupa un caracter diferit de blanc sau tab) din fiecare linie de intrare si care sa stearga liniile care contin numai blancuri.


Exercitiul1.17Scrieti o functiereverse(s) care sa inverseze un sir de caractere s. Folositi-o pentru a scrie un program care isi inverseaza linie cu linie intrarea.

1.10 Domeniu; variabile externe

Variabile din main (line, save, etc) sint private sau locale lui main; deoarece ele sint declarate in main, nici o alta functie nu poate avea acces direct la ele. La fel se intimpla si cu variabilele din alte functii de exemplu variabila i din getline nu are nici o legatura cu varibila i din copy. Fiecare variabila locala dintr-o rutina se naste numai atunci cind functia este apelata si'dispare' cind functia isi termina activitatea. Aceasta este ratiunea pentru care astfel de variabile sint cunoscute uzual sint numele de variabile automate, urmind terminologia din alte limbaje. Vom folosi termenul de 'automat' de aici inainte pentru a ne referi la aceste variabile dinamice locale. (Capitolul 4 discuta clasa de memorie 'statica' in care variabilele locale isi pastreaza valoarea intre apelurile la functii).

Deoarece variabilele automate vin si pleaca odata cu apelurile de functii, ele nu-si pastreaza valoarea de la un apel laaltul si trebuie initializate explicit inainte de fiecare intrare. Daca nu sint setate, rezultatele vor fi imprevizibile.

Ca o alternativa la variabilele automate, este posibil sa definim variabile care sa fie 'externe' tuturor functiilor, adica, variabilele globale care sa fie accesate prin nume de orice functie care doreste sa o faca. (Acest mecanism estefoarte asemanator cu COMMON din FORTRAN sau EXTERNAL din PL/1). Deoarece variabilele externe sint accesibile global, ele pot fi folosite in locul listelor de argumente pentru a comunica date intre functii. Mai mult, deoarece variabilele externe exista permanent, si nu apar si dispar dupa cum functia este apelata sau s-a terminat, ele isi pastreaza valorile chiar si dupa ce s-a terminat functia care le-a setat.

Ovariabilaexternatrebuie sa fie definita in afara oricarei functii; acest lucru face sa se aloce memorie reala pentru ea. Variabila trebuie deasemenea sa fiedeclarata in fiecare functie care vrea sa o foloseasca; aceasta se poate face fieprintr-o declaratie explicita 'extern',fie implicit prin context. Pentru a face discutia corecta, vom rescrie programul precedent, in care line, save, max vor fi declarate variabile externe. Aceasta va cere modificari in apeluri, in declaratii si in corpurile celor trei functii.


#define MAXLINE 1000 /* marimea maxima a liniei de intrare */

char line[MAXLINE]; /* linia de intrare */

char save[MAXLINE]; /* cea mai lunga linie este salvata aici*/

int max; /* lungimea liniei celei mai mari */

main()/* gaseste linia cea mai lunga ;versiune specializata*/


if (max > 0) /* a fost cel putin o linie */

printf('%s', save);

}


getline() /* versiune specializata */


line[i] = '0';

return(i);

}


copy()/* versiune specializata */


Variabileleexterne din main, getline si copy sint definite de primele linii din exemplul de mai sus care declara tipul lor si provoaca o alocare de memorie pentru ele. Din punct de vedere sintactic, definitiile externe sint asemanatoare cu declaratiile pe care le-am folosit anterior dar deoarece ele apar in afara functiilor, variabilele sint externe. Inainte ca o functie sa poata folosi o variabila externa, numele variabilei trebuie sa fie facut cunoscut functiei O modalitate pentru a face aceasta este scriind o declaratie 'extern'; declaratia este identica cu cea de dinainte, avind insa in plus cuvintul cheie extern.

In anumite circumstante, declaratia 'extern' poate fi omisa: daca definitia externa a variabilei apare in fisierul sursa inainte de folosirea ei intr-o functie particulara, atunci nu este necesara o declaratie 'extern' in functie. Deci, declaratiile 'extern' din main, getline si cpoy sint redundante. De fapt practica uzuala consta in plasarea definitiilor tuturor variabilelor externe la inceputul fisierului sursa si apoi omiterea tuturor declaratiilor 'extern'.

Dacaprogramul consta din mai multe fisiere sursa si o variabila este definita in fisierul 1 si folosita in fisierul2atunci e nevoie de o declaratie 'extern' in fisierul 2 pentru a conecta cele 2 aparitii ale variabilei.Acest subiect este discutat pe larg in capitolul 4.


Putetinotaca am folosit cu grija cuvintele 'declaratie' si 'definitie' cind ne-am referit la variabile externe in aceasta sectiune. 'Definitiile' se refera la locul in carevariabila este efectiv creata si i se asigneaza memorie; 'declaratie' se refera la locul unde natura variabilei este declarata dar nu i se aloca memorie.


Fiindca veni vorba, exista o tendinta de a face totul cu ajutorul variabilelor externedeoarece ele par asimplificatoate comunicatiile - listele de argumente sint scurte si variabilele sint intodeauna acolo cind aveti nevoie de ele.Dar variabilele externe sint intodeauna acolo chiar si cind nu aveti nevoie de ele.Aceststil de a codifica este plin de pericole deoarece el conduce la programeale caror conexiuni de date nu sint evidente clar - variabilele pot fi modificate in moduri neasteptate si chiar inadvertente iar programul devine greu demodificat daca acest lucru este necesar. A doua versiune a programului care cauta linia cea mai luunga este inferioara primei, partial din aceste motive, si partial deoarece ea distruge generalitatea a doua functii atit de utile introducind in ele numele unor variabile pe care le vor folosi.


Exercitiul1.18Testul din instructiunea for din functia getline de mai sus este aproapedeneinteles.Rescrieti programul pentru a-l face mai clar dar pastrati acelasicomportamentlasfirsitulfisieruluisaula depasire de buffer. Este acest comportament cel mai adecvat ?

1.11 Rezumat

In acest punct am acoperit ceea ce, conventional, poate fi numit esenta lui C. Cu aceste citeva caramizi,este posibil sa scrieti programe utile de marime considerabila dar ar fi o buna idee daca v-ati odihni mai mult inainte de a face asa ceva. Exercitiile care urmeaza au intetia de a va oferi sugestii pentruprograme de o complexitate oarecum mai mare decit cele prezentate in acest capitol.

Dupace reusiti sa aveti sub control aceasta parte a lui C, ar fi demn de efortul dumneavoastra sa cititi mai departe, deoarece caracteristicile lui C acoperite inurmatoarele citeva capitole sint cele in care puterea si expresivitatea limbajului devin aparente.


Exercitiul 1.19. Scrieti un program 'detab' care inlocuieste taburile din intrare cu numarul potrivit de blancuri pentru a sari pina la urmatorul stop de tab. Presupuneti un set fixat de stopuri de tab, fie din n in n pozitii.


Exercitiul 1.20. Scrieti un program 'entab' care inlocuieste siruri de blancuri cu numarul minim de taburisiblancuri pentru a obtine o aceasi spatiere. Folositi aceleasi stopuri de tab ca si detab.


Exercitiul1.21. Scrieti un program pentru a 'impaturi' liniilede intrare lungi dupa ultimul caracterneblanccare apare inainte de a n-a coloana a intrarii,unde nesteun parametru. Asigurati-va ca programul dumneavoastra lucreaza inteligent cu liniile foarte lungi, chiar daca nu e nici un tab sau blanc inainte de coloana specificata.


Exercitiul 1.22. Scrieti un program care sa elimine toate comentariile dintr-un programC.Nu uitati saminuitiadecvat sirurile dintre ghilimele si constantele de caractere.


Exercitiul 1.23. Scrieti un program pentru a verfica un program C din punct de vedere al erorilor de sintaxa rudimentare ca de exemplu: paranteze neperechi. Nu uitati ghilimelele, atit cele simple cit si cele duble si comentariile. (Acest program este greu daca il faceti la cazul cel mai general.)