You are on page 1of 17

Lucrarea nr.

1
Fundamentele limbajului C++. Partea I.

Identificatori
Identificatorii limbajului C++, ca şi în limbajul C standard, sunt formaţi cu ajutorul caracterelor
alfanumerice şi liniuţa de subliniere (underscore), “_”.
Primul caracter al unui identificator nu poate fi o cifră. De exemplu:

Raza // valid
mesaj // valid
_maxx // valid
a5 // valid
5a // invalid

Din mulţimea identificatorilor posibili, se remarcă cuvintele cheie (reserved keywords) ale limbajului,
identificatori a căror semnificaţie nu poate fi modificată de programator (Tabelul nr. 1).
Cuvintele cheie din tabel care încep cu semnul underscor reprezintă variabile interne.

Tipuri de date fundamentale


Tipul unei date determină dimensiunea zonei de memorie ocupate şi valorile pe care le poate lua.
Tipurile datelor se pot grupa în tipuri fundamentale şi tipuri derivate.
Tipurile de date fundamentale cuprind tipurile aritmetice de bază şi tipul void.
Există patru tipuri aritmetice de bază, specificate prin cuvintele cheie: char, int, float şi double. Gama de
valori poate fi extinsă prin modificatori de tip desemnaţi prin cuvintele cheie: signed, unsigned, short,
long. Tipurile întregi ce se obţin prin combinarea tipurilor de bază cu modificatorii de tip sunt prezentate în
Tabelul nr. 2, iar cele reprezentate în virgulă mobilă în Tabelul nr. 3.

Page 1 of 17
Tipul fundamental void indică absenţa oricărei valori şi se utilizează în următoarele situaţii: declaraţia
unei funcţii fără parametri sau care nu returnează un rezultat, tipul pointer generic şi conversii de tip cu
operatorul cast pentru pointeri.
Iată câteva exemple de expresii care returnează ca valoare spaţiul de memorie ocupat de date de diferite
tipuri:

sizeof (long int); // expresia returnează valoarea 4


sizeof (unsigned char) // expresia returnează valoarea 1
sizeof (long double) // expresia returnează valoarea 10

Observaţie: C++ admite delimitatorii /* */ pentru inserarea de comentarii care se pot întinde pe mai multe
rânduri şi, în plus, introduce delimitatorul // pentru includerea de comentarii de sfârşit de linie.
Tot textul care urmează după delimitatorul // până la sfârşitul liniei este considerat comentariu.

Constante caracter

Page 2 of 17
Constantele caracter sunt reprezentate de unul sau mai multe caractere încadrate de apostrofuri, de
exemplu: ‘a’,’A’,’\n’ şi ele sunt de tip char.
Pentru a specifica o serie de caractere neafişabile, delimitatorii (‘), (“), caracterul (\), etc. se utilizează
secvenţele escape (secvenţe de evitare) (vezi Tabelul nr. 4).

Observaţie: În C, toate constantele de un singur caracter au tipul int şi sunt reprezentate intern pe 16 biţi cu
octetul mai semnificativ 0 pentru valoarea caracterului mai mică decât 128, sau –1 (0xFF) pentru valori în
intervalul 128…255.
Constante caracter duble (specifice pentru C++)
Limbajul C++ permite specificarea unor constante alcătuite din două caractere, reprezentate pe 16 biţi (tipul
int) ca în exemplul care urmează:

‘ab’ // reprezentarea în memorie ca întreg de valoare 25185 (0x62 0x61)


‘\t\t’ // reprezentarea în memorie ca întreg de valoare 2313 (0x09 0x09)

Primul caracter este memorat în octetul mai puţin semnificativ.


Observaţie: Constantele duble pot ridica probleme de portabilitate, ele nefiind
recunoscute de alte compilatoare.

Variabile
Declaraţii de variabile
Toate variabilele trebuie declarate înainte de a fi folosite.
Declaraţia unei variabile (obiect) precizează numele (identificatorul) cu care va fi referită, căruia îi poate
asocia o serie de atribute, cum ar fi:
- tipul datei poate fi tip fundamental sau definit de utilizator şi determină structura, gama de valori,
dimensiunea spaţiului ocupat în memorie;
- clasa de memorare stabileşte zona de memorie în care se va plasa informaţia asociată identificatorului
(segment de date, registru, stivă, heap) şi delimitează durata sa de alocare;

