>> Inapoi <<

========
Capitolul 5
========

==================
Procesarea caracterelor
==================


---------------------------
Tipul de data "char"
---------------------------

Este unul dintre tipurile fundamentale din limbajul C. Constantele si 
variabilele de acest tip sunt folosite pentru reprezentarea caracterelor. 
Fiecare caracter este memorat pe 1 byte (octet), care (in general) este 
compus din 8 biti. Un octet compus din 8 biti poate pastra 2^8=256 valori 
distincte.

Cand memoram un caracter intr-un octet, continutul acestuia poate fi gandit ca
un caracter sau un intreg mic (intre 0 si 255). Desi putem memora 256 valori 
distincte, doar o parte din ele sunt tiparibile (litere mici, mari, cifre, 
semne de punctuatie, spatiu, tab, caractere speciale +, *, %). Exemple de 
caractere netiparibile: newline, bell.

O constanta caracter se scrie intre apostroafe, cum ar fi: 'a', 'b'. O 
declaratie obisnuita a unei variabile de tip caracter este:

                char c;
                
Variabilele caracter se pot initializa astfel:

         char c1 = 'A', c2 = '*';
         
Un caracter este pastrat in memorie pe un octet dupa o codificare specifica. 
Multe masini folosesc codurile de caractere ASCII sau EBCDIC. Ne vom referi 
numai la codul ASCII. Astfel, vom preciza constanta caracter si valoarea 
corespunzatoare a sa:

        de la 2^5+2^4 pana la 57, in ordine: '0', '1', ..., '9'
        de la 2^6+2^0 pana la 90, in ordine: 'A', 'B', ..., 'Z'
        de la 2^6+2^5+2^0 pana la 112, in ordine: 'a', 'b', ..., 'z'
        
De exemplu, se observa ca pentru a obtine litere mici din cele mari, schimbam 
doar un bit. Astfel, caracterul 'A' are codul 65 care inseamna numarul 01000001
in baza 2, iar caracterul 'a' are codul 01100001. Se observa ca difera doar 
bitul cu numarul 3. 

-----------
Exemple:
-----------
In functiile "printf()" si "scanf()", pentru formatul caracter se foloseste %c.

        printf("%c", 'a');                va tipari a
        printf("%c%c%c", 'A', 'B', 'C');  va tipari ABC
        printf("%d", 'a');                va tipari 97
        printf("%c", 97);                 va tipari a
       
        
Anumite caractere netiparibile necesita "secvente escape" (\ reprezinta 
caracterul escape). In acest sens, dam un tabel 

   Numele caracterului    Modul de scriere    Valoarea intreaga
        alert                  \a                          7
        backslash              \\                         92
        backspace              \b                          8
        carriage return        \r                         13
        ghilimea               \"                         34
        formfeed               \f                         12
        tab orizontal          \t                          9
        newline                \n                         10
        caracterul nul         \0                          0
        apostrof               \'                         39
        tab vertical           \v                         11
         
-----------
Exemple: Ce va fi afisat in cazul urmatoarelor instructiuni ?
-----------

1.      printf("\"ABC\"");
2.      printf("'ABC'");

Un alt mod de a scrie o constanta caracter este folosind una, doua sau trei 
cifre octale ca secvente escape, cum ar fi '\007'. Acest '\007' este de fapt 
caracterul "alert" (sau clopotel). El mai poate fi scris '\07' sau '\7' sau 
\a.


---------------------------------------------------
Utilizarea lui "getchar()" si "putchar()"
---------------------------------------------------
Aceste functii sunt folosite pentru citirea si scrierea caracterelor si sunt 
definite in . Astfel pentru citirea unui caracter de la tastatura se 
foloseste "getchar()", iar pentru scrierea unui caracter pe ecran "putchar()".

Bineinteles ca daca dorim sa afisam un sir de caractere mai mare, este mai 
elegant cu functia "printf()". 

-----------
Exemplu:
-----------
Urmatorul program citeste un caracter din intrare (tastatura) si il atribuie 
unei varibile de tip char, apoi il afiseaza pe ecran.

#include 

main()
 {
  char c;

  while (1)
   {
    c=getchar();
    putchar(c);
   } 
 }
 
Singurul mod de a opri acest program este sa apasam CTRL^C. Putem reface 
acest program folosind constanta EOF.

#include 

main()
 {
  int c;
  
  while ((c = getchar()) != EOF) 
   {
    putchar(c);
   }
 }
 
--------------
Comentarii:
--------------
1. In biblioteca , exista o linie in care se declara

                #define EOF (-1)
                
