Documente online.
Zona de administrare documente. Fisierele tale
Am uitat parola x Creaza cont nou
 HomeExploreaza
upload
Upload




STRUCTURI, TIPURI UTILIZATOR

c


STRUCTURI, TIPURI UTILIZATOR

Dupa cum am vazut datele de acelasi tip se pot grupa în tablouri. Limbajul C permite gruparea unor date de tipuri diferite sub alte forme de organizare numite structuri.

Tablourile au un tip si anume tipul comun elementelor lor. Astfel, distingem tablouri de tip întreg, de tip caracter, de tip flotant, etc. În cazul structurilor, nu mai avem un tip comun. Fiecare structura reprezinta un nou tip de date, tip care se introduce prin declaratia structurii respective.



Un exemplu simplu de structura este data calendaristica, cu componentele urmatoare:

ziua;

luna;

anul.

unde: ziua si anul sunt date de tip întreg iar luna este un tablou de caractere.

Structura ca si tabloul, este o multine ordonata de elemente. În exemplul de mai sus se considera ca ziua este primul ei element, luna este al doilea iar anul este ultimul ei element. Trebuie sa precizam ca referirea la componentele unei structuri nu se mai face cu ajutorul indicilor ci prin calificare.

8.1. DECLARAŢIA DE STRUCTURĂ

O structura se poate declara în mai multe feluri, astfel:

Formatul 1:

struct nume_structura

;

Cu ajutorul acestui format se introduce un nou tip de data cu numele nume_structura. Lista de declaratii este formata din declaratii obisnuite. Tipul data_calendaristica îl putem introduce astfel:

struct data_calendaristica

;

O astfel de declaratie se numeste declaratie de tip. 828i85i Sa retinem ca unui nou tip de date nu i se aloca memorie, el este doar contabilizat ca un nou tip utilizator pe lânga tipurile predefinite ale limbajului C.

Formatul 2:

struct nume_structura

lista_variabile;

Un astfel de format introduce tipul utilizator nume_structura si declara o lista de varibile în care fiecare element din lista are tipul nume_structura. Prin exemplu urmator se introduc variabilele dc1 si dc2 ca date elementare de tipul data_calendaristica si tabloul dc de 13 componente.

struct data_calendaristica

dc1, dc2, dc[13];

Formatul 3:

struct lista_variabile;

Acest format se foloseste daca nu vrem sa dam nume noului tip structurat si totodata daca nu mai vrem sa-l folosim. Deci nu vom mai pute declara alte date de tipul structurat nou introdus pentru ca tipul nu are nume.

Exemplu:

struct dc1, dc2, dc[13];

S-au declarat varibilele dc1, dc2 si tabloul dc având noul tip structurat utilizator dar nu se mai doreste sa declaram alte date de acest tip.

Observatii:

1o. Daca se foloseste formatul 1 atunci pentru a declara date de tipul utilizator nou introdus se foloseste o constructie de forma:

struct nume_ structura lista_variabile;

Compilatorul aloca memorie varibilelor din lista de variabile, tratând aceasta constructie ca si declaratiile obisnuite.

2o. Componentele unei structuri pot fi ele însele date structurate. O componenta care nu este structurata se numeste componenta elementara.

3o. Ca si în cazul celorlalte tipuri de variabile se pot defini structuri globale, statice sau automatice. Structurile statice se declara precedând declaratiile lor prin cuvântul static, iar cele externe prin cuvântul cheie extern.

4o. Elementele unei date de tip structura pot fi initializate dupa modelul initializarii variabilelor care au tipuri predefinite.

Exemple:

1) Introducem tipul utilizator data_calendaristica astfel:

struct data_calendaristica

;

pentru a initializa o data de tipul data_calendaristica vom scrie:

struct data_calendaristica dc1=;

2) Daca declaram un nou tip date_personale si în care vrem sa folosim tipul data_calendaristica, vom scrie:

struct date_personale

;

8.2. ACCESUL LA ELEMENTELE UNEI STRUCTURI

Pentru a avea acces la componentele unei date structurate va trebui sa folosim o calificare de forma:

nume_data_structurata.nume_componenta

Astfel daca avem tipul structurat data_calendaristica introdus in exemplele anterioare si declaram data dc astfel:

struct data_calendaristica dc;

