Tipuri de date standard
14.3.1. Tipuri de baza.
Tipurile de baza admise de limbajul C sunt urmatoarele:
- Date de tip text, caractere simple sau siruri de caractere, tip desemnat prin cuvāntul cheie char;
- Date de tip numeric īntreg, pentru care se folosesc cuvintele cheie int, short si long;
- Date de tip real (īn virgula mobila), desemnate prin cuvintele cheie float, double si long double;
- Date de tip enumerativ, desemnate prin cuvāntul cheie enum;
- Pointeri, sau date care contin ca informatii adresa catre locatiile de memorie care contin data propriu-zisa. Deoarece datele referite au propriul lor tip, pointerii sunt desemnati printr-o prefixare cu caracterul * a notatiei entita 343d37d 55;ii pointer, prefixul * si notatia pointerului urmānd unui cuvānt cheie care desemneaza tipul, ca mai jos:
tip * nume_pointer
si se citeste "nume_pointer punctānd catre tip
- Tipul void care, dupa caz, daca se refera la functii are semnificatia de numic, iar daca se refera la pointeri are semnificatia de orice.
14.3.2. Modificatori de tipuri.
Modificatorul de tip este un element atasat tipurilor aritmetice īntregi, referindu-se la reprezentarea cu sau fara semn.
Astfel, tipul signed (care, de altfel, este implicit) se refera la reprezentari cu semn, iar tipul unsigned se refera la reprezentari fara semn (numere pozitive).
Pot fi folosite abreviatiile din tabelul 14.2.
Tabelul 14.2.
Tip |
Abreviatie |
signed char |
char |
signed int |
signed, int |
signed short int |
signed short, short |
signed long int |
signed long, long |
unsigned char |
fara abreviatie |
unsigned int |
unsigned |
unsigned short int |
unsigned short |
unsigned long int |
unsigned long |
14.3.2. Stocare īn memorie si domenii de valori.
Īn tabelul 14.3 sunt redate numerele de octeti necesare stocarii īn memorie si domeniile de valori reprezentabile pentru tipurile de baza.
Tabelul 14.3.
Tip |
Stocare |
Domeniu de valori |
char | ||
int | ||
short | ||
long | ||
unsigned char | ||
unsigfned int | ||
unsigned short | ||
unsigned long | ||
float |
3.4E-38...3.4E+38 |
|
double |
1.7E-308...1.7E+308 |
|
long double |
3.4E-4932...1.1E+4932 |
14.3.4. Tipul enumeratie.
Tipul enumeratie este un tip īntreg special, care permite unei variabile enumerative sa ia valori īntr-0 multime finita de numere īntregi numite constante enumerative. Pot exista urmatoarele variante de definire:
enum nume_tip_enumerare
unde: este o lista de forma:
iar: definire_constanta_enumerativa_i are forma:
constanta_enumerativa_i [=valoare_atribuita_explicit]
Astfel, se poate defini:
enum meniu ;
caz īn care valorile atribuite de catre compilator sunt: aperitiv=0, supa=1, pilaf=2, placinta=3.
Daca se doreste sa se excluda aperitiv din meniu, dar sa se pastreze aceleasi numere, trebuie sa se defineasca:
enum meniu ;
Observatie: valorile constantelor enumerative nu mai pot fi schimbate.
O data tipul definit, se pot defini variabilele enumerative īn maniera:
enum nume_tip_enumerare variabila_enumerativa
ca de exemplu:
enum meniu fel_de_mancare
Aceasta definitie stabileste numai faptul ca fel_de_mancare este de tipul meniu, adica poate lua ca valori numai valorile definite īn multimea enumerativa.
Ulterior se poate scrie:
fel_de_mancare=pilaf;
ceea ce va produce atribuirea valorii īntregi 2 variabilei fel_de_mancare
14.3.5. Tipul structura.
Structura defineste un stoc de date care pot fi de diferite tipuri. Sintaxa definitiei structurii foloseste cuvāntul cheie struct si poate avea una dintre formele:
struct nume_tip_structura [structura_1,...,structura_k];
struct nume_tip_structura structura_1 [,...,structura_k];
struct structura_1 [,...,structura_k];
Īn lista membrilor structurii nu pot intra constante cu atribuire initiala, dar membrii structurii pot fi de orice tip, inclusiv structuri. Astfel, se poate defini, de exemplu:
struct punct2D punctA;
struct triunghi ABC;
struct cerc cerc_1;
Referirea unui membru al structurii se face prin notatia structura.membru, ca de exemplu:
punctA.x=2.5;
punctA.y=3.0;
cerc_1.centru=punctA;
cerc_1.raza=5;
Desi membrii structurilor nu pot fi initializati, structurile pot fi initializate dupa ce au fost definite ca tip.
Astfel, se poate scrie, de exemplu:
struct punct2D r, s, t;
struct triunghi ;
Daca referirea structurii se face indirect, ca pointer, notatia (*structura).membru se poate scrie prescurtat pstructura->membru, unde pstructura este un pointer de tip structura catre un tip. De exemplu:
#include <conio.h>
#include <stdio.h>
struct punct2D ;
void oglinda_oy(punct2D *pct)
void main()
printf("Punctul original A are x=%f si y=%f\n", A.x, A.y);
oglinda_oy(&A);
printf("Punctul oglindit A' are x=%f si y=%f\n", A.x, A.y);
getch();
Ca urmare a rularii programul afiseaza:
Punctul original A are x=5.000000 si y=3.000000
Punctul oglindit A' are x=5.000000 si y=3.000000
Modul de folosire a adresarii indirecte se observa din definitia functiei oglinda_oy.
14.3.6. Tipul uniune.
Cuvāntul cheie care desemneaza acest tip este union.
Din punct de vedere formal tipul uniune apare scris la fel ca tipul structura. Deosebirea este ca, īn timp ce tipul structura aloca spatiul de memorie pentru fiecare membru al structurii, tipul uniune aloca un singur spatiu de memorie avānd lungimea egala cu lungimea celui mai lung tip de membru al uniunii. Astfel, tipul:
union orice_tip (char c; int i; float f; double d;) tip_data
va permite salvarea īn variabila tip_data a unei informatii de oricare tip dintre cele patru tipuri membre ale uniunii orice_tip
Referirea unui membru al uniunii se face, ca si īn cazul structurilor prin operatorul punct (.) sub forma uniune. membru
Orice data este stocata īn variabila uniune īncepand de la prima locatie de memorie rezervata uniunii si este returnata conform tipului referit. Astfel, īn exemplul urmator:
#include <conio.h>
#include <stdio.h>
union tip_dublu ddata;
void main()
rezultatul rularii va fi afisarea:
ddata.f=123456000.000000
ddata.i=31040
ceea ce este corect pentru tipul float dar este gresit pentru tipul int. Aceasta se datoreaza faptului ca citirea din memorie are loc numai pentru a parte a octetilor stocati īn uniune, conform tipului īntreg.
Aceasta este o posibila sursa de erori si nu poate fi evitata decāt prin grija stricta a programatorului de a tine cont de ultimul tip stocat īn uniune.
14.3.7. Date nemodificabile. Declaratia const.
Pentru a preveni modificarea din greseala programatorului a valorilor anumitor date care trebuie sa fie nemodificabile, se foloseste declaratia const, īn forma:
const tip_de_data initializare_data
De axemplu:
const float pi=3.141593;
are ca efect imposibilitatea de a mai schimba valoarea variabilei pi. Īn acest caz atribuirea: pi=2.5;
va produce la compilare un mesaj de eroare care, īn functie de compilatorul folosit, ar putea fi de forma:
Error...: Cannot modify a const object
Observatie: acelasi efect īl are si directiva preprocesor #define, dar mesajul de eroare este diferit.
14.3.8. Declaratia typedef.
Aceasta declaratie are forma:
typedef tip declaratie
si are rolul de a crea denumiri sinonime pentru tipuri. De exemplu:
typedef int intreg; /* creaza un sinonim pentru tipul int */
typedef struct punct3D p3D; /* face ca punct3D si p3D sa fie utilizate cu acelasi rol */
14.4. Conversii de tipuri de date.
14.4.1. Conversia automata de tip.
Acest mod de conversie este realizat automat de catre compilator la generarea codului executabil, ori de cāte ori īntr-o operatie apar tipuri de date diferite. De exemplu, pentru a face operatia:
rezultat_tip=valoare_int_1*valoare_float_2;
compilatorul constata ca īn partea dreapta tipul cel mai lung este float si face o copie a lui valoare_int_1 īntr-o zona temporara de memorie de lungime sizeof(float), convertind acolo valoarea de tip int la valoare de tip float.
Apoi executa operatia si, la pasul urmator, determina lungimea rezultatului operatiei, adica sizeof(float) si lungimea variabilei rezultat_tip convertind valoarea rezultatului operatiei la tipul variabilei rezultat_tip
Daca lungimea lui rezultat_tip este cel putin egala cu lungimea rezultatului operatiei, conversia se face fara erori.
Exista o ierarhie a conversiei de la cea mai īnalta la cea mai scazuta, īn ordinea:
double float long int short
Daca conversia se face de la un nivel inferior la unul superior ea rezulta corecta. Daca conversia se face de la un nivel superior la unul inferior, ea poate rezulta eronata daca marimea numarului rezultat depaseste capacitatea de reprezentare a tipului destinatie.
Īn exemplul anterior, daca rezultat_tip este de tip int iar rezultatul operatiei este mai mic decāt 32767, numarul va fi convertit corect, altfel va fi convertit eronat.
14.4.2. Conversia explicita de tip. Operatorul cast.
Fie urmatoarea secventa de instructiuni:
val_float_1=3.0;
val_int_2=4;
val_int_3=5;
rezultat_float=val_float_1+val_int_2/val_int_3;
Operatia val_int_2/val_int_3, avānd doi operanzi de acelasi tip (īntreg), va avea rezultatul de tip int si acesta, prin rotunjire, va fi egal cu zero. Ca urmare rezultat_float va capata valoarea 3.0.
Daca cel putin unul dintre operanzii val_int_2 si val_int_3 ar fi fost de tip float, īnpartirea lor ar fi fost convertibila la tipul float (cel mai lung dintre tipurile float si int) si ar fi rezultat 0.8, iar rezultatul final ar fi fost cel corect, adica 3.8.
Deci, cānd din diferite motive legate de scrierea programului, nu este posibila schimbarea tipului initial al datelor, se poate face uz de conversia explicita de tip folosind operatorul cast. Acesta are forma:
(tip)
si prefixeaza variabila a carei conversie trebuie realizata.
Īn consecinta, pentru operatia descrisa mai sus, se poate scrie una dintre variantele:
rezultat_float=val_float_1+(float)val_int_2/val_int_3;
rezultat_float=val_float_1+val_int_2/(float)val_int_3;
rezultat_float=val_float_1+(float)val_int_2/(float)val_int_3;
ceea ce asigura, cel putin pentru unul dintre operanzii val_int_2 si val_int_3 (sau, respectiv, pentru ambii) conversia īn timpul operatiei la tipul specificat de operatorul cast si, īn consecinta, producerea unui rezultat corect.
14.5. Instructiuni.
Executia unui program scris īn limbajul C este controlata prin instructiuni.
Instructiunile pot fi: instructiuni simple, care vor fi trecute īn revista īn acest capitol, sau instructiuni compuse, formate din alte instructiuni.
Instructiunile simple se termina cu caracterul ";" iar instructiunile compuse sunt cuprinse īntre acolade si se mai numesc si blocuri.
Pot fi folosite si instructiuni vide care apar sub forma caracterului ";".
Orice instructiune poate fi precedata de o eticheta formata dintr-un nume urmat de caracterul :, sub forma:
nume_eticheta:
Eticheta nu este utila decāt īn cazul folosirii instructiunii goto sau switch.
14.5.1. Instructiunea expresie.
O expresie apare sub forma generala:
expresie;
Ca exemple de expresii se pot cita:
- expresii de atribuire. De exemplu:
x=a+b;
unde variabilei x i se atribuie suma variabilelor a si b.
- expresii cu efect lateral. De exemplu:
i++
unde i capata valoarea i+1, sau
f(x)
unde este apelata functia f cu parametrul x. Aici se pot distinge cazurile:
a. O variabila globala īsi modifica valoarea īn corpul functiei f si, īn consecinta, dupa apelul functiei f, programul va "vedea" aceasta valoare modificata. Acelasi lucru se īntāmpla si daca x nu este variabila globala dar este o adresa de variabila, ca īn cazul apelului functiei f(&x);. Acesta este cazul functiilor cu efect lateral
b. functia f executa o anumita actiune (de exemplu, tipareste pe ecran sau la imprimanta valoarea lui x) fara sa aiba un alt efect;
c. functia f returneaza un rezultat. Cum īnsa nu exista nici o atribuire de forma y= f(x); rezultatul se pierde si, īn acest caz, nu exista nici un efect.
14.5.2. Instructiunea de decizie.
Forma generala a instructiunii de decizie este:
if (conditie) instructiune_1 [else instructiune_2]
Instructiunile conditionate instructiune_1 si instructiune_2 pot fi instructiuni simple sau compuse (blocuri), caz īn care ele trebuie sa fie īncadrate de acolade. Alternativa else poate lipsi.
Actiunea instructiunii if este de a evalua mai īntāi instructiunea conditie si, daca aceasta este adevarata (diferita de zero), de a executa instructiune_1 sau, īn caz contrar, de a executa instructiune_2. De exemplu:
if(a<=0) absa=-a; else absa=a;
Instructiunile if-else pot fi īncuibate una īn alta. Īn acest caz alternativa else se refera la ultima conditionare if care nu are alternativa else. De exemplu:
if(a<b) /* primul if */
if(c<a) minabc=c; /* al doilea if */
else minabc=a; /* primul else */
else /* al doilea else */
if(c<b) minabc=c; /* al treilea if */
else minabc=b; /* al treilea else */
Se observa din acest exemplu ca al doilea else se refera la primuil if, iar al treilea else se refera la al treilea if.
Pentru īncuibari mai complicate este indicat sa se foloseasca acoladele pentru delimitarea blocurilor dorite fara echivoc, pentru a evita erorile de scriere a schemelor decizionale.
14.5.3. Instructiunea de selectie.
Instructiunea de selectie are forma genarala:
switch (expresie_selectoare)
unde: expresie_selectoare trebuie sa produca un rezultat de tip īntreg;
etichetele i1,...,in trebuie sa fie constante sau expresii cu valoare constanta de tip īntreg si trebuie sa aiba valori distincte;
secventele pot fi secvente de instructiuni sau pot fi vide;
eticheta default: si secventa_d asociata ei sunt optionale.
Actiunea de executie selectiva se desfasoara astfel:
1. Se evalueaza expresie_selectoare;
2. Se cauta aceea dintre expresiile i1,...,in care are valoarea egala cu rezultatul evaluarii lui expresie_selectoare. Daca o astfel de expresie este īntālnita, se vor executa toate secventele de instructiuni din corpul instructiunii switch pāna la eticheta default sau pāna la primul break īntālnit.
Daca nici una dintre expresiile i1,...,in nu are valoare egala cu rezultatul dat de expresie_selectoare, este executata secventa de instructiuni asociata etichetei default, daca aceasta exista.
Īntālnirea unei instructiuni break transfera controlul executiei la prima instructiune care urmeaza instructiunii switch.
De exemplu:
switch(i)
rezultatul produs fiind y=1 pentru i=1, 2 sau 3, y=2 pentru i=4, si y=0 pentru oricare alta valoare a lui i. Sau:
switch (i)
Īn acest caz rezultatele sunt: pentru i=1 se obtine y=y+3, pentru i=2 se obtine y=y+2, iar pentru i=3 se obtine y=y+1. Pentru oricare alta valoare a lui i, y ramāne neschimbat.
|