Page 3 of 17
- domeniul reprezintă porţiunea de program în care poate fi accesată informaţia asociată identificatorului,
el fiind determinat de poziţia declaraţiei;
- durata de viaţă a identificatorului reprezintă perioada cât există efectiv în memorie şi este corelată cu
clasa de memorie;
- legătura precizează modul de asociere a unui identificator cu un anumit obiect sau funcţie, în procesul de
editare a legăturilor.
Atributele se pot asocia identificatorilor în mod implicit, în funcţie de poziţia şi sintaxa declaraţiei sau
explicit prin utilizarea unor specificatori.
Sintaxa unei declaraţii de variabilă impune specificarea tipului, având forma generală:
tip_var nume_var;
tip_var este un specificator de tip de date oarecare, standard, pointer sau definit de utilizator.

float * r; // declararea variabilei r de tip pointer la float,


unsigned int n; // declararea variabilei n de tip unsigned int

Se pot face declaraţii de variabile cu iniţializare utilizând sintaxa:


tip_var nume_var= valoare_initiala;
sau se pot declara mai multe variabile de acelaşi tip utilizând sintaxa:
tip_var nume_var1<=val_initiala1>,< nume_var2<= val_initiala2>>,...;

double real=2.5; // declararea variabilei real de tip double, iniţializată cu valoarea 2.5
char c1, c2=’a’, ch; // declararea a trei variabile de tip char, c1, c2 şi ch, variabila c2
// fiind iniţializată cu valoarea ‘a’

Poziţia declaraţiei determină cele două domenii de existenţă fundamentale:


- Domeniul bloc (local)
Identificatorii cu domeniu bloc se numesc locali şi sunt rezultatul unor declaraţii în interiorul unui bloc (au
domeniul cuprins între declaraţie şi sfârşitul blocului) sau sunt parametrii formali din definiţia unei funcţii
(au ca domeniu blocul funcţiei).
- Domeniul fişier (global)
Identificatorii cu domeniu fişier se numesc globali şi sunt declaraţi în afara oricăror funcţii (domeniul este
cuprins între declaraţie şi sfârşitul fişierului).

#include <stdio.h>
// zona declaraţiilor globale
int functie (int, float);
int a; // se declară variabila cu numele a, căreia i se rezervă o zonă de memorie de 2
// octeţi (16 biţi) localizată în segmentul de date, deoarece declaraţia se află în
// zona declaraţiilor globale definiţii de funcţii
void main (void)
{
unsigned char c; // se declară variabila automatică cu numele c căreia i se rezervă un
// octet în segmentul de stivă, variabila fiind o variabilă locală
float r=2.5; // se declară variabila automatică cu numele r căreia i se rezervă 4
// octeţi în segmentul de stivă, variabila fiind o variabilă locală care este
… // iniţializată cu valoarea 2.5
}
int functie (int n, float q) // se declară variabilele locale n şi q, cărora li se alocă 2,
// respectiv 4 octeţi în segmentul de stivă
Page 4 of 17
{

}

Observaţii:
1. Într-un bloc inclus în domeniul unei declaraţii este permisă o declaraţie locală a aceluiaşi identificator,
asocierea fiind însă făcută unui alt obiect cu alocarea altei zone de memorie.
2. Spre deosebire de C, care impune gruparea declaraţiilor locale la începutul unui bloc, C++ permite
plasarea declaraţiilor în interiorul blocului, bineînţeles înainte de utilizarea obiectului.

void main (void)


{

for (int i=5; i<8; i++) // declararea lui i este imediat urmată de utilizarea sa
{…}
for {i=0; i<5; i++) // i a fost declarat anterior
{…}

}
Clasa de memorare se poate preciza prin specificatorii auto, static, extern, register. Aceşti specificatori
precizează modul de alocare a memoriei şi timpul de viaţă pentru variabile şi legătură pentru funcţii şi
variabile.

auto
Declaraţia auto specifică o variabilă automatică şi se poate utiliza pentru variabile cu domeniul local (cu
spaţiu alocat pe stivă). Variabilele ce se declară în interiorul unui bloc sunt implicit automatice, astfel că
declaraţia auto este rar folosită.
void fct()
{
auto float r; // declararea unei variabile automatice cu declarare explicită
double s; // declararea unei variabile implicit automatică
...
}
static
Declaraţia static a unei variabile locale forţează durata statică fără a modifica domeniul de existenţă.
Variabilele statice îşi păstrează valoarea între două apeluri succesive ale blocurilor care le conţin,
asigurându-se în acelaşi timp o protecţie, dar ele nu pot să fie accesate din blocuri care nu constituie
domeniul lor de existenţă. Variabilele statice pot fi declarate cu iniţializare, în caz contrar, implicit se
iniţializează cu valoarea 0, similar variabilelor globale.

