Capitolul 1.9. Tablouri de caractere.

Vezi subiectul anterior Vezi subiectul urmator In jos

Capitolul 1.9. Tablouri de caractere.

Mesaj  zooky la data de Mier Mar 18, 2009 12:49 am

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

Aceasta schita ne 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 functie getline care 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. ceasta 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 */
{
int len; /* lungimea liniei curente */
int max; /* lungimea maxima gasita pina acum */
char line[MAXLINE]; /* linia curenta introdusa */
char save[MAXLINE]; /* cea mai lunga linie salvata */
max = 0;
while ((len = getline(line, MAXLINE)) > 0)
if (len > max) {
max = len;
copy(line, save);
}
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; {
int c, i;
for(i = 0; i < lim - 1 && (c=getchar())!=EOF && c!='\n';++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i; }
s[i] = '\0';
return(i);
}

copy(s1, s2) /* copiaza pe s1 in s2; s2 suficient de mare */
char s1[], s2[];
{
int i;
i = 0;
while ((s2[i] = s1[i]) != '\0')
++i;
}

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;

care spun ca 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

"hello\n"

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 verifica daca nu s-a produs o depasire. Pe de alta 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 tipareasca toate 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.

Exercitiul 1.17. Scrieti o functie reverse(s) care sa inverseze un sir de caractere s. Folositi-o pentru a scrie un program care isi inverseaza linie cu linie intrarea.
avatar
zooky
Moderator
Moderator

Numarul mesajelor : 147
Data de inscriere : 15/03/2009
Varsta : 24
Localizare : Cernatesti City

Vezi profilul utilizatorului http://e-learning.forumhit.ro

Sus In jos

Vezi subiectul anterior Vezi subiectul urmator Sus


 
Permisiunile acestui forum:
Nu puteti raspunde la subiectele acestui forum