atunci pentru a ne referi la componentele datei dc vom folosi constructiile:

dc.ziua

dc.anul

dc.luna (atentie este pointer spre caractere)

Daca avem declarat un tablou astfel:

struct data_calendaristica tdc[10];

atunci pentru fiecare componenta i ne vom referi astfel:

tdc[i].ziua

tdc[i].anul

tdc[i].luna (este pointer)

tdc[i].luna[0], tdc[i].luna[1], . . . , tdc[i].luna[11]

Ca si tablourile structurile se pot transfera prin parametrii, transferând un pointer spre data structurata respectiva, adica adresa de început a zonei alocate structurii. Deci, printr-un apel de forma:

functie(&data_structurata);

se transfera functiei functie adresa de început a zonei alocate structurii data_structurata. Daca data_structurata este o structura de tipul tip, atunci antetul functiei functie este urmatorul:

void functie(tip *p)

unde p este pointer spre tipul structurat tip.

Pentru data structurata dc de tipul data_calendaristica antetul functiei functie este:

void functie(struct data_calendaristica *p)

iar apelul pentru data dc se face

functie(&dc);

Printr-un astfel de apel, functia apelata nu are acces la numele datei structurate transferate, ci numai la pointerul spre ea. De aceea se pune problema accesului la componentele datei structurate prin pointerul la ea. În acest caz numele datei structurate se va înlocui prin *p. Deci, în cazul datei structurate dc, transferate ca si mai sus, în locul constructiei

dc.zi

vom scrie:

(*p).zi

înlocuind numele datei structurate dc prin *p, unde p este un pointer spre dc.

Observatie:

1o. Parantezele rotunde din constructia de mai sus sunt obligatorii, deoarece punctul este un operator prioritar operatorului unar *.

2o. Constructia de mai sus poate fi înlocuita prin p->zi care este identica cu ea. Simbolul -> se compune din caracterele '-' si '>' scrise unul dupa celalalt fara spatiu între ele. El se numeste sageata si este considerat a fi un operator cu aceeasi prioritate ca si punctul, deci de prioritate maxima.

8.3. ATRIBUIRI DE NUME PENTRU TIPURI DE DATE

Dupa cum stim tipurile de baza ale limbajului C, numite si tipuri predefinite se identifica printr-un cuvânt cheie (int, char, float, etc). Totodata prin instructiunea struct, programatorul poate sa introduca un tip nou. Programatorul poate sa atribuie un nume unui tip (predefinit sau utilizator) cu ajutorul constructiei:

typedef tip nume_nou_tip;

unde:

tip este numele unui tip predefinit sau al unui tip utilizator (introdus cu struct);

nume_nou_tip este noul nume atribuit tipului respectiv.

Dupa ce s-a atribuit un nou nume unui tip, numele respectiv poate fi utilizat pentru a declara date de acel tip, la fel cum se utilizeaza în declaratii cuvintele cheie int, char, float, etc.

Observatii:

1o. De obicei numele atribuit unui tip se scrie cu litere mari.

2o. Un exemplu de astfel de nume exista în fisierul stdio.h pentru tipul fisier, caruia i s-a atribuit numele FILE.

Exemple:

Fie declaratiile:

typedef int INTREG;

typedef float REAL;

În continuare, denumirile INTREG si REAL se pot folosi la fel ca si cuvintele cheie int si float. Cu alte cuvinte, declaratia:

INTREG i, j, tablou[10];

este identica cu declaratia urmatoare:

int i, j, tablou[10];

Analog:

REAL x, y, z;

este identica cu declaratia:

float x, y, z;

typedef struct data_calendaristica

DC;

Prin aceasta declaratie se atribuie denumirea DC tipului structurat data_calendaristica. În continuare putem declara date de tip DC:

DC data_nasterii, data_angajarii;

DC data_curenta =;

typedef int *PI;

Prin aceasta declaratie se introduce un sinonim pentru tipul pointer spre întregi: int *.

Putem sa declaram în continuare pointeri spre întregi astfel:

PI p;

care este echivalenta cu:

int *p;

4) Declaratia typdef struct

COMPLEX;

introduce numele COMPLEX pentru datele de tip complex.

Functia urmatoare returneaza modulul unui numar complex:

typedef struct

COMPLEX;

