Utilitate:
Exemplul 2. Un punct in spatiu
struct punct{
float x, y;
float z;
} a; // s-a declarat tipul structurat si
// o variabila structurata (a)
struct punct b, tetraedru[4]; //s-a declarat
o variabila structurata
//si un tablou de structuri
double dx,dy;
//...
a.x = a.y = a.z = 0.;
b.x = a.x + dx;
b.y = a.y + dy;
b.z = 1;
printf("\nIntroduceti coordonatele varfurilor
tetraedrului");
for(i=0;i<8;i++) scanf("%f%f%f",
&tetraedru[i].x, &tetraedru[i].y, &tetraedru[i].z);
Exemplul 3. Student, an de studiu
struct {
char nume[20];
unsigned an_admis;
float medii[5];
} Vasile, an5[30];
int i,j, nstud;
// ...
gets(Vasile.nume);
Vasile.nume[0] = toupper (Vasile.nume[0]);
scanf("%u", &Vasile.an_admis);
// ... anul V ...
// preluarea mediilor anilor precedenti
for ( i=0; i<nstud; i++ ) {
printf("\nMediile studentului
%s\n", an5[i].nume);
for(j=0;j<5;j++) {
printf("Media anului %d =",j+1);
scanf("%f", &an5[i].medii[j]);
}
}
// ...
Sintaxa declaratiilor de structuri
<declaratie_structura> ::= <specificator_structura> <lista_var>
;
<specificator_structura> ::= struct <nume_structura> |
struct <nume_structura> { <declaratii_membri> } |
struct { <declaratii_membri> }
<declaratii_membri> ::= <specificator_tip> <lista_var>;
<specificator_tip> ::= <specif_tip_simplu> | <decl_tablou>
| <specificator_structura>
Referirea membrilor unei structuri
Atunci cand se utilizeaza numele variabilei structurate se foloseste
operatorul '.' (punct).
Prioritatea si asociativitatea acestui operator este la fel cu cea
a parantezelor.
Membrii unei structuri pot fi variabile simple, pointeri, tablouri,
sau chiar structuri. Utilizarea lui typedef este
permisa .
Exemplul 4. Un segment de dreapta in plan este reprezentat printr-o structura ce are ca membri 2 puncte (extremitatile). Fiecare punct este reprezentat printr-o structura ce are ca membri coordonatele in plan.
struct Punct2D {
int x;
int y;
};
typedef struct Punct2D PUNCT;
typedef struct {
PUNCT a;
PUNCT b;
} SEGMENT;
SEGMENT om;
// segmentul OM cu capetele in (0,0) si (1,2)
om.a.x = om.a.y = 0; //observati utilizarea
repetata a operatorului .
om.b.x =1;
om.b.y =2;
}
Datorita asociativitatii de la stanga spre dreapta a operatorului de
referentiere . expresia om.a.x este
echivalenta cu (om.a).x Continuand exemplul,
putem lua in considerare o structura ce reprezinta un triunghi prin coordonatele
celor trei varfuri:
typedef struct Triung { PUNCT a,b,c; } TRIUNG;
Dar un triunghi ar putea fi reprezentat si printr-un segment si un punct exterior segmentului:
typedef struct Triung {
SEGMENT lat;
PUNCT c;
} TRIUNGHI;
TRIUNGHI trng;
Referirea coordonatelor celor trei varfuri se face astfel:
trng.lat.a.x = 0; trng.lat.a.y = 1; //observati
diferenta in
trng.lat.b.x = 2; trng.lat.b.y =3; //referirea
extremitatilor
trng.c.x = -1; trng.c.y = -2; //segmentului
si varful extern
Observatii.
1. Expresia trng.lat.a.x este echivalenta
cu ((trng.lat).a).x datorita asociativitatii
operatorului de referentiere.
2. Spatiile identificatorilor pentru numele structurilor, membrii structurilor
si numele de tipuri date prin typedef sunt diferite. Declaratii
ca cea de mai jos sunt corecte:
Variabilele structurate pot fi initializate explicit intr-un mod similar cu initializarea tablourilor (se pune semnul egal urmat de o lista de valori cuprinse intre acolade).
Exemplu 5. Initializare numere complexe
Se creeaza un fisier exstru4.h avand
urmatorul continut:
Exemplu 6. Initializare cu constante sir
struct Persoana {
char *nume;
char *adresa;
unsigned varsta;
} x, v = { "Vasilescu V.", "Suceava, str.Universitatii
nr.1", 46};
struct Persoana ={0}; // toate campurile sunt initializate cu 0
Observatie. Pentru initializarea variabilei x in afara declaratiei trebuie alocata dinamic memorie pentru campurile nume si adresa, sau atribuiri ca cele de mai jos:
x.nume = "Vasilescu Ion"; // se atribuie pointeri
x.adresa = Vasile.adresa; // idem
Sunt gresite insa incercarile de citire de genul gets(x.nume); sau scanf("%s", x.nume); deoarece in campurile respective se pot memora adrese de siruri (pointeri la caracter) si nu siruri.
Aplicatie. Program de calcul al procentajului de promovati la un examen, in cadrul unei grupe de maxim 30 studenti. Pentru fiecare student tn parte se va introduce numele (maxim 50 caractere) si nota obtinuta la examen. Un student este reprezentat printr-un element al unui tablou de structuri care retine un pointer la caracter (indica adresa din memorie unde s-a stocat numele studentului) si un intreg (nota).
// Program Exstruc2.c
// Citire date si calcul procentaj promovati
// PSG/23/03/2000
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "D:/C/cit_int.c"
#define NSTUD 30
typedef struct STUDENT {
char *nume;
unsigned char nota; //
notele sunt de la 1 la 10
} STUDENT;
void main ()
{
STUDENT gr1111[NSTUD];
int CitesteDateGrupa ( STUDENT []);
int Integralisti (STUDENT gr[], int
nstud);
int nstud = CitesteDateGrupa( gr1111);
printf("\nPromovati %.2f%%",
(double)Integralisti ( gr1111, nstud
)/nstud*100.);
// ... alte prelucrari
// La sfarsit se elibereaza memoria
ocupata cu numele studentilor
//
for( ; nstud; nstud--) free( gr1111[nstud].nume
);
}
#define NCAR 51
#define STERGE_NL(x) if(x[strlen(x)-1]=='\n')
x[strlen(x)-1]=0;
int CitesteDateGrupa ( STUDENT grupa[])
{
int i=0;
char buf[NCAR];
printf("\nIntroduceti numele si nota.
Cand ati terminat"
" dati <CR> la 'Nume student'.\n");
do {
printf("Nume student:");
flushall(); //curata buffer intrare de '\n' lasat de scanf
fgets(buf, NCAR, stdin); //dupa flushall citirea are loc
STERGE_NL( buf ); //direct din Intrare si nu din buffer
if(buf[0]==0) return i;
grupa[i].nume = malloc ( strlen(buf) + 1 );
printf("Nota=");
scanf("%d",&grupa[i].nota);
} while (++i<NSTUD);
return i;
}
//------------------------------------------------------
int Integralisti (STUDENT gr[], int ns )
{
int nRest=0, i;
for(i=0; i<ns; i++ ) nRest += gr[i].nota<5;
return ns-nRest;
}
Referirea prin pointeri la structuri
Referirea membrilor unei structuri se poate face si prin intermediul unui pointer la variabila structura. In acest caz operatorul de referentiere este -> (minus, mai mare), care are aceeaºi prioritate si asociativitate cu operatorii . ( )[ si ].
Exemplu 7. Se reia exemplul cu numere complexe:
struct Complex {
double real;
double imag;
} z, *pz=&z;
// ...
pz->real=2.;
pz->imag=-3.; // z= 2 -3i
printf("\nz1=%lf+(%lf)i", z.real, (*pz).imag);
Expresiile pz->imag si
(*pz).imag sunt echivalente (in exemplul de mai sus referind ambele
membrul z.imag).
Variabilele structurate pot fi alocate dinamic.
Exemplul 8. Fisierul ce contine functia main() este exstru4.c
unde se va aloca o variabila structurata ce va fi initializata cu -5+7i
si apoi afisata.
// Program Exstru4.c
#include <stdio.h>
#include <alloc.h>
#include "d:/c/exstru4.h"
void main ()
{
PtCOMPLEX pz;
//.. structura alocata dinamic
pz = (PtCOMPLEX) malloc (sizeof(COMPLEX));
pz->real =-5;
pz->imag=7.; // z = -5 + 7 i
printf("\nz2=%lf %c %lfi", (*pz).real,
pz->imag>=0?'+':'\b', (*pz).imag);
}
Exemplul 9. Sa consideram o structura care are ca membri
structuri si un pointer la o alta structura.
// Program Exstru7.c
// Structuri ce contin ca membri alte structuri
// PSG/24/03/2000
#include <stdio.h>
#include <string.h>
void main ()
{
struct adresa {
char strada[20];
int nr;
} adrAlex;
struct data { int zi,luna,an; } ziAlex={24,3,80};
struct Pers {
char *nume;
struct adresa *padr;
struct data nascut;
} Alex , *pAlex= &Alex;
//
strcpy(adrAlex.strada, "str.Mirauti");
adrAlex.nr=24;
Alex.nume="Bonus Alexandru"; //nume
este pointer
Alex.padr= &adrAlex;
Alex.nascut = ziAlex; //atribuire de
structuri
//
printf("\nNume:%s (%c.%c.)\nNascut
%d/%d/%d\nAdresa: %s nr.%d",
Alex.nume,
*pAlex->nume, pAlex->nume[6], //sau *(pAlex->nume+6),
Alex.nascut.zi, pAlex->nascut.luna, (*pAlex).nascut.an,
Alex.padr->strada, (*Alex.padr).nr );
}
Programul produce urmatoarea afisare:
Nume:Bonus Alexandru (B.A.)
Nascut 24/3/80 Adresa: str.Mirauti nr.24 |
Structuri si functii
O structura poate fi transmisa ca argument al unei functii sau poate
fi returnatã ca rezultat.
Atunci cand este transmisã ca argument, transferul este prin
valoare, deci se va efectua o copie locala a structurii. Acest lucru poate
fi prohibitiv din punctul de vedere al memoriei, daca structura are ca
membri tablouri, sau are un numar mare de membri. Mai convenabil este ca
o structura sa fie transmisa prin intermediul unui pointer. In exemplul
de mai jos sunt ilustrate diverse situatii posibile.
Exemplul 10.
// Program Exstru6.c
// Exemple functii si structuri
// PSG/24/03/2000
#include <stdio.h>
#include <alloc.h>
#include "d:/c/exstru4.h"
COMPLEX suma (COMPLEX a, COMPLEX b);
PtCOMPLEX dif (PtCOMPLEX a, PtCOMPLEX b);
void afis (char *text, COMPLEX z);
void main ()
{
COMPLEX z1={2,-3}, z2={-5,7.},
zs, *pd;
zs = suma (z1, z2 ); //
argumente structuri
pd = dif (&z1, &z2);
// argumente pointeri la structuri
//...
afis("z_suma" , zs);
afis("z_dif ", *pd); //argumentul
2 trebuie sa fie o structura
free (pd); // eliberare
spatiu alocat in functia dif()
}
COMPLEX suma (COMPLEX a, COMPLEX b)
{
COMPLEX rez;
rez.real = a.real + b.real;
rez.imag = a.imag + b.imag;
return rez;
}
PtCOMPLEX dif (PtCOMPLEX a, PtCOMPLEX b)
{
PtCOMPLEX p;
if( (p = (PtCOMPLEX) malloc(
sizeof(COMPLEX)) )==NULL) return NULL;
p->real = a->real - b->real;
p->imag = a->imag - b->imag;
return p;
}
void afis (char *text, COMPLEX z)
{
printf ("\n%s=%.2lf + (%.2lf)i",
text, z.real, z.imag);
}