#include <stdio.h>
int fct()
{
static int a=2; // se declară o variabilă locală funcţiei, cu durată statică
return (a++); }
void main(void)
{
int n;
n=fct();
printf („\n Prima atribuire : n= %d”, n);
n=fct();
Page 5 of 17
printf („\n A doua atribuire : n= %d”, n);
}

Programul afişează:
Prima atribuire : n= 3 (la primul apel al funcţiei, variabila a are valoarea iniţială 2, ea fiind apoi
incrementată ).
A doua atribuire : n= 4 (la al doilea apel al funcţiei, variabila a are la început valoarea 3, valoare datorată
apelului anterior al funcţiei, valoarea fiind apoi incrementată.

register
Declaraţia register are ca efect memorarea variabilei într-un registru al procesorului şi nu în memorie,
având ca rezultat creşterea vitezei de execuţie a programului. Aceste variabilele pot fi variabile locale,
nestatice, de tip int sau char. Numai două variabile pot fi memorate simultan în registre, în cazul existenţei
mai multor declaraţii register, cele care nu pot fi onorate vor fi tratate
de compilator ca variabile obişnuite.

register char c; // declararea variabilei c cu memorare într-un registru al procesorului

extern
Specificatorul extern indică legătura externă şi asigură durata statică pentru variabile locale şi globale sau
pentru funcţii (acestea au implicit legătură externă şi durată statică).
Pentru identificatorii cu legătură externă sunt permise mai multe declaraţii de referinţă, dar o singură
definiţie. De exemplu, în cazul unui proiect în care o variabilă se foloseşte în mai multe fişiere, ea se va
defini global într-un fişier, în celelalte fiind declarată extern fără definire. Compilatorul îi va aloca o
singură dată memorie.

// Fişier Ex_prj.cpp
#include <stdio.h>
extern int m; // se declară legătură externă pentru variabila m
void main(void)
{

scanf(“%d”, &m);
printf(“\nm= %#x”, m);

}
// Fişier Ex_prj1.cpp
...
int m ; // declaraţia variabilei m

În exemplul anterior, cele două fişiere, Ex_prj.cpp şi Ex_prj1.cpp, se includ într-un proiect utilizând
opţiunea “project” a meniului principal din mediul de programare C/C++. Variabila m este declarată global
într-unul dintre fişiere, ea putând fi referită din celălalt fişier datorită specificării legăturii “extern” .

Modificatori de acces
Modificatorii de acces ce pot fi utilizaţi sunt const şi volatile şi ei pot controla modul de modificare a unei
variabile.

const

Page 6 of 17
Variabilele const nu pot fi modificate pe parcursul execuţiei unui program. Instrucţiunile care încearcă
modificarea variabilelor const generează erori la compilare.

const int a=99; // declaraţia variabilei a const


a++; // eroare, a este const
a+=5; // eroare, a este const

O variabilă pointer constantă nu se poate modifica, în schimb se poate modifica obiectul indicat.
În cazul unui pointer către un obiect constant, valoarea pointerului este modificabilă, dar nu şi valoarea
obiectului.

void main()
{
int var1=25, var2=44;
const int var3=7;
int * p1=&var1; // declaraţie cu iniţializare
int * p2=&var3; // eroare, nu se poate converti ’const int *’ la ’int *’
const int * p3=&var3; // corect, tipul de date corespund
var3++; // eroare, se încearcă modificarea unui obiect constant
*p3=15; // eroare, se încearcă modificarea unui obiect constant
int * const p4=&var1; // corect, se declară un pointer constant
p4=&var2; // eroare, se încearcă modificarea unui pointer constant
*p4++; // corect, se modifică valoarea obiectului var2 care nu
// este declarat constant
}

În mod uzual se folosesc funcţii cu parametri pointeri către obiecte constante atunci când se doreşte
protejarea la modificare a acestora.
Un exemplu este o funcţie care realizează criptarea unui şir de caractere:

#include <stdio.h>
#include <string.h>
void criptare(const char *sir_i, char *sir_c); // parametrul sir_i este declarat const pentru a
// evita modificarea lui în interiorul funcţiei
// criptare()
void main()
{
char sir_initial[80], sir_criptat[80];
sir_initial=”Exemplu criptare”;
criptare(sir_initial, sir_criptat);
printf(“\nSirul criptat este: %s”, sir_criptat);
}
void criptare( const char *sir_i, char *sir_c)
{
while (*sir_i)
{
*sir_c = * sir_i+1 ; // criptarea se face prin modificarea codului ASCII
sir_i ++ ;
sir_c ++ ;
}
*sir_c=’\0’;
}
Page 7 of 17
volatile
Variabilele volatile pot fi modificate din exteriorul programului (de exemplu servirea unei întreruperi).

Declaraţia typedef
Specificatorul typedef nu declară un obiect, ci asociază un nume unui tip de date. Sintaxa este:
typedef tip_data identificator_tip

typedef unsigned char octet; // tipul unsigned char este echivalent cu octet
octet var; // variabila var se declară de tip octet

Tipuri de date derivate

Pointeri de date
Tipul pointer (indicator) reprezintă adrese ale unor zone de memorie (adrese de variabile sau constante).
Există, de asemenea, pointeri generici, numiţi pointeri void, care pot conţine adresa unui obiect de orice tip.
Declararea variabilelor pointer
Sintaxa declaraţiei unui pointer de date este:
tip * id_ptr;
Simbolul * precizează că id_ptr este numele unei variabile pointer, iar tip este tipul obiectelor a căror
adresă o va conţine (tipul de bază al id_ptr).
Compilatorul interpretează zona de memorie adresată de pointer ca obiect de tipul indicat in declaraţie, cu
toate atributele tipului: dimensiunea zonei de memorie necesară şi semnificaţia informaţiei conţinute.
Declararea unui pointer generic se face folosind sintaxa:
void * id_vptr;
În cazul acestei declaraţii, dimensiunea zonei de memorie adresate şi interpretarea informaţiei nu sunt
definite, iar proprietăţile diferă de ale celorlalţi pointeri de obiecte.

int * ptr; // pointer la întreg


int * tabptr[10]; // tablou de pointeri către întregi
float **pptr; // dublă indirectare; pointer la pointer

Este important că orice variabilă pointer trebuie iniţializată cu o valoare validă, 0 (NULL) sau adresa unui
obiect înainte de a fi utilizată. In caz contrar, efectele pot fi grave deoarece la compilare sau în timpul
execuţiei nu se fac verificări ale validităţii valorilor pointerilor.
Operatori specifici.
Există doi operatori unari care permit folosirea variabilelor pointer:
• operatorul & se foloseşte pentru aflarea adresei unei variabile oarecare şi
• operatorul * pentru accesul la variabila adresată de un pointer.

#include <stdio.h>
void main(void)
{
int var=20, *pvar;
printf("\nVariabila var se afla la adresa %p”, &var);
printf("si are valoarea var= %d", var);
pvar=&var;
printf("\nVariabila pvar are valoarea %p”, pvar);
printf("si adreseaza obiectul: %d", *iptr);

Page 8 of 17
*iptr=50;
printf("\nNoua valoare a lui var este %d”, var);
}

Programul afişează:
Variabila var se află la adresa: FFF4 si are valoarea iv= 20
Variabila pvar are valoarea: FFF4 si adreseaza obiectul: 20
Noua valoare a lui var este 50

Situaţia:
tipl * id_pl;
tip2 * id_p2;
id_pl=&id_p2;
nu generează erori dacă tip1 şi tip2 sunt identice, sau, în caz contrar dacă tip1 este void.
Dacă se foloseşte un pointer void, pentru orice referire a obiectului adresat este necesară precizarea
explicită a tipului utilizând operatorul cast.

void main()
{ void *p1;
float *p2, var=1.5;
p2=&var;
p1=p2;
printf(“\nValoarea referita de p1: %f “, * (float *) p1);
}

Variabile referinţă
C++ oferă posibilitatea de a declara identificatori ca referinţe de obiecte (variabile sau constante).
Referinţele, ca şi pointerii, conţin adrese. Pentru a declara o referinţă la un obiect se foloseşte simbolul &,
folosind sintaxa:
tip & id_referinta = nume_obiect;
tip este tipul obiectului pentru care se declară referinţa, iar simbolul & precizează că id_referinta este
numele unei variabile referinţă, iar nume_obiect este obiectul a cărui adresă va fi conţinută în id_referinta.

int n; // se declară n de tip întreg


int * p=&n; // se declară pointerul p cu iniţializare adresa lui n
int &r=n; // se defineşte r referinţa lui n
n=20; // n primeşte valoarea 20
*p=25; // n primeşte valoarea 25
r=30; // n primeşte valoarea 30

În exemplul anterior, atât p, cât şi r, acţionează asupra variabilei n. Atunci când se accesează o variabilă
prin referinţa sa, nu este necesar să se folosească adresa, acest lucru realizându-se automat.
Spre deosebire de pointeri, care la un moment dat pot primi ca valoare adresa unei alte variabile, referinţele
nu pot fi modificate, ele fiind practic o redenumire a variabilei a căror adresă o conţin (se creează un alias
al respectivei variabile).
În utilizarea referinţelor, trebuie avute în vedere următoarele restricţii:
• referinţele trebuie iniţializate în momentul declarării;
• referinţelor nu li se pot modifica locaţiile la care se referă;
• nu sunt permise referinţe la câmpuri de biţi, referinţe la referinţe şi pointeri la referinţe, deci nici
tablouri de referinţe.
Page 9 of 17
int &r ; // eroare, se declară o referinţă fără iniţializare
int &r=20 ; // corect, se declară o referinţă la o constantă
const int i = 20;
int &r = i ; // eroare, se declară o referinţă întreagă la o constantă întreagă
const int i = 20;
const int &r = i ; // corect, se declară o referinţă constantă întreagă la o constantă întreagă

Observaţie: Referinţele de sine stătătoare sunt rar folosite. În schimb, utilizarea parametrilor formali
referinţă permite transferul prin referinţă simplu şi eficient, fără recurgerea la parametri formali pointeri.

Tablouri de date
Tabloul de date (sau masiv de date) este o colecţie de date de acelaşi tip, plasate într-o zonă contiguă de
memorie.
Sintaxa declaraţiei unui tablou cu N dimensiuni este:
tip_element nume_tablou [dimensiune1][dimensiune2]…[dimensiuneN]
Zona de memorie rezervată conţine dimensiune1 x dimensiune2 x...x dimensiuneN elemente de tipul
tip_element.
Referirea unui element de tablou se face cu operatorul de indexare [ ] sub forma:
nume_tablou [indice1][indice2]...[indiceN]
Declaraţia unui tablou se poate face cu iniţializarea sa folosind sintaxa:
declaratie_tablou={listă_valori};
Lista de valori trebuie să conţină constante de tip compatibil cu tipul de bază al tabloului, în ordinea plasării
în memorie.

float vect1[5]; // se declară un tablou cu 5 elemente float, fără iniţializare


vect1[0]=1.5; // elementului de index 0 i se atribuie valoarea 1.5
int vect2[10]={2,7,-1,0,9,15,-5,22,6,11}; // se declară un tablou cu 10 elemente int cu
// iniţializare
int mat[2][3]={{3,5,-3},{2,-1,0}}; // se declară un tablou bidimensional cu 2*3
// elemente de tip întreg, cu iniţializare
mat[1][2]= 23; // elementului de indecşi 1, respectiv 2, i se atribuie valoarea 23
Tablourile unidimensionale cu elemente de tip char sunt folosite pentru memorarea şirurilor de caractere.
Pentru a marca sfârşitul unui şir de caractere, după ultimul caracter se adaugă un octet cu valoarea 0 (‘\0’),
numit şi terminator de şir.

char sir1[10]; // se declară un tablou unidimensional, cu elemente char (şir de caractere), fără
// iniţializare
char sir3[ ]=”sir de caractere”; // se declară un tablou cu 17 elemente char (şir de
// caractere) cu iniţializare (ultimul caracter depus în
// tablou este terminatorul de şir ‘\0’
sir3[0]=’S’; // primul caracter al şirului primeşte valoarea ‘S’

Numele unui tablou fără index este un pointer constant de tipul elementelor tabloului şi are ca valoare
adresa primului element al tabloului.

float tab[20], *ptr;


ptr=tab; // atribuire validă, pointerul ptr va conţine adresa primului element al
Page 10 of 17
// tabloului
&tab[0] = = tab ;
&tab[2] = = tab+2 ;
tab[0] = = *tab ;
tab[2] = = *(tab+2) ;
tab++ ; // eroare, tab este un pointer constant, deci nu se poate incrementa
ptr++ ; // corect, ptr este un pointer la float, nu a fost declarat constant

Tablourile multidimensionale reprezintă tablouri cu elemente tablouri, astfel încât numele tabloului (fără
index) este un pointer de tablouri.

float mat[10][10]; // mat reprezintă un tablou de pointeri float


float *p; // p este un pointer float
p=mat; // eroare, tipurile pointerilor diferă
p=(float*)mat; // corect, s-a folosit o conversie explicită de tip
mat = = &mat[0][0]; // expresie adevărată
mat+1 = = &mat[1][0]; // expresie adevărată
*(mat+9) = = mat[9][0]; // expresie adevărată

Tipuri de date definite de utilizator


Tipurile de date fundamentale şi derivate nu pot acoperi totdeauna necesităţile de organizare a informaţiei,
în numeroase situaţii fiind necesară asocierea de date de tipuri diferite.
Vom prezenta în continuare posibilităţile oferite de limbajul C pentru definirea unor tipuri de date cu un
grad de complexitate sporit. Acestea sunt:
- enumerarea, care este o listă de identificatori cu valori constante de tip întreg;
- structura, care este o colecţie de date de tipuri diferite referite cu acelaşi nume;
- câmpul de biţi, care este un membru al unei structuri căruia i se alocă în memorie un număr de biţi în
interiorul unui cuvânt;
- uniunea, care permite utilizarea aceleiaşi zone de memorie de obiecte de tipuri diferite.
Noţiunile puse în discuţie în această lucrare de laborator sunt cele comune celor două limbaje, urmând ca,
într-o lucrare ulterioară tratarea acestora să se completeze cu aspecte specifice limbajului C++.

Enumerarea
Tipul enumerare constă dintr-un ansamblu de constante întregi, fiecare asociată unui identificator. Sintaxa
declaraţiei este:
enum <id_tip_enum> {id_elem<=const>,…} <lista_id_var>;
unde: id_tip_enum = nume tip enumerare;
id_elem = nume element;
const = constantă de iniţializare a elementului.
Dacă declaraţia nu specifică o constantă, valorile implice sunt 0 pentru primul element, iar pentru celelalte
valoarea elementului precedent incrementat cu o unitate.
Identificatorii elementelor trebuie să fie unici în domeniul lor (diferiţi de numele oricărei variabile, funcţie
sau tip declarat cu typedef).

enum boolean {false, true}; // valoarea identificatorului false este 0, iar a lui true este 1
sau
typedef enum {false, true} boolean; // declaraţia este echivalentă declaraţiei anterioare
# include <stdio.h>

Page 11 of 17
enum boolean {false, true}; // valoarea identificatorului false este 0, iar a lui true este 1
void main()
{
boolean op1=false, op2;
op2=true;
printf(“\n op1=%d\nop2=%d”, op1, op2);
}

Tipul enumerare facilitează operarea cu variabile care pot lua un număr mic de valori întregi, asociindu-se
nume sugestive pentru fiecare valoare.
Programul devine mai clar şi mai uşor de urmărit.

Structuri
Structura este o colecţie de date referite cu un nume comun. O declaraţie de structură precizează
identificatorii şi tipurile elementelor componente şi constituie o definiţie a unui nou tip de date.
Sintaxa declaraţiei unui tip structură este:
struct id_tip_struct {
tip_elem1 id_elem1;
tip_elem2 id_elem2;

tip_elemN id_elemN;} lista_id_var_struct;
unde: struct = cuvânt cheie pentru declararea tipurilor structură;
id_tip_struct = numele tipului structură declarat;
tip_elemK = tipul elementului K, unde K=1…N;
id_elemK = numele elementului K;
lista_id_var_struct = lista cu numele variabilelor de tipul declarat,
id_ti_struct.
Pot să lipsească, fie numele structurii, fie lista variabilelor declarate, dar nu amândouă. De regulă se
specifică numele tipului structură definit, aceasta permiţând declaraţii ulterioare de obiecte din acest tip.

struct data // se declară tipul de date data, ca structură cu 3 membri de tip unsigned int
{
unsigned int zi;
unsigned int luna;
unsigned int an;
};
struct persoana // se declară tipul de date persoana ca structură cu 2
// membri şir de caractere şi un membru de tip data
{
char nume[15];
char prenume[15];
data data_n;
} pers1, pers2; // odată cu declaraţia tipului de date persoana, se declară
// două obiecte din acest tip de date

Se poate declara un tip structură cu ajutorul declaraţiei typedef cu sintaxa:


typedef struct {
tip_elem1 id_elem1;
tip_elem2 id_elem2;

tip_elemN id_elemN;} id_tip_struct;
Page 12 of 17
unde semnificaţia denumirilor este identică cu cea anterioară.
Se reia exemplul anterior, utilizând typedef pentru declaraţia structurilor:

typedef struct
{
unsigned int zi;
unsigned int luna;
unsigned int an;
} data;
typedef struct
{
char nume[15];
char prenume[15];
data data_n;
} persoana;

Elementele structurii se numesc generic membrii (câmpurile) structurii.


Tipurile membrilor pot fi oarecare, mai puţin tipul structură care se defineşte, dar pot fi de tip pointer la
structura respectivă.
Iniţializarea unei variabile structură se face prin enumerarea valorilor membrilor în ordinea în care apar în
declaraţie.
persoana pers={“Ionescu”, ”Adrian”, 10, 10, 1975}; // declararea unui obiect persoana
// cu iniţializare
Referirea unui membru al unei variabile de tip structură se face folosind operatorul de selecţie (.) (punct),
sub forma:
nume_variabilă . nume_câmp
printf(”\nNumele: %s”, pers.nume);
printf(”\nPrenume: %s”, pers.prenume);
printf(”\nData nasterii: %d.%d.%d”, pers.data_n.zi, pers.data_n.luna, pers.data_n.an);

Referirea unui membru al unei structuri indicate de un pointer se face folosind operatorul de selecţie
indirectă (->) (săgeată).

persoana * p_pers; // se declară un obiect pointer la persoana


puts(”\nIntroduceti numele:”);
scanf(„%s”, &p_pers->nume);
puts( ”\nIntroduceti prenumele:)”
scanf(„%s”, &p_pers->prenume);
puts( ”\nIntroduceti data nasterii:”);
scanf(„%d.%d.%d”, &p_pers->data_n.zi, &p_pers->data_n.luna, &p_pers->data_n.an);

Operatorul de atribuire admite ca operanzi variabile structură de acelaşi tip, efectuând toate atribuirile
membru cu membru.

persoana p1={”Popescu”, ”George”, 5, 12, 1982}, p2; // p1 se declară cu iniţializare


p2=p1; // prin atribuire, p2 preia, membru cu membru datele din p1
printf(”\nNumele:%s”, p2.nume);
printf(”\nPrenume:%s”, p2.prenume;
printf(”\nData nasterii: %d.%d.%d”, p2.data_n.zi, p2.data_n.luna, p2.data_n.an);

Transferul unui parametru de tip structură se poate face prin valoare.


Parametrul formal şi cel efectiv trebuie să fie de acelaşi tip.

Page 13 of 17
#include <stdio.h>
typedef struct complex {int re, im;} ;
complex suma(complex a, complex b)
{
complex c;
c.re=a.re+b.re;
c.im=a.im+b.im;
return c;
}
void main()
{
complex c1, c2, c3;
scanf("%d", &c1.re);
scanf("%d", &c1.im);
scanf("%d", &c2.re);
scanf("%d", &c2.im);
c3=suma(c1, c2);
printf("\n%i %i", c3.re, c3.im);
}

Transferul unui parametru de tip structură se poate face prin referinţă.


Parametrii efectivi trebuie să fie adrese de structuri de acelaşi tip cu parametrii.

#include <stdio.h>
typedef struct complex {int re, im;} ;
complex suma(complex *a, complex *b)
{
complex c;
c.re=a->re+b->re;
c.im=a->im+b->im;
return c;
}
void main()
{
complex c1, c2, c3;
c1.re=12;
c1.im=-7;
c2.re=29;
c2.im=35;
c3=suma(&c1, &c2);
printf("\n%i %i", c3.re, c3.im);
}

Pentru transferul parametrilor de tip structură se pot folosi variabile referinţă de structură de acelaşi tip.

include <stdio.h>
typedef struct complex {int re, im;} ;
complex suma(complex &a, complex &b)
{
complex c;
c.re=a.re+b.re;
c.im=a.im+b.im;
return c;
}
void main()

Page 14 of 17
{
complex c1, c2, c3;
puts(”\nIntroduceti valorile:”
scanf(”%d”, &c1.re);
scanf(”%d”, &c1.im);
scanf(”%d”, &c2.re);
scanf(”%d”, &c2.im);
c3 = suma(c1,c2);
printf(”\nc3=%d + i* %d", c3.re, c3.im);
}

Câmpuri de biţi
Câmpul de biţi este un membru al unei structuri sau uniuni care are alocat un grup de biţi în interiorul unui
cuvânt de memorie. Declaraţia unei structuri cu membrii câmpuri de biţi se face sub forma:
struct id_tip_struct
{
tip_elem1 id_elem1 : lungime;
tip_elem2 id_elem2 : lungime;

tip_elemN id_elemN : lungime;
} lista_id_var_struct;
unde lungime reprezintă numărul de biţi utilizaţi pentru reprezentarea în memorie a câmpului respectiv.
Restricţiile care se impun la declararea câmpurilor de biţi sunt:
• tipul poate fi int signed sau unsigned;
• lungimea este o constantă întreagă cu valoarea în domeniul 0-15;
• nu se poate evalua adresa câmpului, deci nu se poate folosi operatorul & pentru acel câmp;
• nu se pot folosi tablouri de câmpuri de biţi.
Referirea membrilor se face ca pentru orice structură, folosind operatorii de selecţie directă sau indirectă
(punct sau săgeată).

#include <stdio.h>
typedef struct
{
unsigned int zi:5; // se declară membrul zi cu reprezentare pe 5 biţi
unsigned int luna:4; // se declară membrul luna cu reprezentare pe 4 biţi
unsigned int an:11; // se declară membrul an cu reprezentare pe 11 biţi
} DATE;
void main()
{
DATE data_n; // se declară un obiect de tip DATE
unsigned int aux1, aux2, aux3;
puts(”Introduceti data :”)
scanf(”%2d.%2d.%4d”, &aux1, &aux2, &aux3); // este necesară utilizarea unor variabile
// auxiliare pentru citirea valorilor, deoarece pentru câmpurile de biţi nu se
// poate face referire la adresă
data_n.zi=aux1;
data_n.luna=aux2;
data_n.an=aux3;
....}

Se poate observa că zona de memorie ocupată de un obiect date este de 3 octeţi, spre deosebire de structura
care nu include câmpuri de biţi care ocupă 6 octeţi.
Page 15 of 17
printf(”data_n ocupa %d octeti”, sizeof(data_n));

Uniuni
Uniunea permite utilizarea în comun a unei zone de memorie de către mai multe obiecte de tipuri diferite.
Sintaxa de declarare a unei uniuni este similară declaraţiei unei structuri:
union id_tip_uniune {
tip_elem1 id_elem1;
tip_elem2 id_elem2;

tip_elemN id_elemN;} lista_id_var_uniune;
sau

typedef union {
tip_elem1 id_elem1;
tip_elem2 id_elem2;

tip_elemN id_elemN;} id_tip_uniune;

Spaţiul alocat în memorie corespunde tipului de dimensiune maximă, membrii uniunii utilizând în comun
zona de memorie.

#include <stdio.h>
struct octet
{
unsigned int b0:1; // se declară o structură care ocupă un octet de memorie,
unsigned int b1:1; // cu acces separat, prin membrii săi, la fiecare bit în parte
unsigned int b2:1;
unsigned int b3:1;
unsigned int b4:1;
unsigned int b5:1;
unsigned int b6:1;
unsigned int b7:1;
};
union intreg
{
char val; // se declară o uniune ce ocupă un octet de memorie care poate
octet bit; // fi accesat ca şi char prin membrul val, sau ca octet prin membrul bit
};
void main ()
{
intreg i;
i.val=22;
// se afişează fiecare bit al uniunii separat:
printf("\n0x%x se reprezinta in binar: %d%d%d%d%d%d%d%d", i.val, i.bit.b7,
i.bit.b6, i.bit.b5, i.bit.b4, i.bit.b3, i.bit.b2, i.bit.b1, i.bit.b0);
}
Programul afişează:
0x16 se reprezinta in binar 00010110

Desfăşurarea lucrării

Page 16 of 17
1. Se va scrie un program care să folosească instrucţiunile condiţionale pentru scrierea semnificaţiei
unei categorii de abonat al cărei număr c (c = 1..4) este citit de la consolă.
Categoriile de abonat disponibile sunt următoarele:
1: Abonat obişnuit;
2: Rezervă;
3: Abonat transferat;
4: Abonat absent.

2. Să se scrie un program care va calcula numărul de zile ale oricărei luni a anului. Luna pentru care se
face calculul se introduce de la tastatură sub formă de număr (1..12). Luna februarie are 29 de zile dacă
anul este divizibil cu 4. Se vor afişa luna şi numărul de zile.

3. Se va scrie un program pentru calculul expresiei : s = 1 + x 2 + x 3 + .. + x n . Se vor citi de la tastatură n


şi x şi se va afişa suma calculată s.

4. Să se realizeze un program care să permită înregistrarea şi citirea variabilelor necesare pentru o


agendă telefonocă pentru maxim 10 abonaţi. Datele care sunt necesare pentru agenda telefonică sunt:
S numele abonatului,
S prenumele abonatului,
S numărul de telefon.
Se vor folosi trei variabile de tip matrice cu identificatorii: NUME, PREN şi TEL.

5. Să se realizeze un program care să permită:


S iniţializarea datei curente: zi, luna, an,
S iniţializarea ceasului: ora, minut, secunda,
S avansul ceasului şi al datei,
S afişarea permanentă a datei şi orei exacte.

Page 17 of 17

You might also like