#include <math.h>

double modul (COMPLEX *x) // returneaza modulul numarului

// spre care pointeaza x

8.4. UNIUNE

Limbajul C ofera utilizatorului posibilitatea de a folosi aceeasi zona de memorie pentru a pastra date de tipuri diferite în momente diferite ale executiei programului. Astfel, de exemplu, putem utiliza o zona de memorie pentru a pastra la un moment dat o data flotanta, iar ulterior sa reutilizam aceeasi zona pentru o data întreaga sau de tip pointer. Reutilizarile zonelor de memorie conduc la utilizarea mai eficienta a acesteia, uneori putându-se obtine o economie substantiala a spatiului de memorie alocat programului.

O uniune se declara printr-o constructie asemanatoare declaratiei de structura. Deosebirea consta în înlocuirea cuvântului struct prin union:

union nume

Exemplu:

union u

Prin aceasta declaratie s-a definit tipul de date u. În continuare, putem declara date de tipul u printr-o declaratie de forma:

union u u1;

unde u1 este o data de tip u careia i se aloca o zona de memorie care poate fi utilizata pentru a pastra date de tipurile int, float sau double. Deoarece tipul double necesita memoria cea mai mare se aloca 8 octeti. Astfel zona u1 poate pastra pe oricare din celelalte componente ale uniunii dar în momente diferite ale executiei programului.

Accesul la componentele unei uniuni se face la fel ca si în cazul structurilor. Astfel, pentru a ne referi la componenta i a uniunii u1 definita în exemplul anterior folosim constructia:

u1.i

sau daca p este pointer spre tipul u declarat prin

union u *p;

atunci constructia

p -> i

permite accesul la componenta i a uniunii spre care pointeaza p.

Pentru a evita erorile legate de evidenta în fiecare moment a datei care se prelucreaza se ataseaza unei uniuni o data menita sa indice componenta curenta. Aceasta data este specificata pentru fiecare uniune. De exemplu pentru uniunea u1 definita anterior este important sa se stie daca zona de memorie contine un întreg, un flotant în simpla precizie sau un flotant în dubla precizie. Se definesc trei constante simbolice:

#define INTREG 1

#define F_SIMPLU 2

#define F_DUBLU 3

Modificam tipul u atasând data tip_curent de tip int astfel:

struct u

uu;

Declaram structura us astfel:

struct u us;

În acest caz, în momentul în care se pastreaza o data în zona rezervata uniunii, se atribuie componentei tip_curent una din constantele definite anterior:

INTREG, daca se pastreaza un întreg;

F_SIMPLU daca se pastreaza un flotant în simpla precizie;

F_DUBLU daca se pastreaza un flotant în dubla precizie.

Astfel când se foloseste componenta de tip int se va asocia atribuirea:

us.tip_curent=INTREG;

Analog se vor folosi ti atribuirile urmatoare când se vor folosi componentele de tip float sau de tip double:

us.tip_curent=F_SIMPLU;

respectiv:

us.tip_curent=F_DUBLU;

În felul acesta, se poate testa, în fiecare moment, tipul de data prezent în zona rezervata. Aceasta se poate face printr-o secventa de instructiuni if sau prin intermediul instructiunii switch.

if (us.tip_curent = = INTREG) // se foloseste us.uu.i

else if (us.tip_curent = = FSIMPLU) // se foloseste us.uu.f

else if (us.tip_curent = = FDUBLU) // se foloseste us.uu.d

else eroare

sau folosind switch avem o constructie mai clara de forma:

switch (us.tip_curent)

Programul urmator calculeaza ariile pentru urmatoarele figuri geometrice:

cerc;

dreptunghi;

patrat;

triunghi.

Programul citeste datele pentru o figura geometrica, calculeaza aria figurii respective si scrie rezultatul:

La intrare se folosesc urmatoarele formate:

- pentru cerc C raza;

- pentru dreptunghi D lungime latime;

- pentru patrat P latura;

- pentru triunghi T latura latura latura;

- sfârsit fisier    EOF.

În cazul triunghiului, se utilizeaza formula lui HERON pentru calculul ariei:

aria = sqrt (p*(p-a)(p-b)(p-b))

unde p este semiperimetrul, iar a, b, c sunt cele 3 laturi.

#include <stdio.h>