Denumirea lui EOF provine de la "end-of-file".

2. Variabila c trebuie sa fie declarata de tip int si nu de tip char. Am vazut
ca sfarsitul unui fisier este codificat cu -1, si nu cu un caracter. 

3. Subexpresia 

                c=getchar()

citeste o valoare de la tastatura si o asigneaza variabilei c. 


--------------------------
Biblioteca 
--------------------------
Sistemul C pune la dispozitie fisierul header  care contine o multime
de macro-uri (definitii) folosite pentru testarea caracterelor si o multime de
prototipuri de functii ce sunt folosite pentru conversia caracterelor. 

In tabelul de mai jos prezentam o lista de macro-uri folosite la testarea 
caracterelor. Aceste macro-uri iau ca argument o variabila de tip int si 
returneaza o valoare de tip int (zero=false, diferit de zero=true).

-------------------------------------------------------------------
|      Macro    |    Se returneaza true (diferit de zero) daca    |
-------------------------------------------------------------------
   isalpha(c)                    c este litera
   isupper(c)                c este litera majuscula
   islower(c)                  c este litera mica
   isdigit(c)                    c este cifra
   isalnum(c)                c este litera sau cifra
  isxdigit(c)               c este cifra hexazecimala
   isspace(c)                 c este caracter spatiu
   ispunct(c)               c este semn de punctuatie
   isprint(c)               c este caracter tiparibil
   isgraph(c)         c este tiparibil, dar diferit de spatiu
   iscntrl(c)               c este caracter de control          
   isascii(c)                   c este cod ASCII    
-------------------------------------------------------------------

In tabelul urmator, vom scrie functiile "toupper()" si "tolower()", care sunt 
din biblioteca standard si macro-ul "toascii()". Macro-ul si prototipurile 
pentru cele doua functii sunt in . Acestea au ca argument o variabila
de tip int si returneaza tipul int.

   toupper(c)         schimba c din litera mica in majuscula
   tolower(c)         schimba c din majuscula in litera mica
   toascii(c)         schimba c cu codul ASCII


----------------
Un exemplu util: Numararea cuvintelor
---------------- 
  
Vrem sa numaram cate cuvinte sunt introduse de la tastatura. Ele sunt separate
prin spatiu. Pentru scrierea programului vom utiliza tot strategia "top-down".

#include 
#include 

main()
 {
  int numar_cuvinte = 0;
  int gaseste_urmatorul_cuvant(void);
  
  while (gaseste_urmatorul_cuvant() == 1)
    ++ numar_cuvinte;
  printf("Numarul de cuvinte = %d\n\n", numar_cuvinte);  
 }
 
int gaseste_urmatorul_cuvant(void)
 {
  int c;
  
  while (isspace(c = getchar()))
    ;                             /* sarim peste spatii */      
  if (c != EOF)
   {
    while ((c = getchar()) != EOF && !isspace(c))
      ;              /* sarim peste orice diferit de EOF si spatii */
    if (c != EOF) return 1;  
    else return 0;
   }
  return 0; 
 } 


-----------------------------------------------
Exercitii propuse spre implementare
-----------------------------------------------

1. Folosind functiile "getchar()" si "putchar()", sa se scrie un program C care
transforma literele mici in litere mari. Incercati si o varianta de program 
care foloseste functiile "islower()" si "toupper()". 

2. Utilizand functiile "getchar()" si "putchar()" creati un program C care sa 
copie un fisier in alt fisier (comanda voastra proprie de copiere). Utilizati 
redirectarea ! De asemeni, precizati si cazul cand dorim sa copiem un fisier la
sfarsitul unui fisier existent. 

3. Scrieti in C un analizor lexical care sa recunoasca cat mai multi atomi 
lexicali din C. De exemplu, cuvintele rezervate (while, do, for, ...), 
identificatori, operatori (relationali, logici, artimetici, ...) si eventual 
alte structuri. Apoi, tipariti acelasi fisier de intrare cu exceptia spatiilor
multiple si a comentariilor. 

4. Scrieti un program C care citeste caractere de la tastatura si le scrie la 
ecran. Scrieti toate vocalele cu litere majuscule si consoanele cu litere mici.
Apoi, scrieti un program C care citeste caractere de la tastatura si sterge 
vocalele din ele (afisand doar consoanele). (Acest mod de scriere era folosit 
in scrisul hieroglific al Greciei Antice).

5. ("Pretty printing") 
   Scrieti un program C care are la intrare un fisier sursa C si il transforma
intr-un program C scris frumos (eventual in stilul Bell Laboratoires).