#include <math.h>

#define PI 3.14159265

#define EROARE -1

#define CERC 1

#define PATRAT 2

#define DREPT 3

#define TRIUNGHI 4

typedef struct

fig;

}FIG;

void main (void) // calculeaza arii

zfig.tip = EROARE;

switch(car[0])

zfig.tip = CERC; // se pastreaza tipul figurii

break;

case 'P': // patrat

printf("se cere latura patratului in flotanta\n");

i = scanf("%lf",&zfig.fig.lp);

if( i !=1)

zfig.tip = PATRAT;

break;

case 'D': // dreptunghi

printf("se cer laturile dreptunghiului in flotanta\n");

i = scanf("%lf %lf",&zfig.fig.ld[0],&zfig.fig.ld[1]);

if(i != 2)

zfig.tip = DREPT;

break;

case 'T': // triunghi

printf("se cer laturile triunghiului in flotanta\n");

i = scanf("%lf %lf %lf", &zfig.fig.lt[0], &zfig.fig.lt[1],&zfig.fig.lt[2]);

if(i != 3)

zfig.tip =TRI;

break;

printf("laturile nu formeaza un triunghi\n");

break;

default:

printf("se cere una din literele urmatoare\n");

printf("C pentru cerc\n");

printf("P pentru patrat\n");

printf("D pentru dreptunghi\n");

printf("T pentru triunghi\n");

} // sfarsit switch

switch (zfig.tip)

else

default : // avans pana la newline sau EOF

while ((i = getchar()) != '\n' && i != EOF);

} // sfarsit switch

if (i = = EOF) break;

} // sfarsit for

} // sfarsit main

8.5. CAMP

Limbajul C permite utilizatorului definirea si prelucrarea datelor pe biti. Utilizarea datelor pe biti este legata de folosirea indicatorilor care de obicei sunt date care iau numai doua valori 0 sau 1.

Nu este justificat ca un astfel de indicator sa fie pastrat ca un întreg pe 16 biti si nici macar pe un octet. Indicatorul poate fi pastrat pe un singur bit. În acest scop, limbajul C ofera posibilitatea de a declara date care sa se aloce pe biti (unul sau mai multi biti). Acest lucru îsi gaseste aplicare în programele de sistem. Astfel, de exemplu, atributele variabilelor dintr-o tabela de simboluri pot fi pastrate pe biti, ceea ce conduce la o economisire substantiala a memoriei ocupate de tabela respectiva.

Prin camp întelegem un sir de biti adiacenti continuti într-un cuvânt calculator. Câmpurile se grupeaza formând o structura.

Un câmp se declara ca si o componenta a unei structuri si el are tipul unsigned (întreg fara semn). Totodata în declaratia câmpului se indica si dimensiunea lui în biti.

În general, o structura cu componente câmpuri are forma:

struct

nume;

unde campi (i=1,...,n) are unul din formatele de mai jos:

unsigned nume : lungime_în_biti

sau : lungime_în_biti

Exemplu:

struct

indicatori;

Data indicatori se aloca într-un cuvânt calculator, adica pe 16 biti. Componentele ei sunt:

a un bit;

b un bit;

c doi biti;

d doi biti;

e trei biti.

La câmpuri ne putem referi la fel ca si la componentele oricarei structuri. Deci la indicatorii de mai sus ne putem referi prin urmatoarele constructii:

indicatori.a

indicatori.b

indicatori.c

indicatori.d

indicatori.e

Alocarea bitilor este dependenta de calculator. De obicei bitii se aloca de la dreapta spre stânga ca în figura de mai jos:

a

b

c

d

e

Observatii:

1o. Daca un câmp nu poate fi alocat în limitele unui cuvânt, el se aloca în întregime în cuvântul urmator.

2o. Nici un câmp nu poate avea o dimensiune mai mare decât 16 biti.

3o. Formatul fara nume (al doilea format) pentru câmp se foloseste pentru cadraje. Acest lucru este util atunci când sunt zone de biti neutilizate în cadrul unui cuvânt. De asemenea, utilizarea formatului cu lungime egala cu zero permite ca alocarea câmpurilor urmatoare lui sa se faca în cuvântul urmator.

4o. O structura care are si componente câmpuri poate avea si componente obisnuite.

5o. Nu se pot defini tablouri de câmpuri.

6o. Unui câmp nu i se poate aplica operatorul adresa.

Câmpurile se utilizeaza frecvent la scrierea unor programe de sistem, cum ar fi : drivere pentru periferice, compilatoare, etc.

Utilizarea câmpurilor poate conduce la programe cu o portabilitate redusa. Totodata, accesul la date pe biti conduce la cresterea numarului de operatii, fiind necesare deplasari si operatii pe biti suplimentare, fapt ce poate conduce atât la cresterea timpului de executie a programelor, cât si la cresterea memoriei utilizate. Ori datele pe biti se folosesc chiar în ideea de a economisi memorie.

8.6. TIPUL ENUMERAT

Tipul enumerat permite utilizatorului sa foloseasca în program nume sugestive în locul unor valori numerice. De exemplu, în locul numarului unei luni calendaristice, se poate folosi denumirea ei:

ian

feb

mar

În locul valorilor 0 si 1 se pot folosi cuvintele FALS si ADEV RAT.

Prin aceasta, se introduce o mai mare claritate în programe, deoarece valorile numerice sunt înlocuite prin diferite sensuri atribuite lor.

Un tip enumerat se introduce printr-o declaratie de forma:

enum nume ;

Prin aceasta declaratie se defineste tipul enumerat nume, iar numei are valoarea i. O forma mai generala a declaratiei de mai sus permite programatorului sa forteze valorile numelor din acolada. În acest scop, se pot folosi constructii de forma:

numei= eci

unde eci este o expresie constanta de tip int.

Cu alte cuvinte, unui nume i se poate atribui o valoare sau valoarea lui coincide cu a numelui precedent marita cu 1. Daca primului nume din acolada nu i se atribuie o valoare, el are valoarea 0. Numele nume0, nume1,. . . , numen trebuie sa fie nume diferite. Ele sunt constante si valoarea lor se stabileste prin declaratia în care au fost scrise. Domeniul lor de valabilitate este definit de domeniul de valabilitate al declaratiei prin care se definesc:

instructiunea compusa care contine declaratia;

fisierul sursa în care este scrisa declaratia, daca este externa oricarei functii.

Valorile atribuite lui nume0, nume1, . . . , numen sunt de obicei diferite, dar unele pot sa si coincida.

Dupa ce s-a introdus un tip enumerat, se pot declara date de tipul respectiv printr-o declaratie de forma:

enum nume lista_de_variabile;

Datele de tip enumerat se considera de tip int si se pot utiliza în program oriunde este legal sa apara o data de tip int.

Observatii:

1o. Se pot utiliza, ca si în cazul structurilor, constructii de forma:

enum nume lista_de_variabile;

sau

enum lista_de_variabile;

2o. De asemenea, se poate utiliza constructia typedef pentru a atribui un nume unui tip enumerat:

typedef enum nume NUME;

În continuare se pot declara date de tipul NUME, astfel:

NUME lista_de_variabile;

Exemple:

enum luna;

enum luna luna_calendaristica

Prin prima declaratie se introduce tipul enumerat luna. Multimea de valori asociate acestui tip este formata din numerele întregi 1,2, . . . , 12. Se pot utiliza denumirile:

ian ia valoarea 1

feb ia valoarea 2

dec ia valoarea 12

A doua constructie declara data luna_calendaristica de tipul luna. Ei i se pot atribui valori prin expresii de atribuire de forma:

luna_calendaristica = mar sau

luna_calendaristica = mai + 4

typedef enum ZI;

ZI z;

Variabila z este de tip ZI. Se poate utiliza în expresii de forma:

z=marti;

if(z<sambata) // trateaza ziua de lucru

else // trateaza zi de odihna



Document Info


Accesari: 1167
Apreciat: hand-up

Comenteaza documentul:

Nu esti inregistrat
Trebuie sa fii utilizator inregistrat pentru a putea comenta


Creaza cont nou

A fost util?

Daca documentul a fost util si crezi ca merita
sa adaugi un link catre el la tine in site


in pagina web a site-ului tau.




eCoduri.com - coduri postale, contabile, CAEN sau bancare

Politica de confidentialitate | Termenii si conditii de utilizare




Copyright © Contact (SCRIGROUP Int. 2024 )