Download as pdf or txt
Download as pdf or txt
You are on page 1of 409

7-bit ASCII Character Codes

Decimal Octal Hex Binary Value Description

000 000 00 0000 0000 NUL "null" character

001 001 01 0000 0001 SOH start of header

002 002 02 0000 0010 STX start of text

003 003 03 0000 0011 ETX end of text

004 004 04 0000 0100 EOT end of transmission

005 005 05 0000 0101 ENQ enquiry

006 006 06 0000 0110 ACK acknowledgment

007 007 07 0000 0111 BEL bell

008 010 08 0000 1000 BS backspace

009 011 09 0000 1001 HT horizontal tab

010 012 0A 0000 1010 LF line feed

011 013 0B 0000 1011 VT vertical tab

012 014 0C 0000 1100 FF form feed

013 015 0D 0000 1101 CR carriage return

014 016 0E 0000 1110 SO shift out

015 017 0F 0000 1111 SI shift in

016 020 10 0001 0000 DLE data link escape

017 021 11 0001 0001 DC1 device control 1 (XON)


Decimal Octal Hex Binary Value Description

018 022 12 0001 0010 DC2 device control 2

019 023 13 0001 0011 DC3 device control 3 (XOFF)

020 024 14 0001 0100 DC4 device control 4

021 025 15 0001 0101 NAK negative acknowledgement

022 026 16 0001 0110 SYN synchronous idle

023 027 17 0001 0111 ETB end of transmission block

024 030 18 0001 1000 CAN cancel

025 031 19 0001 1001 EM end of medium

026 032 1A 0001 1010 SUB substitute

027 033 1B 0001 1011 ESC escape

028 034 1C 0001 1100 FS file separator

029 035 1D 0001 1101 GS group separator

030 036 1E 0001 1110 RS request to send/record separator

031 037 1F 0001 1111 US unit separator

032 040 20 0010 0000 SP space

033 041 21 0010 0001 ! exclamation mark

034 042 22 0010 0010 " double quote

035 043 23 0010 0011 # number sign

036 044 24 0010 0100 $ dollar sign


Decimal Octal Hex Binary Value Description

037 045 25 0010 0101 % percent

038 046 26 0010 0110 & ampersand

039 047 27 0010 0111 ' single quote

040 050 28 0010 1000 ( left/opening parenthesis

041 051 29 0010 1001 ) right/closing parenthesis

042 052 2A 0010 1010 * asterisk

043 053 2B 0010 1011 + plus

044 054 2C 0010 1100 , comma

045 055 2D 0010 1101 - minus or dash

046 056 2E 0010 1110 . dot

047 057 2F 0010 1111 / forward slash

048 060 30 0011 0000 0

049 061 31 0011 0001 1

050 062 32 0011 0010 2

051 063 33 0011 0011 3

052 064 34 0011 0100 4

053 065 35 0011 0101 5

054 066 36 0011 0110 6

055 067 37 0011 0111 7


Decimal Octal Hex Binary Value Description

056 070 38 0011 1000 8

057 071 39 0011 1001 9

058 072 3A 0011 1010 : colon

059 073 3B 0011 1011 ; semi-colon

060 074 3C 0011 1100 < less than

061 075 3D 0011 1101 = equal sign

062 076 3E 0011 1110 > greater than

063 077 3F 0011 1111 ? question mark

064 100 40 0100 0000 @ "at" symbol

065 101 41 0100 0001 A

066 102 42 0100 0010 B

067 103 43 0100 0011 C

068 104 44 0100 0100 D

069 105 45 0100 0101 E

070 106 46 0100 0110 F

071 107 47 0100 0111 G

072 110 48 0100 1000 H

073 111 49 0100 1001 I

074 112 4A 0100 1010 J


Decimal Octal Hex Binary Value Description

075 113 4B 0100 1011 K

076 114 4C 0100 1100 L

077 115 4D 0100 1101 M

078 116 4E 0100 1110 N

079 117 4F 0100 1111 O

080 120 50 0101 0000 P

081 121 51 0101 0001 Q

082 122 52 0101 0010 R

083 123 53 0101 0011 S

084 124 54 0101 0100 T

085 125 55 0101 0101 U

086 126 56 0101 0110 V

087 127 57 0101 0111 W

088 130 58 0101 1000 X

089 131 59 0101 1001 Y

090 132 5A 0101 1010 Z

091 133 5B 0101 1011 [ left/opening bracket

092 134 5C 0101 1100 \ back slash

093 135 5D 0101 1101 ] right/closing bracket


Decimal Octal Hex Binary Value Description

094 136 5E 0101 1110 ^ caret/circumflex

095 137 5F 0101 1111 _ underscore

096 140 60 0110 0000 `

097 141 61 0110 0001 a

098 142 62 0110 0010 b

099 143 63 0110 0011 c

100 144 64 0110 0100 d

101 145 65 0110 0101 e

102 146 66 0110 0110 f

103 147 67 0110 0111 g

104 150 68 0110 1000 h

105 151 69 0110 1001 i

106 152 6A 0110 1010 j

107 153 6B 0110 1011 k

108 154 6C 0110 1100 l

109 155 6D 0110 1101 m

110 156 6E 0110 1110 n

111 157 6F 0110 1111 o

112 160 70 0111 0000 p


Decimal Octal Hex Binary Value Description

113 161 71 0111 0001 q

114 162 72 0111 0010 r

115 163 73 0111 0011 s

116 164 74 0111 0100 t

117 165 75 0111 0101 u

118 166 76 0111 0110 v

119 167 77 0111 0111 w

120 170 78 0111 1000 x

121 171 79 0111 1001 y

122 172 7A 0111 1010 z

123 173 7B 0111 1011 { left/opening brace

124 174 7C 0111 1100 | vertical bar

125 175 7D 0111 1101 } right/closing brace

126 176 7E 0111 1110 ~ tilde

127 177 7F 0111 1111 DEL delete


STRUCTURA PC
Organizarea generala
Placa de baza
Procesorul
Memoria cache
Executia instructiunilor
Interfatarea procesorului
Tipuri de RAM
Interfata grafica
Subsistemul de I/E

Bibliografie
Michael Karbo –„ PC Architecture”
Organizarea generala

PC-urile sunt realizate pe baza microprocesoarelor, care au evoluat din


anii '70 pana astazi:

Nr. biti Procesor Aplicatii

4 biti 4004 Calcule aritmetice

8 biti 8080 Microcalculatoare CP/M


16 biti 8086, 80286 PC-uri IBM cu MS-DOS

32 biti 80386, Pentium 4 Windows 32

64 biti Athlon 64, Pentium Servere cu Windows, Linux


4 Itanium, Intel 64biti
Core i7
Un PC este alcatuit dintr-o unitate centrala si cateva dispozitive
externe. Unitatea centrala este formata dintr-o carcasa (tower, minitower,
desktop) continand electronica calculatorului (dispozitivele interne):

Dispozitivele interne:
-placa de baza (motherboard): CPU, RAM, ROM (BIOS si programele
de startup), chipset (controllere), porturi, magistrale cu sloturi, interfete EIDE,
USB, AGP, etc;
-hard disk-uri, unitati optice (CD-ROM, DVD), unitati de floppy disk;
-placi diferite: placa video, placa retea, controller SCSI, placa de sunet;
Dispozitive externe: tastatura, mouse, monitor, boxe, camera video
digitala, imprimanta, hard disk extern, etc. Dispozitivele externe sunt conectate
la unitatea centrala prin cabluri sau wireless.
Placa de baza

Placa de baza (motherboard) este componenta cea mai importanta,


intregul calculator fiind construit in jurul sau.
Comunicatia pe placa de baza:
Comunicatia cu dispozitivele externe:
Alimentarea placii de baza:
Conectorul mai vechi AT:
Conectorul ATX12V 2.x de 24 pini sau 20 pini (omite pinii 11, 12, 23, 24):
Placa de baza contine de asemenea:
-cipuri: ROM cu BIOS si alte programe, memoria CMOS cu date
definite de utilizator pentru programul de setup, chipset (de obicei doua cipuri)
continand diferite controllere;
-socket-uri: CPU, memori a RAM, diferite placi (PCI, AGP, AMR, etc.),
hard disk, unitate CD-ROM, DVD;
-conectori pentru dispozitive externe: tastatura, mouse, monitor, USB,
audio, etc.
-jumper-i utilizati pentru diferite configurari (tensiuni, selectie
viteza,adaptare tip echipament);
-pini pentru conectarea buton RESET, LED activitate hard disk, difuzor
incorporat, etc.
Procesorul

Procesorul sau CPU (Central Processing Unit) poate fi diferit. Anumite


caracteristici sunt importante pentru amplasarea pe o placa de baza:
-tip socket;
-frecventa de lucru;
-mod de operare;
-viteza de transfer pe magistrala;
-putere termica.

Un exemplu: Intel Core i7 Extreme cu urmatoarele caracterisitici:


-tip socket: 1366;
-frecventa de lucru: 3.33 GHz;
-mod de operare 32/64 biti;
- viteza de transfer pe magistrala: 6.4 GT/sec (Giga Transferuri pe
secunda);
-putere termica: 130 W.
Pentru a identifica procesorul din sistem se poate utiliza din Windows: Control
Panel → Performance and Maintenance → System:
Puterea termica a procesoarelor actuale este foarte mare, astfel fiind necesara
racirea ("cooler"):
Schema bloc a unui PC:
Transferul de date se poate face pe mai multe magistrale de viteze si
rate de transfer diferite. Magistralele pot fi conectate prin circuite controller
speciale numte "bridge"-uri.

Arhitectura cea mai raspandita de PC contine doua circuite in chipset


numite "north bridge" si "south bridge" (inclusiv cele mai populare chipset-uri de
la Intel si VIA), fiecare avand functii specifice.
North bridge este un controller care controleaza fluxul de date intre
CPU, RAM si portul AGP. AGP este de fapt un port de I/E, utilizat pentru placa
grafica si deoarece trebuie sa fie cat mai aproape de memoria RAM portul AGP
este conectat la "north bridge". Asemanator portul PCI Express x 16, care este
o solutie alternativa la PC-urile mai noi.
South bridge incorporeaza o serie de functii de control, in primul rand
pentru hard disk si celelalte echipamente I/E.
Dezvoltarea hardware-ului a facut ca producatorii de circuite sa includa
o serie de functii in chipset:
-placa grafica → north bridge;
-placa sunet → south bridge;
-modem → south bridge;
-retea → south bridge;
-Firewire → south bridge.
Astfel calitatea obtinuta este satisfacatoare pentru majoritatea aplicatiilor. Insa
pentru aplicatii speciale, placile dedicate permit performante superioare.
Exemplu: placa grafica in jocuri 3D sau ieisre TV.
Memoria cache

Memoria cache este organizata pe cel putin doua niveluri:


Exemplu: Intel Celeron D 300 contine doua memorii cache L1 de 16 KB si o
memorie cache L2 de 256 KB. Magistrala dintre cache-urile L1 si L2 trebuie sa
dispuna de o viteza (rata) foarte mare de transfer. Se poate calcula pe baza
largimii magistralei (numar de biti transferati in paralel) si frecventa ceasului:

CPU Largime Frecventa Rata


magistrala ceas teoretica
Intel Pentium 64 bits 1400 MHz 11.2 GB/s
III
AMD 64 bits 2167 MHz 17.3 GB/s
Athlon XP+

AMD Athlon 64 bits 2200 MHz 17,6 GB/s


64
AMD Athlon 128 bits 2200 MHz 35,2 GB/s
64 FX
Intel Pentium 256 bits 3200 MHz 102 GB/s
4
Capacitatea memoriilor cache variaza in functie de procesor. In timp ce
la AMD se utilizeaza cache L1 de capacitate mare (128 KB), Intel utilizeaza
cache L1 mai mic (16 KB)dar eficient (Execution Trace Cache). Capacitatile
memoriilor cache pentru cateva procesoare:

CPU L1 cache L2 cache


Athlon XP 128 KB 256 KB
Athlon XP+ 128 KB 512 KB
Pentium 4 (I) 20 KB 256 KB
Pentium 4 (II) 20 KB 512 KB
"Northwood"
Athlon 64 128 KB 512 KB
Athlon 64 FX 128 KB 1024 KB
Pentium 4 (III) 28 KB 1024 KB
Executia instructiunilor

Setul de instructiuni executate intr-un PC este de tip CISC ("Complex


Instruction Set Computer"). Instructiunile sunt complexe si au o lungime
variabila intre 8 si 120 de biti. Solutia opusa este setul RISC ("Reduced
Instruction Set Computer"), avand instructiuni de lungime constanta (ex: 32 de
biti). Procesoarele actuale realizeaza un mixaj intre RISC si CISC. Pentru
compatibilitate cu procesoarele mai vechi (programele mai vechi DOS /
Windows) procesoarele actuale pot executa instructiuni CISC, dar fiecare
instructiune CISC este translatata in cate o secventa RISC (2-3 micro-ops)
inainte de executie.
Fiecare nou procesor introdus a extins setul de instructiuni al
procesorului precedent: 80386 a adaugat 26 noi instructiuni, 80486 a adaugat
6 noi instructiuni, iar Pentium a adaugat 8 noi instructiuni. In paralel a scazut
ciclul instructiunilor (ex: adunarea a doua numere la 80386 necesita 6 cicluri, iar
la 80486 necesita numai doua cicluri).
Au fost introduse extensii cum sunt MMX si SSE (se vor discuta mai
tarziu).
O alta imbunatatire importanta: procesoare pe 64 de biti, care pentru
compatibilitate pot executa si programe pe 32 de biti).
Calculele executate intr-un calculator pot fi impartite in doua categorii:
cu numere intregi si cu numere in virgula mobila (in jocuri 3D, prelucrari de
sunete, imagini, video). Initial calculele de v.m. erau executate intr-un
coprocesor aritmetic separat (ex: procesorul 80386 + coprocesorul de v.m
80387). Incepand cu 80486 coprocesorul aritmetic a fost plasat in procesor sub
forma uneia sau mai multor FPU ("floating point unit").
Pentru cresterea performantelor s-au adaugat noi registre si noi
instructiuni. Un prim exemplu: Pentium MMX ("multimedia extension") care
avea un set de instructiuni MMX si un set de registre MMX.
In vara 1998 AMD a introdus sub denumirea 3DNow! un grup de 21
instructiuni SIMD pentru imbunatatirea prelucrarilor 3D, care permitea
prelucrarea in paralel a catorva date cu o singura instructiune
In ianuarie 1999 Intel a introdus SSE ("Streaming SIMD Extensions")
de asemenea pentru imbunatatirea performantelor 3D, in cadrul procesorului
Pentium III. SSE reprezenta o solutie mai performanta decat 3Dnow!:
-8 registre noi de 128 biti care pot sa contina patru numere pe 32 de
biti;
-50 noi instructiuni SIMD;
-12 noi instructiuni media, special propiectate, exemplu: codificarea si
decodificarea stream-urilor video MPEG-2;
-opt noi instructiuni de streaming la memorie pentru a imbunatati
transferul intre cache-ul L2 si memoria RAM.
Cu Pentium 4 s-a extins SSE la SSE2, continand 144 noi instructiuni,
inclusiv operatii intregi SIMD pe 128 biti si operatii de v.m. dubla precizie pe
128 biti. Aplicatii: video, recunoasterea vorbirii, prelucrarea imaginilor, programe
financiar/stiitifice. SSE2 a fost adoptat si de AMD, care a dublat numarul de
registre SSE2 (in comparatie cu Pentium 4).
Mai tarziu, Intel a introdus SSE3 cu 13 noi instructiuni (Pentium 4
Prescott).
Pentru a beneficia de aceste facilitati a fost necesara rescrierea unor
programe care sa includa noile instructiuni.
In cadrul procesorului Pentium 4 s-a introdus tehnologia Hyper-
Threading Technology: permite executia in paralel a doua thread-uri (fire de
executie). Astfel un singur procesor fizic functioneaza ca doua procesoare
logice:
O solutie imbunatatita: procesoarele dual-core. Exemple: AMD
Opteron, Intel Pentium 4 Smithfield. Un procesor dual-core Pentium 4 cu
Hyper-Threading Technology functioneaza ca patru procesoare logice:
Interfatarea procesorului

Cea mai importanta conexiune este cea dintre procesor si memoria


RAM. Transferul de date se face pe o magistrala lucrand la o anumita frecventa
(deaoarece RAM-ul este mult mai lent decat procesorul si aceasta frecventa
este mai mica).
In PC-ul original (IBM XT) transferul intre procesor, RAM si I/E se
desfasura sincron la o frecventa comuna.
Compaq 1987: ideea separarii magistralei sistem de magistrala I/E,
lucrand la frecvente diferite.
Cu introducerea procesorului 80486 s-a trecut la dublarea (cresterea)
frecventei procesorului fata de frecventa RAM
Cu introducerea procesoarelor urmatoare s-a marit si mai mult
frecventa procesorului fata de frecventa magistralei. Ex: Pentium III frecventa
magistralei 133 MHz si frecventa procesorului 1200 MHz (9x).
Tipuri de RAM

In PC se utilizeaza diferite tipuri de RAM, cateva fiind date in tabel:

Tip RAM Pini Lung. Utilizare


cuvant
SD RAM 168 64 biti In PC-uri mai vechi.
Rambus 184 16 biti In unele PC-uri cu Pentium 4 si anumite
RAM chipseturi.
DDR RAM 184 64 biti Versiune mai rapida de SD RAM.
Utilizat cu Athlon si Pentium 4 la 2.5 V.
DDR2 RAM 240 64 biti Frecventa mai mare de ceas, la 1.8 V.
Interfata grafica

Portul AGP este direct conectat la procesor si la memoria RAM.


Interfata grafica poate fi realizata in doua moduri:
-placa "plug-in";
-integrata pe placa de baza.
Placa grafica poate fi conectata la magistrala PCI, magistrala AGP sau la
magistrala PCI Express x16.
Initial, interfata grafica era plasata ca o interfata obisnuita de I/E. Din
cauza cerintelor mari de transfer s-au introdus solutii mai performante.
AGP (Accelerated Graphics Port) este un port special de I/E propiectat
exclusiv pentru placi grafice. Lansata initial de Intel, a fost plasata aproape fizic
fata de "north bridge".
Magistrala AGP este o varianta pe 64 biti a magistralei PCI (pana si
conectorul are forma unui conector PCI, dar de alta culoare si plasat in alta
pozitie). Au fost dezvoltate diferite versiuni: 1X (rata de transfer 254 MB/s), 2X
(508 MB/s), 4X, 8X.
Texturile corespund fondului in cadrul jocurilor, acestea se pot incarca
direct din memoria RAM. Sistemul se numeste DIME – Direct Memory Execute,
acesta permitand extinderea memoriei de pe placa video in RAM-ul placii de
baza.
In figura apare si RAMDAC care permite translatarea datelor numerice in
semnal analogic in cazul in care placa grafica este conectata la un monitor
analogic.
Ulterior s-a introdus magistrala PCI Express X16, oferind o rata de 8 GB/s.
Subsistemul de I/E

Cresterea traficului si perfectionarea tehnologica au condus la


perfectionarea controller-elor de I/E din south bridge.
O comparatie intre magistrala sistem si magistralele de I/E:

Magistrala Magistralele north Magistralele I/E


bridge
Variante FSB, RAM, AGP, PCI ISA, PCI, PCI
Express X16, CSA Express, USB, ATA,
SCSI, FireWire
Conecteaza CPU, RAM, Video, Toate celelalte
Ethernet dispozitive
Frecventa ceasului 66-1066 MHz 10-33 MHz
Capacitate maxima >3 GB/s 20-500 MB/s per
magistrala
Magistralele de I/E conecteaza diferite echipamente la procesor si memoria
RAM:

Nume Dispozitive
KBD, PS2, FDC, Tastatura, mouse, unitate de floppy disk, joystick,
Game etc
ROM, CMOS BIOS, setup, POST
ATA Hard disk, CD-ROM/RW, DVD, etc.
PCI, PCI Express Placa retea, controller SCSI, video grapper card,
placa sunet, etc.
USB Mouse, scanner, imprimanta, modem, hard disk
extern, etc.
Firewire Scanner, DV camera, external hard disk
SCSI Hard disk, unitati CD-ROM, scanner, unitati banda
magnetica
LPT, COM Dispozitive paralele si seriale (imprimanta, modem,
etc)
Cateva exemple de magistrale propriu-zise:
-ISA: mai veche, viteza scazuta;
-MCI, EISA, VL: de asemenea mai vechi , dar mai rapide;
-PCI: magistrala foarte generala de I/E;
-PCI Express: mai recenta.
Acestor magistrale le corespund pe placa de baza conectori in care se pot
introduce diferite placi.
Magistrala PCI

PCI (Peripheral Component Interconnect) este o magistrala


independenta de procesor, putand fi utilizata atat in sisteme pe 32 biti cat si in
sisteme pe 64 biti. Se poate calcula rata de transfer a magistralei:

Frecventa ceas 33 MHz


Largime magistrala 32 biti
Rata 32 biti x 33 333 333 impulsuri/s =
4 B x 33 333 333 impulsuri/s = 132 MB/s

Standardul Plug and Play (dezvoltat de Microsoft si Intel) este parte a


specificatiei PCI, insemnand ca toate interfetele (placile) PCI sunt auto-
configurabile. Conceptul permite ca foarte simplu o placa se poate introduce in
calculator si aceasta va functiona: in realitate este ceva mai complicat caci este
necesar sa se instaleze un driver software. Acest lucru se face insa automat
prin cooperarea dintre interfata, placa de baza si sistemul de operare. Pentru a
opera pe magistrala este necesar sa se specifice placii adresele de I/E,
nivelurile de intrerupere (IRQ), etc:
SCSI
SCSI (Small Computer System Interface) este un controller avansat care poate
transfera pana la 160 MB/s (mult mai mult decat magistrala PCI). Sistemul
SCSI este construit in jurul unui controller central (adaptorul host) care poate
controla un numar de dispozitive SCSI conectate in lant. Fiecarui dispozitiv i se
aloca un numar de identificare si se plaseaza cate un terminator la sfarsitul
fiecarui capat al lantului SCSI. Un lant tipic SCSI:

Controllerul SCSI gestioneaza o intreaga mica retea de dispozitive de I/E.


Discurile SCSI au o capacitate sporita de transfer fata de dispozitivele standard
ATA (chiar daca recent discurile ATA au fost perfectionate devenind
comparabile cu discurile SCSI).
RAID

RAID (Redundant Array of Inexpensive Disks) este o tehnologie care


conecteaza impreuna o serie de hard discuri standard pentru a forma un sistem
avansat, corector de erori, utilizat in servere. Este o extensie a standardului
SCSI si a fost utilizat prima data in 1987, dar ulterior au fost dezvoltate
standardele mai ieftine ATA si SATA.

Avantaje RAID:
-securitate sporita (informatiile se gasesc pe mai multe discuri, in cazul
defectarii unui disc, informatia se gaseste si pe alte discuri;
-transfer de date mai rapid (controllerul RAID scrie si citeste in paralel
pe mai multe discuri, astfel viteza de transfer se poate dubla sau tripla).
Categorii RAID:
Nivel Tehnica
RAID 0 Doua sau mai multe discuri sunt conectate, iar datele sunt
impartite intre ele. Creste viteza (acces paralel), dar fara
sporirea securitati.
RAID 1 Doua hard discuri, obtinand securitate sporita (scriere
normala, + scriere pe discul "mirror".
RAID Utilizeaza patru discuri si combina cele doua tehnici.
0/1
RAID 3 Raspandeste datele pe mai multe discuri si memoreaza
informatia de paritate pe unul dintre ele.
RAID 5 Imbunatateste securitatea si performanta. Utilizeaza cel
putin trei sau uzual patru discuri, fiind considerata cea mai
buna solutie.
USB

USB (Universal Serial Bus) este o magistrala seriala ieftina, care


unifica conectorii diferiti pentru tastatura, mouse, scanner joystick, camera
digitala, imprimanta, etc. pe o magistrala partajata, cu un conector comun.

Caracteristici:
-viteza de transfer maxima 12 Mbiti/s (USB 1.1), respectiv 40 MB/s
(USB 2.0);
-utilizeaza numai patru semnale (in comparatie cu alte standarde si
magistrale);
-cablul USB poate furniza alimentare catre dispozitivul conectat;
-se pot conecta maxim 127 de echipamente USB utilizand hub-uri USB;
-dispozitivele USB se pot conecta din "zbor" fara a restarta calculatorul;
-a facut interfetele seriale COM1 si COM2 inutile.
IEEE 1394 – FireWire

FireWire este o extensie a standardului SCSI furnizand o magistrala


seriala de viteza mare cu rata maxima de 400 Mb/s.

Anumite calculatoare dispun de porturi FireWire integrate pe placa de baza, altele permit
conectarea unor placi FireWire, astfel se poate conecta direct o camera video
Hard discuri ATA si SATA

Un hard disc consta din unul sau mai multe platane magnetice montate
intr-o cutie metalica. Vitezele de rotatie standard sunt de 5400 sau 7200 rotatii /
minut. Capul de citire / scriere este un mic electromagnet care se deplaseaza
deasupra pistelor pe care sunt inregistrati bitii.

Furnizand curent bobinei se poate face scriere, iar fara curent furnizat bobinei
se face citirea.
Fiecare platan de disc este imparit in piste, iar fiecare pista este impartita in
sectoare, un sector continand normal 512 octeti. Scrierea fisierelor pe disc se
face pe unul sau mai multe sectoare, iar evidenta este tinuta de sistemul de
fisiere (FAT in Windows 98, respectiv NTFS in Windows 2000/XP).
Toate hard discurile au cate o memorie cache de 2-8 MB, functionand ca un
buffer, permitand o gestionare optima a datelor.

Hard discul este gestionat de un controller plasat chiar in unitate care


comunica cu un controller compatibil plasat pe placa de baza, cele doua
controllere fiind conectate printr-un cablu. Interfata ATA (AT Attachement) se
bazeaza pe standardul IDE (Integrated Drive Electronics). Standardul IDE
putea gestiona discuri de maxim 512 MB, astfel ca pe la mijlocul anilor '90 a
fost dezvoltat standardul ATA (ATA paralel), utilizat pentru diverse echipamente
ca hard discuri, CD-ROM, DVD, etc.
Interfata ATA poate fi vazuta ca o magistrala gestionata de un controller host,
conectand pana la patru dispozitive, cate doua pe fiecare canal:
Exista mai multe protocoale ATA, fiecare fiind compatibil inapoi:

Protocol Rata transfer maxima teoretica


PIO3 13.3 MB/s
PIO4 16.6 MB/s
Ultra DMA 33 MB/s
(ATA/33)
ATA/66 66 MB/s
ATA/100 100MB/s
ATA/133 133 MB/s
SATA 150 MB/s

Acestea sunt vitezele interfetelor, caci discurile livreaza date in general la o rata
mai mica.
Incepand cu ATA/66 s-a schimbat si tipul de cablu, fiecare fir fiind dublat cu o
linie de masa.
Fiecare dispozitiv ATA contine o mica zona de jumperi, care permit setarea
daca este master sau slave.
Sistemul paralel ATA este inflexibil, iar cablurile late de conectare a
discurilor la placa de baza ocupa loc si impiedica racirea => sistemul Serial
ATA, avand cablu cu numai 7 fire. Caracteristici SATA:
-rate mari de transfer 150 MB/s (versiunea initiala), apoi 300 MB/s, 600
MB/s;
-nu este necesara oprirea calculatorului pentru conectarea /
deconectarea unitatilor de disc;
-controller mai inteligent (tip SCSI);
-fara jumperi pentru master/slave;
-cablu de conectare ingust (8 mm);
-cost scazut si instalare simpla.
CAPITOLUL 3 Implementarea structurilor de control

3. IMPLEMENTAREA STRUCTURILOR DE CONTROL

3.1. Implementarea structurii 3.3. Implementarea structurilor


secvenţiale repetitive
3.2. Implementarea structurii de 3.4. Facilităţi de întrerupere a unei
decizie secvenţe

Algoritmul proiectat pentru rezolvarea unei anumite probleme, pentru a fi înţeles de către
calculator, trebuie implementat într-un limbaj de programare; prelucrarea datelor se realizează
cu ajutorul instrucţiunilor. Instrucţiunea descrie un proces de prelucrare pe care un calculator
îl poate executa. O instrucţiune este o construcţie validă (care respectă sintaxa limbajului)
urmată de ;. Ordinea în care se execută instrucţiunile unui program defineşte aşa-numita
structură de control a programului.

Limbajele moderne sunt alcătuite pe principiile programării structurate. Conform lui C.


Bohm şi G. Jacobini, orice algoritm poate fi realizat prin combinarea a trei structuri
fundamentale:
 structura secvenţială;
 structura alternativă (de decizie, de selecţie);
 structura repetitivă (ciclică).

3.1. IMPLEMENTAREA STRUCTURII SECVENŢIALE


Structura secvenţială este o înşiruire de secvenţe de prelucrare (instrucţiuni), plasate una după
alta, în ordinea în care se doreşte execuţia acestora.

Reprezentarea structurii secvenţiale cu Reprezentarea structurii secvenţiale cu


ajutorul schemei logice ( figura 3.1.): ajutorul pseudocodului:
instr1;
instr2;
S1 . . . . .

S2

Sn

Figura 3.1. Schema logică pentru


structura secvenţială

49
CAPITOLUL 3 Implementarea structurilor de control

Implementarea structurii secvenţiale se realizează cu ajutorul instrucţiunilor:


 Instrucţiunea vidă
Sintaxa: ;
Instrucţiunea vidă nu are nici un efect. Se utilizează în construcţii în care se cere prezenţa unei
instrucţiuni, dar nu se execută nimic (de obicei, în instrucţiunile repetitive).

Exemplul 3.1.:
int a;
. . . . . .
int j;
;
for (;;)
{
. . . .
}

 Instrucţiunea expresie
Sintaxa: <expresie>;
sau: <apel_funcţie>;

Exemplul 3.2.:
int b, a=9;
double c;
b=a+9;
cout<<a;
c=sqrt(a);
clrcsr();//apelul funcţiei clrscr, care şterge ecranul; prototip în conio.h

 Instrucţiunea compusă (instrucţiunea bloc)


Sintaxa: {
<declaratii>;
<instr1>;
<instr2>;<declaratii>;
. . . .
}

Într-un bloc se pot declara şi variabile care pot fi accesate doar în corpul blocului.
Instrucţiunea bloc este utilizată în locurile în care este necesară prezenţa unei singure
instrucţiuni, însă procesul de calcul este mai complex, deci trebuie descris în mai multe
secvenţe. Ca urmare, întregul grup de declaraţii şi instrucţiuni dintr-o instrucţiune compusă,
va fi “privit” ca o singură instrucţiune.

3.2. IMPLEMENTAREA STRUCTURII DE DECIZIE


Structura de decizie este întâlnită sub şi sub numele de structură condiţională, alternativă
sau de selecţie.

Reprezentarea prin schemă logică şi prin pseudocod a structurilor de decizie şi repetitive sunt
descrise în capitolul 1. Se vor prezenta în continure doar instrucţiunile care le
implementează.

50
CAPITOLUL 3 Implementarea structurilor de control

 Instrucţiunea if:
Sintaxa: if (<expresie>)
<instrucţiune1>;
[ else
<instrucţiune2>; ]
La întâlnirea instrucţiunii if, se evaluează <expresie> (care reprezintă o condiţie). Dacă
valoarea sa este 1 (condiţia este îndeplinită) se execută <instrucţiune1>; dacă valoarea
expresiei este 0 (condiţia nu este îndeplinită), se execută <instrucţiune2>. Deci, la un
moment dat, se execută doar una dintre cele două instrucţiuni: fie instrucţiune1, fie
instrucţiune2. După execuţia instrucţiunii if se trece la execuţia instrucţiunii următoare.

Observaţii:
1. Instrucţiune1 şi instrucţiune2 pot fi instrucţiuni compuse (blocuri), sau chiar alte
instrucţiuni if (if-uri imbricate).
2. Deoarece instrucţiunea if testează valoarea numerică a expresiei (condiţiei), este posibilă
prescurtarea: if (<expresie>), în loc de if (<expresie> != 0).
3. Deoarece ramura else a instrucţiunii if este opţională, în cazul în care aceasta este omisă
din secvenţele if-else imbricate, se produce o ambiguitate. În aceste situaţii, ramura
else se asociază ultimei instrucţiuni if.

Exemplul 3.3.:
if (n>0)
if (a>b)
z=a;
else z=b;
4. Pentru claritatea programelor sursă se recomandă alinierea instrucţiunilor prin utilizarea
tabulatorului orizontal.
5. Deseori, apare construcţia: Aceeaşi construcţie poate fi scrisă:
if (<expresie1>)
<instrucţiune1>; if (<expresie1>)
else <instrucţiune1>;
if (expresie2>) else if (<expresie2>)
<instrucţiune2>; <instrucţiune2>;
else else if (<expresie3>)
if (<expresie3>) <instrucţiune3>;
<instrucţiune3>; . . . . .. . . . . .
. . . . . . else
else
<instrucţiune_n>; <instrucţiune_n>;

Expresiile sunt evaluate în ordine; dacă una dintre expresii are valoarea 1, se execută
instrucţiunea corespunzătoare şi se termină întreaga înlănţuire. Ultima parte a lui else
furnizează cazul când nici una dintre expresiile 1,2,. . ., n-1 nu are valoarea 1.
6. În cazul în care instrucţiunile din cadrul if-else sunt simple, se poate folosi operatorul
condiţional.

Exerciţiul 3.1.: Să se citească de la tastatură un număr real. Daca acesta se află în intervalul
[-1000, 1000], să se afiseze 1, dacă nu, să se afiseze -1. Pentru rezolvarea acestei probleme
poate fi folosit atât operatorul condiţional (capitolul 2.5.1.), cât şi instrucţiunea if.

51
CAPITOLUL 3 Implementarea structurilor de control

#include <iostream.h>
void main()
{
double nr; cout<<”Astept numar:”; cin>>nr;//citirea valorii variabilei nr
// variabilei afis i se atribuie valoarea expresiei în care se foloseşte operatorul ?:
int afis = (nr>= -1000 && nr <= 1000 ? 1 : -1); cout<<afis;
/* folosirea instrucţiunii if
int afis;
if (nr >= -1000 && nr <= 10000) afis = 1;
else afis = -1;
cout<<afis; */
}

Exerciţiul 3.2.: Să se calculeze valoarea funcţiei f(x), ştiind că x este un număr real citit de la
tastatură:
- 6x + 20 , dacă x ∈ [- ∞ , -7 ]
f(x) = x + 30 , dacă x ∈ (-7, 0]
x , dacă x>0

Se prezintă două variante de implementare. În prima variantă se folosesc instrucţiuni if-


else imbricate. În a doua variantă, se folosesc 3 instrucţiuni if. Pentru calculul valorii lui
x , a fost apelată funcţia sqrt, din header-ul math.h.

#include <iostream.h> Sau: #include <iostream.h>


#include <math.h> #include <math.h>
void main() void main()
{ {
double x,f;cout<<”x=”; double x,f;cout<<”x=”;cin>>x;
cin>>x; if (x <= 7)
if (x <= -7) f = -x* 6 +20;
f = -x* 6 +20; if (x>=-7 && x<=0 )
else f = x+30;
if ( x<=0 ) if (x>0) f = sqrt(x);
f = x+30; cout<<”f=”<<f<<’\n’;
else f = sqrt(x); }
cout<<”f=”<<f<<’\n’; }

Uneori, construcţia if-else este utilizată pentru a compara valoarea unei variabile cu diferite
valori constante, ca în programul următor:

Exerciţiul 3.3.: Se citeşte un caracter reprezentând un operator aritmetic binar simplu. În


funcţie de caracterul citit, se afişează numele operaţiei pe care acesta o poate realiza.

#include <iostream.h>
void main()
{ char oper;
cout<<”Introdu operator aritmetic, simplu, binar:”; cin>>oper;
if (oper == ’+’)
cout<<”Operatorul de adunare!\n”;
else if (oper==’-’ ) cout<<”Operatorul de scadere!\n”;
else if (oper==’*’ ) cout<<”Operatorul de inmultire!\n”;
else if (oper==’/’ ) cout<<”Operatorul de impartire!\n”;
else if (oper==’%’ ) cout<<”Operatorul rest!\n”;
else cout<<”Operator ilegal!!!\n”; }
52
CAPITOLUL 3 Implementarea structurilor de control

 Instrucţiunea switch
În unele cazuri este necesară o decizie multiplă, specială. În limbajul C, instrucţiunea switch
implementează o astfel de structură de comutare sau de selecţie.

Reprezentare prin schema logică (figura 3.2): Reprezentare prin pseudocod:

evaluare
expresie
Dacă expresie=expr_const_1
instrucţiune1;
[ieşire;]
Altfel dacă expr=expr_const_2
exp=exp_cst_1 DA instrucţiune2;
[ieşire;]
NU secvenţa1

DA ieşire
exp=exp_cst_2 Altfel dacă
expresie=expr_const_n-1
secvenţa2 instrucţiune_n-1;
NU [ieşire;]
Altfel instrucţiune_n;
ieşire
exp=exp_cst_n-1
DA

secvenţa n-1
NU
ieşire
secvenţa n

Figura 3.2. Decizia multiplă

Sintaxa:
switch (<expresie>)
{
case <expresie_const_1>: <instructiune_1>;
[break;]
case <expresie_const_2>: <instructiune_2>;
[break;]
. . . . . . . . . . . . .
case <expresie_const_n-1>: <instructiune_n-1>;
[break;]
[ default: <instructiune_n>; ]
}

Este evaluată <expresie>, iar valoarea ei este comparată cu valorile expresiilor constante
specificate prin <expr_const_1>, <expr_const_2>, etc., până la întâlnirea primei
egalităţi (de exemplu, <expresie>=<expresie_const_k>). În această situaţie se execută
instrucţiunea corespunzătoare acelei ramuri (<instrucţiune_k>). Dacă se întâlneşte
53
CAPITOLUL 3 Implementarea structurilor de control

instrucţiunea break, parcurgerea este întreruptă, deci se va trece la execuţia primei


instrucţiuni de după switch. Dacă nu este întâlnită instrucţiunea break, parcurgerea continuă.
Break-ul cauzează deci, ieşirea imediată din switch.

În cazul în care valoarea expresiei nu este găsită printre valorile expresiilor constante, se
execută cazul marcat cu eticheta default (când acesta există). Expresiile <expresie>,
<expresie_const_1>, <expresie_const_2>,etc., trebuie să fie întregi. În exemplul
următor, ele sunt de tip char, dar o dată de tip char este convertită automat în tipul int.
Valoarea <expresie> joacă rolul de comutator sau selector

Exerciţiul 3.4.: Să rescriem programul pentru problema 3.3., utilizând instrucţiunea switch.

#include <iostream.h>
void main()
{
char oper;
cout<<”Introdu operator aritmetic, simplu, binar:”;
cin>>oper;
switch (oper)
{ case (’+’):
cout<<”Operatorul de adunare!\n”;
break;
case (’-’):
cout<<”Operatorul de scadere!\n”;
break;
case (’*’):
cout<<” Operatorul de inmultire!\n”;
break;
case (’/’):
cout<<”Operatorul de impartire!\n”;
break;
case (’%’):
cout<<”Operatorul rest!\n”;
break;
default:
cout<<”Operator ilegal!\n”; }
}

3.3. IMPLEMENTAREA STRUCTURII REPETITIVE

Aşa cum s-a arătat în capitolul 1, există două categorii de structuri repetitive (ciclice): cu test
iniţial şi cu test final. Structura ciclică cu test iniţial este implementată prin instrucţiunile
while şi for. Structura ciclică cu test final este implementată prin instrucţiunea
do-while.

3.3.1. IMPLEMENTAREA STRUCTURII REPETITIVE CU TEST INIŢIAL

 Instrucţiunea while
Sintaxa:
while (<expresie>)
<instructiune>;

54
CAPITOLUL 3 Implementarea structurilor de control

La întâlnirea instrucţiunii while, se evaluează <expresie>. Dacă aceasta are valoarea 1


sau diferită de 0 (condiţie îndeplinită), se execută <instrucţiune>. Se revine apoi în
punctul în care se evaluează din nou valoarea expresiei. Dacă ea este tot 1, se repetă
<instrucţiune>, ş.a.m.d. Astfel, <instrucţiune> (corpul ciclului) se repetă atât timp
cât <expresie> are valoarea 1. În momentul în care <expresie> ia valoarea 0 (condiţie
neîndeplinită), se iese din ciclu şi se trece la următoarea instrucţiune de după while.

Observaţii:
1. În cazul în care la prima evaluare a expresiei, aceasta are valoarea zero, corpul
instrucţiunii while nu va fi executat niciodată.
2. <Instrucţiune> din corpul ciclului while poate fi compusă (un bloc), sau o altă
instrucţiune ciclică.
3. Este de dorit ca instrucţiunea din corpul ciclului while să modifice valoarea expresiei.
Dacă nu se realizează acest lucru, corpul instrucţiunii while se repetă de un număr infinit
de ori.

Exemplul 3.4.:
int a=7;
while (a==7) //ciclu infinit; se repetă la infinit afişarea mesajului
cout<<”Buna ziua!\n”;

 Instrucţiunea for
În majoritatea limbajelor de programare de nivel înalt, instrucţiunea for implementează
structura ciclică cu număr cunoscut de paşi (vezi reprezentarea prin schema logică şi
pseudocod din capitolul 1). În limbajul C instrucţiunea for poate fi utilizată într-un mod mult
mai flexibil.

Reprezentare prin schema logică (figura 3.3.): Reprezentare în pseudocod:

evaluare expresie1 evaluare expr1


CÂT TIMP expr
(particular - iniţializare contor) REPETĂ
ÎNCEPUT
instrucţiune
0 evaluare expr3
expresie2
SFÂRŞIT
1
instrucţiune

evaluare expresie3
(particular - incrementare contor)
Figura 3.3. Structura ciclică cu test iniţial

Sintaxa:
for ([<expresie1>]; [<expresie2>]; [<expresie3>])
<instructiune>;

Aşa cum se observă, prezenţa expresiilor nu este obligatorie; este obligatorie doar prezenţa
instrucţiunilor vide.

55
CAPITOLUL 3 Implementarea structurilor de control

Exemplul 3.5.:
for ( ; <expresie2>; ) sau: for ( ; ; )
<instructiune>; <instructiune>;

3.3.2. IMPLEMENTAREA STRUCTURII REPETITIVE CU TEST FINAL

 Instrucţiunea do-while

Sintaxa:
do <instructiune>;
while(<expresie>);

Se execută <instrucţiune>. Se evaluează apoi <expresie>. Dacă aceasta are valoarea 1


(condiţie îndeplinită), se execută <instrucţiune>. Se testează din nou valoarea expresiei.
Se repetă <instrucţiune> cât timp valoarea expresiei este 1 (condiţia este îndeplinită).
Spre deosebire de instrucţiunea while, în cazul instrucţiunii do-while, corpul ciclului se
execută cel puţin o dată.

Exerciţiul 3.5.: Se citeşte câte un caracter, până la întâlnirea caracterului @. Pentru fiecare
caracter citit, să se afişeze un mesaj care să indice dacă s-a citit o literă mare, o literă mică, o
cifră sau un alt caracter. Să se afişeze câte litere mari au fost introduse, câte litere mici, câte
cifre şi câte alte caractere. Se prezintă trei modalităţi de implementare (cu instrucţiunea
while, cu instrucţiunea for şi cu instrucţiunea do-while).

#include <iostream.h> Observaţii legate de implementare


#include <conio.h> Variabila c (tip char) memorează
void main() caracterul introdus la un moment dat, de
{ char c; clrscr(); la tastatură.
int lmic=0, lmare=0, lcif=0;
int altcar=0; Variabilele întregi lmic, lmare, lcif şi
cout<<"Aştept car.:"; cin>>c; altcar sunt utilizate pentru contorizarea
while (c!='@'){ (numărarea) literelor mari, mici, a
if (c>='A' && c<='Z') { cifrelor, respectiv a altor caractere.
cout<<"Lit. mare!\n";lmare++; } Acţiunea (care se repetă cât timp
else if (c>='a' && c<='z') { caracterul citit este diferit de constanta
cout<<"Lit. mică!\n";lmic++; } caracter '@') constă din mai multe acţiuni
else if (c>='0' && c<='9') {
simple: citirea unui caracter (cu afişarea
cout<<"Cifră!\n";lcif++; }
în prealabil a mesajului "Aştept car.:");
else{cout<<"Alt car!\n";altcar++;}
cout<<"Aştept car.:";cin>>c; testarea caracterului citit (operatorii
} relaţionali pot fi aplicaţi datelor de tip
cout<<"Aţi introdus \n"; char). Ca urmare, acţiunea din corpul
cout<<lmare<<" litere mari, "; instructiunii while a fost implementată
cout<<lmic<<" litere mici\n"; printr-o instrucţiune bloc.
cout<<lcif<<" cifre şi \n";
cout<<altcar<<" alte caractere\n"; Tot instrucţiuni bloc au fost utilizate pe
getch(); fiecare ramură a instrucţiunii if (afişarea
} mesajului referitor la caracter şi
incrementarea contorului).

56
CAPITOLUL 3 Implementarea structurilor de control

#include <iostream.h> Pentru implementarea aceluiaşi


#include <conio.h> algoritm se poate utiliza instrucţiunea
void main()
for. În cadrul acesteia,
{ char c;clrscr();
int lmic=0,lmare=0,lcif=0; <expresie1> şi <expresie3>
int altcar=0; lipsesc, însă prezenţa instrucţiunilor
cout<<"Aştept caract.:"; cin>>c; vide este obligatorie.
for( ; c!='@'; ){
// corp identic
}
cout<<"Aţi introdus \n";
cout<<lmare<<" litere mari, ";
cout<<lmic<<" litere mici\n";
cout<<lcif<<" cifre şi \n";
cout<<altcar<<" alte caractere\n";
getch(); }

O altă variantă de implementare poate fi următoarea, în care şi iniţializarea variabilelor


contor se realizează în cadrul expresiei <expresie1>.
int lmic, lmare, lcif, altcar;
for(lmare=0, lmic=0, lcif=0, altcar=0; c!='@'; ){
// corp identic
}

Variantă de implementare care utilizează instrucţiunea do-while:


int lmic=0, lmare=0, lcif=0;
int altcar=0;
cout<<"Aştept caract.:";cin>>c;
do {
//corp do-while
} while (c!='@');
cout<<"Aţi introdus \n";
//. . .

Exerciţiul 3.6.: Să se calculeze suma şi produsul primelor n numere naturale, n fiind introdus
de la tastatură. Se vor exemplifica modalităţile de implementare cu ajutorul instrucţiunilor
n n
while, do-while şi for. (Se observă că: S = ∑k , P = ∏ k ). Variabilele P şi S vor fi
k =1 k =1
utilizate pentru memorarea valorii produsului, respectiv sumei, iar k - variabilă contor - pentru
numărarea numărului de repetări a acţiunii (implementată printr-o instrucţiune bloc).

#include <iostream.h> #include <iostream.h>


void main() void main()
{cout<<"n="; int n; cin>>n; {cout<<"n="; int n; cin>>n;
int S=0, P=1, k=1; int S=0, P=1, k=1;
while (k <= n){ do{
S+=k; P*=k; S+=k; P*=k;
k++; k++;
} } while (k <= n);
cout<<"P="<<P<<"\tS="<<S<<'\n'; cout<<"P="<<P<<"\tS="<<S<<'\n';
} }

57
CAPITOLUL 3 Implementarea structurilor de control

Pentru a ilustra multiplele posibilităţi oferite de instrucţiunea for, prezentăm şi variantele


următoare de implementare (s-a rescris doar secvenţa care calculează şi afişează suma şi
produsul):

// varianta1 /* varianta2 - declararea şi iniţializarea


int S=0, P=1, k; variabilei k în cadrul expresie1*/
for (k=1; k<=n; k++){ int S=0, P=1;
S+=k; P*=k; for (int k=1; k<=n; k++){
} S+=k; P*=k;
cout<<"P="<<P<<"\tS="; }
cout<<S<<'\n'; cout<<"P="<<P<<"\tS=";
cout<<S<<'\n';

// varianta3 - declararea şi iniţializarea variabilelor k, P şi S în cadrul expresie1


for (int S=0, P=1, k=1; k<=n; k++){
S+=k; P*=k;
}
cout<<"P="<<P<<"\tS="<<cout<<S<<'\n';

// varianta4 - calculul S, P şi incrementare contor în cadrul expresie3


// instrucţiune din corpul for este vidă
for (int S=0, P=1, k=1; k<=n; S+=k, P*=k, k++)
;
cout<<"P="<<P<<"\tS="<<cout<<S<<'\n';

Exerciţiul 3.7.: Să se citească un şir de numere reale, până la întâlnirea numărului 900. Să se
afişeze maximul numerelor citite.
#include <iostream.h> Se presupune că primul element din şirul de
void main() numere are valoarea maximă. Se
{double n;
cout<<"Introdu nr:"; cin>>n;
memorează valoarea sa în variabila max. Se
double max=n; parcurge apoi şirul, comparându-se valoarea
while (n!=900) fiecărui element cu valoarea variabilei max.
{ if (n>=max) În cazul în care se găseşte un element cu o
max=n; valoare mai mare decât a variabilei max, se
cout<<"Introdu nr:";
reţine noua valoare (max=n).
cin>>n;
}
cout<<"Max şir este:"<<max<<'\n';
}

Exerciţiul 3.8.: Să se afişeze literele mari ale alfabetului şi codurile ASCII ale acestora în
ordine crescătoare, iar literele mici şi codurile aferente în ordine descrescătoare. Afişarea se va
face cu pauză după fiecare ecran.
#include <iostream.h>
#include <conio.h>
#define DIM_PAG 22 //dimensiunea paginii (numarul de randuri de pe o pagina)
void main()
{clrscr();
cout<<"LITERELE MARI:\n";int nr_lin=0;
// nr_lin este contorul de linii de pe un ecran
for (char LitMare='A'; LitMare<='Z'; LitMare++){
if (nr_lin==DIM_PAG){

58
CAPITOLUL 3 Implementarea structurilor de control

cout<<"Apasa o tasta...."; getch(); clrscr(); nr_lin=0;}


cout<<"Litera "<<LitMare<<" cod ASCII "<<(int)LitMare<<'\n';
// conversia explicita (int)LitMare permite afisarea codului ASCII al caracterului
nr_lin++;
}
cout<<"LITERELE MICI:\n";
for (char LitMica='z'; LitMica>='a'; LitMica--){
if (nr_lin==DIM_PAG){
cout<<"Apasa o tasta...."; getch(); clrscr(); nr_lin=0;}
cout<<"Litera "<<LitMica<<" cod ASCII "<<(int)LitMica<<'\n';
nr_lin++;
}
}

Exerciţiul 3.9.: Să se scrie un program care realizează conversia numărului N întreg, din baza
10 într-o altă bază de numeraţie, b<10 (N şi b citite de la tastatură). Conversia unui număr
întreg din baza 10 în baza b se realizează prin împărţiri succesive la b şi memorarea resturilor,
în ordine inversă. De exemplu:
547:8=68 rest 3; 68:8=8 rest 4; 8:8=1 rest 0; 1:8=0 rest 1 547 10 = 1043 8

#include <iostream.h>
void main()
{ int nrcif=0,N,b,rest,Nv,p=1;
long Nnou=0;
cout<<"\nIntroduceti baza<10, b=";cin>>b;
cout<<"Introduceti numarul in baza 10, nr=";cin>>N;Nv=N;
while(N!=0)
{
rest=N%b; N/=b; cout<<"nr="<<N<<'\n';
cout<<"rest="<<rest<<'\n';
nrcif++; Nnou+=rest*p; p*=10; cout<<"Nr. nou="<<Nnou<<'\n';
}
cout<<"Numarul de cifre este "<<nrcif<<'\n';
cout<<"Nr. in baza 10 "<<Nv;
cout<<" convertit in baza "<<b<<" este "<<Nnou<<'\n';
}

Exerciţiul 3.10.: Să se calculeze seria următoare cu o eroare mai mică decât EPS (EPS

xk
introdus de la tastatură): 1+ ∑ , x ∈ [0,1], x citit de la tastatură. Vom aduna la sumă încă un
k =1 k
termen cât timp diferenţa dintre suma calculată la pasul curent şi cea calculată la pasul
anterior este mai mare sau egală cu EPS.
#include <iostream.h>
#include <conio.h>
#include <math.h>
void main()
{ double T,S,S1;long k;k=1;T=1;S=T;double x; cout<<"x="; cin>>x;
double EPS; cout<<"Precizie="; cin>>EPS;
//T=termenul general la pasul curent; S=suma la pasul curent; S1=suma la pasul anterior
do {
S1=S;k++;T=pow(x,k)/k;//funcţia pow(x, k), aflată în <math.h> calculează x k
S+=T; // cout<<k<<" "<<T<<" "<<S<<'\n';getch();
} while (fabs(S-S1)>=EPS);
cout<<"Nr termeni="<<k<<" T="<<T<<" S="<<S<<'\n'; }

59
CAPITOLUL 3 Implementarea structurilor de control

3.4. FACILITĂŢI DE ÎNTRERUPERE A UNEI SECVENŢE


Pentru o mai mare flexibilitate (tratarea excepţiilor care pot apare în procesul de prelucrare),
în limbajul C se utilizează instrucţiunile break şi continue. Ambele instrucţiuni sunt
utilizate în cadrul instrucţiunilor ciclice. În plus, instrucţiunea break poate fi folosită în
cadrul instrucţiunii switch.

 Instrucţiunea break
Aşa cum se observă din figura 3.4., utilizată în cadrul instrucţiunilor ciclice, instrucţiunea
break “forţează” ieşirea din acestea. Fără a se mai testa valoarea expresiei (condiţia) care
determină repetarea corpului instrucţiunii ciclice, se continuă execuţia cu instrucţiunea care
urmează instructiunii ciclice. Astfel, se întrerupe repetarea corpului instrucţiunii ciclice,
indiferent de valoarea expresiei care exprimă condiţia de test.
Prezenţa instrucţiunii break în cadrul instrucţiunii switch: În situaţia în care s-a ajuns la o
valoare a unei expresiii constante egală cu cea a expresiei aritmetice, se execută instrucţiunea
corespunzătoare acelei ramuri. Dacă se întâlneşte instrucţiunea break, parcurgerea este
întreruptă (nu se mai compară valoarea expresiei aritmetice cu următoarele constante), deci se
va trece la execuţia primei instrucţiuni de după switch. Dacă nu este întâlnit break,
parcurgerea continuă. Instrucţiunea break cauzează deci, ieşirea imediată din switch.

 Instrucţiunea continue
Întâlnirea instrucţiunii continue în cadrul instrucţiunilor ciclice, (figura 3.4.) determină
ignorarea instrucţiunilor următoare acesteia, din corpul instrucţiunii repetitive şi reluarea
execuţiei cu testarea valorii expresiei (care reprezintă condiţia de test) care determină
repetarea sau nu a corpului ciclului.

Exemplul 3.5.: Să revenim la programul realizat pentru problema 1, care foloseşte


instrucţiunea do-while. Dacă primul caracter citit este chiar caracterul '@', se realizează
testarea acestuia; ca urmare, se afişează mesajul "Alt car.!" şi se incrementează valoarea
contorului altcar. Dacă nu se doreşte ca acest caracter “terminator” să fie testat şi numărat,
în corpul instrucţiunii do-while putem introduce un test suplimentar.
int lmic=0,lmare=0,lcif=0,altcar=0;cout<<"Aştept caract.:";cin>>c;
do {
if (c == '@') break; //ieşire din do while
//corp do-while
} while (c!='@');
cout<<"Aţi introdus \n";
//. . .
do{
while (expresie1){ <instructiune1>;
<instructiune1>; <instructiune2>;
<instructiune2>; if (<expresie2>)
if (<expresie2>) break;
break; else
else continue;
continue; <instructiune3>;
<instructiune3>; } while (<expresie1>);
}

60
CAPITOLUL 3 Implementarea structurilor de control

Exemplul 3.6.:
for Să se urmărească rezultatele execuţiei
(<exp1>;<exp2>;<exp3>)){ următorului program.
<instructiune1>;
<instructiune2>; void main()
if (<expresie2>) { int k;
break; for(k = 1;k < 15;k++){
else if (k == 8) break;
continue; cout<<"k="<<k<<'\n'; }
<instructiune3>; for(k = 1;k < 15;k++){
if (k == 8) continue;
cout<<"k="<<k<<'\n;
}
Figura 3.4. Modul de utilizare a }
instrucţiunilor break şi continue

3.5. ÎNTREBĂRI ŞI PROBLEME

ÎNTREBĂRI

1. Care sunt instrucţiunile care 4. Care sunt instrucţiunile care


implementează în limbajul C structura implementează în limbajul C structura
condiţională? repetitivă cu test final?
2. Care sunt instrucţiunile care 5. Ce deosebiri sunt între instrucţiunea while
implementează în limbajul C structura şi instrucţiunea do-while?
secvenţială? 6. Pornind de la sintaxa instrucţiunii for,
3. Care sunt instrucţiunile care stabiliţi echivalenţa între aceasta şi
implementează în limbajul C structura instrucţiunile while şi do-while.
repetitivă cu test iniţial?

PROBLEME

1. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.


2. Să se implementeze algoritmii proiectaţi pentru problemele 1-7 din capitolul 1.
3. Să se calculeze aria unui triunghi, cunoscându-se mărimea laturilor sale. Numerele care
reprezintă mărimile laturilor vor fi introduse de utilizator. Se va testa mai întâi dacă cele 3
numere reprezentând mărimea laturilor pot forma un triunghi (a<= b+c, b<=c+d, c<=
a+b).
4. Să se rescrie următoarea secvenţă, folosind o singură instrucţiune if.
if (n<0)
if (n>=90)
if (x!=0)
int b= n/x;
5. Să se citească un numar natural n. Să se scrie un program care afişează dacă numărul n
citit reprezintă sau nu, un an bisect (anii bisecţi sunt multipli de 4, exceptând multiplii de
100, dar incluzând multiplii de 400).
6. Să se găsească toate numerele de două cifre care satisfac relaţia:
xy = ( x + y ) 2

7. Să se citească un şir de numere reale, până la întâlnirea numarului 800 şi să se afişeze


valoarea minimă introdusă, suma şi produsul elementelor şirului.
61
CAPITOLUL 3 Implementarea structurilor de control

8. Scrieţi un program care să verifice inegalitatea 1/(n+1) < ln[(n+1)/n] < 1/n, unde n este un
număr natural pozitiv, introdus de la tastatură.
9. Fie funcţia
e x −3 , x ∈ [0, 1)
Să se calculeze f(x), x citit de la tastatură.
f(x)= sinx+cosx , x ∈ [1, 2)
0,9ln(x+3) , x ∈ [2, 100]
10. Să se scrie un program care calculează şi afişează maximul a 3 numere reale (a, b şi c)
citite de la tastatură.
11. Să se scrie un program care calculează şi afişează minimul a 3 numere reale (a, b şi c)
citite de la tastatură.
12. Să se citească 2 caractere care reprezintă 2 litere mari. Să se afişeze caracterele citite în
ordine alfabetică.
13. Să se citească 3 caractere care reprezintă 3 litere mici. Să se afişeze caracterele citite în
ordine alfabetică.
14. Să se scrie un program care citeşte o cifră. În funcţie de valoarea ei, să se facă următorul
calcul: dacă cifra este 3, 5 sau 7 să se afişeze pătratul valorii numerice a cifrei; dacă cifra
este 2, 4 sau 6 să se afişeze cubul valorii numerice a cifrei; dacă cifra este 0 sau 1 să se
afişeze mesajul "Valori mici"; altfel., să se afişeze mesajul "Caz ignorat!".
15. Fie şirul lui Fibonacci, definit astfel:f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) pentru n>1.
Să se scrie un program care implementează algoritmul de calcul al şirului Fibonacci.
16. Să se calculeze valoarea polinomului Cebîşev de ordin n într-un punct x dat, cunoscând
relaţia: T 0 (x)=1, T 1 (x)=x şi T k +1 (x) - 2xT k (x) + T k −1 (x) = 0
17. Să se citească câte 2 numere întregi, până la întâlnirea perechii (0, 0). Pentru fiecare
pereche de numere, să se calculeze şi să se afişeze cel mai mare divizor comun.
18. Se citesc câte 3 numere reale, până la întâlnirea numerelor 9, 9, 9. Pentru fiecare triplet de
numere citit, să se afişeze maximul.
19. Se citeşte câte un caracter până la întâlnirea caracterului @. Să se afişeze numărul literelor
mari, numarul literelor mici şi numărul cifrelor citite; care este cea mai mare (lexicografic)
literă mare, literă mică şi cifră introdusă.
20. Se citesc câte 2 numere întregi, până la întâlnirea perechii de numere 9, 9. Pentru fiecare
pereche de numere citite, să se afişeze cel mai mare divizor comun al acestora.
21. Să se calculeze suma seriei 1 + x 3 /3 - x 5 /5 + x 7 /7 - … cu o eroare mai mică
decât epsilon (epsilon citit de la tastatură). Să se afişeze şi numărul de termeni ai sumei.
22. Să se citească un număr întreg format din 4 cifre (abcd). Să se calculeze şi să se afişeze
valoarea expresiei reale: 4*a + b/20 -c + 1/d.
23. Să se scrie un program care afişează literele mari ale alfabetului în ordine crescătoare, iar
literele mici - în ordine descrescătoare.
24. Să se scrie un program care generează toate numerele perfecte până la o limită dată, LIM.
Un număr perfect este egal cu suma divizorilor lui, inclusiv 1 (exemplu: 6=1+2+3).
25. Să se calculeze valoarea sumei urmatoare, cu o eroare EPS mai mică de 0.0001:
S=1+(x+1)/ 2! + (x+2)/ 3! + (x+3)/ 3! + ... , unde 0<=x<=1, x citit de la tastatură.
26. Să se genereze toate numerele naturale de 3 cifre pentru care cifra sutelor este egală cu
suma cifrelor zecilor şi unităţilor.
27. Să se citească câte un număr întreg, până la întâlnirea numărului 90. Pentru fiecare numar
să se afişeze un mesaj care indică dacă numărul este pozitiv sau negativ. Să se afişeze cel
mai mic număr din şir.
28. Să se genereze toate numerele naturale de 3 cifre pentru care cifra zecilor este egală cu
diferenţa cifrelor sutelor şi unităţilor.
29. Să se calculeze suma: (1 + 2!) / (2 + 3!) - (2+3!) / (3+4!) + (3+4!) / (4+5!) - .....

62
CAPITOLUL 4 Tablouri

4. TABLOURI

4.1. Declararea tablourilor 4.3. Tablouri bidimensionale


4.2. Tablouri unidimensionale 4.4. Şiruri de caractere

4.1. DECLARAREA TABOURILOR


Numim tablou o colecţie (grup, mulţime ordonată) de date, de acelaşi tip, situate într-o zonă
de memorie continuă (elementele tabloului se află la adrese succesive). Tablourile sunt
variabile compuse (structurate), deoarece grupează mai multe elemente. Variabilele tablou au
nume, iar tipul tabloului este dat de tipul elementelor sale. Elementele tabloului pot fi referite
prin numele tabloului şi indicii (numere întregi) care reprezintă poziţia elementului în cadrul
tabloului.

În funcţie de numărul indicilor utilizaţi pentru a referi elementele tabloului, putem întâlni
tablouri unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri
bidimensionale).

Ca şi variabilele simple, variabilele tablou trebuie declarate înainte de utilizare.

Modul general de declarare:


<tip> <nume_tablou>[<dim_1>][[<dim_2>],…[<dim_n>]];
unde: tip reprezintă tipul elementelor tabloului; dim_1, dim_2,...,dim_n sunt numere întregi
sau expresii constante întregi (a căror valoare este evaluată la compilare), reprezentând
limitele superioare (valorile maxime posibile) ale indicilor tabloului.

Exemplul 4.1.:
//1
int vect[20]; //declararea tabloului vect, de maximum 20 de elemente, de tip int.
// Se rezervă 20*sizeof(int)=20 * 2 = 40 octeţi

//2
double p,q,tab[10];
// declararea variabilelor simple p, q şi a vectorului tab, de max. 10 elemente, tip double

//3
#define MAX 10
char tabc[MAX];
/*declararea tabloului tabc, de maximum MAX (10) elemente de tip char*/

//4
double matrice[2][3]; // declararea tabloului matrice (bidimensional),
// maximum 2 linii şi maximum 3 coloane, tip double

63
CAPITOLUL 4 Tablouri

4.2. TABLOURI UNIDIMENSIONALE


Tablourile unidimensionale sunt colecţii indexate de componente cu un singur indice
(corespund conceptului matematic de vectori). Dacă tabloul conţine maximum dim_1
elemente, indicii elementelor au valori întregi în intervalul [0, dim_1-1].
La întâlnirea declaraţiei unei variabile tablou, compilatorul alocă o zonă de memorie continuă
(dată de produsul dintre dimensiunea maximă şi numărul de octeţi corespunzător tipului
tabloului) pentru păstrarea valorilor elementelor sale. Numele tabloului poate fi utilizat în
diferite expresii şi valoarea lui este chiar adresa de început a zonei de memorie care i-a fost
alocată. Un element al unui tablou poate fi utilizat ca orice altă variabilă (în exemplul
următor, atribuirea de valori elementelor tabloului vector). Se pot efectua operaţii asupra
fiecărui element al tabloului, nu asupra întregului tablou.

Exemplul 4.2.:
// Declararea tabloului unidimensional vector
100 vector[0]
int vector[6];
101 vector[1]
// Iniţializarea elementelor tabloului 102 vector[2]
vector[0]=100;
vector[1]=101; 103 vector[3]
vector[2]=102;
vector[3]=103; 104 vector[4]
vector[4]=104; 105 vector[5]
vector[5]=105;

Exemplul 4.3.: Figura 4.1.


double alpha[5], beta[5], gama[5];
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis

Variabilele tablou, ca şi variabilele simple, pot fi iniţializate în momentul declarării:


<declaraţie_tablou>=<listă_valori>;
Lista de valori cuprinde valorile cu care vor fi iniţializate componentele tabloului, valori
separate prin virgulă şi cuprinse între acolade, ca în exemplele următoare:

Exemplul 4.4.:
//1
int vector[6]={100,101,102,103,104,105};
vector 100 101 102 103 104 105
vector[0] vector[5]
//2
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};

La declararea unui vector cu iniţializarea elementelor sale, numărul maxim de elemente ale
tabloului poate fi omis, caz în care compilatorul determină automat mărimea tabloului, în
funcţie de numărul elementelor iniţializate.

64
CAPITOLUL 4 Tablouri

Exemplul 4.5.: tab


char tab[]={ ’A’, ’C’, ’D’, ’C’}; ’A’ ’B’ ’C’ ’D’
tab[0] tab[3]

float data[5]={ 1.2, 2.3, 3.4 }; data 1.2 2.3 3.4 ? ?


data[0] data[4]
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculată astfel:
adresa_elementului_i = adresa_de_bază + i ∗ lungime_element

Exerciţiul 4.1.:
//1 Citirea elementelor unui vector:
double a[5]; int i;
for (i=0; i<5; i++)
{ cout<<”a["<<i<<”]=”;//afişarea unui mesaj prealabil citirii fiecărui element
cin>>a[i]; } //citirea valorii elementului de indice i
//Sau:
double a[20]; int i, n; cout<<”Dim. Max. =”; cin>>n;
for (i=0; i<n; i++)
{ cout<<”a[“<<i<<”]=”; cin>>a[i]; }
//2 Afişarea elementelor unui vector:
cout<<”Vectorul introdus este:\n”;
for (i=0; i<n; i++) cout<<a[i]<<’ ’;
//3 Afişarea elementelor unui vector în ordine inversă:
cout<<”Elementele vectorului în ordine inversă:\n”;
for (i=n-1; i>=0; i--) cout<<a[i]<<’ ’;
//3 Vectorul sumă (c) a vectorilor a şi b, cu acelaşi număr de elemente, n:
for (i=0; i<n; i++) c[i]=a[i]+b[i];
//4 Vectorul diferenţă (c) a vectorilor a şi b, cu acelaşi număr de elemente:
for (i=0; i<n; i++) c[i]=a[i] - b[i];
//5 Produsul scalar (p) a vectorilor a şi b, cu acelaşi număr de elemente:
n −1
p= ∑ a i ∗ bi double p=0;
i =0
for (i=0; i<n; i++) p += a[i] ∗ b[i];

4.3. TABLOURI BIDIMENSIONALE

Din punct de vedere conceptual, elementele unui tablou bidimensional sunt plasate în spaţiu
pe două direcţii. Matricea reprezintă o aplicaţie naturală a tablourilor bidimensionale.
În matematică:

q 11 q 12 q 13 . . . q 1n
q 21 q 22 q 23 . . . q 2n
Q = ,Q m× n
. . . . . . . . . . . . .
q m1 q m2 q m3 . . . q mn

65
CAPITOLUL 4 Tablouri

În limbajele C/C++, indicii de linie şi de coloană pornesc de la 0:

q 00 q 01 q 02 . . . q 0,n−1

Q = q 10 q 11 q 12 . . . q 1,n−1 ,Q m× n
. . . . . . . . . . . . . .
q m−1,0 q m−1,1 q m−1,2 . . . q m−1,n −1

Exemplul 4.6.:
double q[3][2]; // declararea matricii q, cu maxim3 linii şi 2 coloane, tip double

În memorie, elementele unei matrici sunt memorate pe linii:


q 00 q 01 q 10 q 11 q 20 q 21 . . .
Dacă notăm cu k poziţia în memorie a unui element, valoarea lui k = i ∗ m + j (unde m
este numărul maxim de linii, i este indicele de linie, j este indicele de coloană).

q[0][0] q[0][1] q[0][2] . . q[0][n-1] q[1][0] . . .q[m-1][0] . . q[m-1][n-1]

Dacă se doreşte iniţializarea elementelor unei matrici în momentul declarării acesteia, se


poate proceda astfel:
int mat[4][3] = {
{10, -50, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 19} };
Prin această construcţie, elementele matricii mat se iniţializează în modul următor:
mat[0][0]=10, mat[0][1]=-50, mat[0][2]=3
mat[1][0]=32, mat[1][1]=20, mat[1][2]=1
mat[2][0]=-1, mat[2][1]=1, mat[2][2]=-2
mat[3][0]=7, mat[3][1]=-8, mat[3][2]=19

La declararea unei matrici şi iniţializarea elementelor sale, se poate omite numărul maxim de
linii, în schimb, datorită modului de memorare, trebuie specificat numărul maxim de coloane,
ca în exemplul următor (construcţia are acelaşi efect ca precedenta):
int mat[][3] = {
{10, -5, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 9} };

În declaraţia cu iniţializare:
int mat[][3] = {
{1, 1},
{ -1},
{3, 2, 1}};
mat reprezintă o matrice 3 ∗ 3 (elemente întregi), ale cărei elemente se iniţializează astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2,
mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt iniţializate. Ele au valoarea zero
dacă tabloul este global şi valori iniţiale nedefinite dacă tabloul este automatic.

Construcţiile utilizate la iniţializarea tablourilor bidimensionale se extind pentru tablouri


multidimensionale, cu mai mult de doi indici.

66
CAPITOLUL 4 Tablouri

Exemplul 4.7.:
int a[2][2][3]={
{ {10, 20}, {1, -1}, {3, 4}},
{ {20, 30}, {50, -40}, {11, 12}}
};

Exerciţiul 4.2.: Să se citească de la tastatură elementele unei matrici de maxim 10 linii şi 10


coloane. Să se afişeze matricea citită.

#include <iostream.h>
void main(void)
{int A[10][10];int nr_lin, nr_col;
cout<<"Nr.linii:"; cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]=";//afişarea unui mesaj prealabil citirii
cin>>A[i][j]; }
//afişarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n';}//după afiş. elem-lor unei linii, se trece pe linia următoare
}

4.4. ŞIRURI DE CARACTERE


Şirurile de caractere sunt vectori de caractere, care au ca ultim element un terminator de şir,
caracterul null (zero ASCII), ’\0’.

Exemplul 4.8.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};//tablou de caractere
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};//şir de car., cu elementele abcd
Limbajul C/C++ permite iniţializarea unui tablou de caractere printr-o constantă şir (şir între
ghilimele), care include automat caracterul null. Deci ultima iniţializare este echivalentă cu:
char sc[5] = ”abcd”; //sau cu
char sc[] = ”abcd”;

Exemplul 4.9.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};
char sc1[5] = ”abcd”;
char s[10];
cout<<sc<<’\n’; //afişează abcd
cout<<tc<<’\n’;
//eroare: tabloul de caractere nu conţine terminatorul de şir; nu poate fi afişat ca şir
cout<<s<<’\n’; // eroare: tablou neiniţializat
cout<<sc1[2]; // afişează al treilea element din şirul sc1
sc1[1]=’K’; // elementului din şir de indice 1 i se atribuie valoarea ‘K’;

67
CAPITOLUL 4 Tablouri

4.4.1. FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE

Funcţiile pentru operaţii cu şiruri de caractere au prototipurile în header-ul <string.h>. În


continuare sunt prezentate câteva dintre funcţiile utilizate în mod frecvent:

strlen (<nume_şir>)
Funcţia returnează un număr întreg care reprezintă lungimea şirului de caractere primit ca
argument, fără a număra terminatorul de şir.

strcmp (<şir_1>, <şir_2>)


Funcţia compară cele două şiruri date ca argument şi returnează o valoare întreagă. În
BorlandC valoarea returnată este egală cu -1 (dacă <şir_1> este mai mic lexicografic decât
<şir_2>), 0 (dacă <şir_1> şi <şir_2> sunt egale lexicografic) sau 1 (dacă <şir_1> este mai
mare lexicografic decât <şir_2>); în GNUC++ valoarea returnată reprezintă diferenţa dintre
codurile ASCII ale primelor caractere care nu coincid.

strcpy (<şir_destinaţie>, <şir_sursă>)


Funcţia copie şirul sursă în şirul destinaţie. Pentru a fi posibilă copierea, lungimea şirului
destinaţie trebuie să fie mai mare sau egală cu cea a şirului sursă, altfel pot apare erori grave.

strcat (<şir_destinaţie>, <şir_sursă>)


Funcţia concatenează cele două şiruri: şirul sursă este adăugat la sfârşitul şirului destinaţie.
Tabloul care conţine şirul destinaţie trebuie să aibă suficiente elemente.

Exemplul 4.10.:
#include <iostream.h>
#include <string.h>
void main()
{char sir1[]=”abcd”, sir2[]=”abcde”, sir3[]= "abcdef”;
char sir4[]=”de”; cout<<sizeof(sir4); // afişare: 3
cout<<strcmp(sir1, sir2)<<’\n’; // afişare: -1
// Cod ’e’ = 101, Cod ’a’ = 97, Cod ’d’ = 100
cout<<strcmp(sir2, sir1)<<’\n’; //afişare: 1
cout<<strcmp(sir1, "")<<’ ';//compararea variabilei sir1 cu constanta şir vid
char str1[20]=”hello”; char str2[20]=”goodbye”; char str3[20];
int difer, lungime;
cout<<”str1=”<<str1<<” str2=”<<str2<<’\n’;
difer=strcmp(str1, str2);
if (difer == 0) cout<<”Siruri echivalente!\n”;
else if (difer>0)
cout<<str1<<”mai mare (lexicografic) decât “<<str2<<’\n’;
else
cout<<str1<<” mai mic (lexicografic) decât “<<str2<<’\n’;
cout<<”str1=”<<str1<<’\n’; cout<<”str3=”<<str3<<’\n’;
strcpy (str3, str1); cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
strcat (str3, str1);
cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
char nume[40];
strcpy(nume, "Pop");strcat(nume, " ");strcat(nume, "Oana");
cout<<"Nume="<<nume<<'\n';
for (int h=0; h<=7; h++) cout<<nume[h]<<'\n'; }
68
CAPITOLUL 4 Tablouri

Exerciţiul 4.3.: Să se citească elementele unui vector cu maxim 100 de elemente reale.
a) Să se interschimbe elementele vectorului în modul următor: primul cu ultimul, al doilea cu
penultimul, etc.
b) Să se ordoneze crescător elementele vectorului. 1 vect[i]

// a) aux 2
#define FALSE 0
#define TRUE 1 3 vect[n-i-1]
#include <iostream.h>
void main()
{ double vect[100]; Figura 4.2. Interschimbarea a
int n; //n-numărul de elemente ale vectorului două variabile
cout<<"Nr. elemente"; cin>>n; double aux;
// de completat exemplul cu secvenţa de citire a elementelor vectorului
for (int i=0; i<n/2; i++){
aux=vect[i];
vect[i]=vect[n-1-i];
vect[n-1-i]=aux;
}
// de completat exemplul cu secvenţa de afişare a vectorului
}

Pentru interschimbarea elementelor vectorului s-a folosit variabila auxiliară aux (figura 4.2.).
Fără această variabilă, la atribuirea vect[i]=vect[n-1-i], valoarea elementului vect[i]
s-ar fi pierdut. Trebuie observat, de asemenea, că variabila contor i ia valori între 0 şi n/2 (de
exemplu, dacă vectorul are 4 sau 5 elemente sunt necesare 2 interschimbări).

b) Pentru ordonarea elementelor vectorului, este prezentat un algoritm de sortare. Metoda


Bubble Sort compară fiecare element al vectorului cu cel vecin, iar dacă este cazul, le
schimbă între ele.
ALGORITM Bubble_Sort
INCEPUT
gata ← false
CIT TIMP not gata REPETA
INCEPUT
gata ← true
PENTRU i=0 LA n-2 REPETA
INCEPUT
DACA vect[i] > vect[i+1] ATUNCI
` INCEPUT
aux ← vect[i]
vect[i] ← vect[i+1]
vect[i+1] ← aux
gata ← fals
SFARSIT
SFARSIT
SFARSIT
SFARSIT

69
CAPITOLUL 4 Tablouri

// implementarea metodei BubbleSort


// constantele simbolice TRUE şi FALSE au valorile 1, respectiv 0
int gata = FALSE;int i;
while (!gata){
gata = TRUE;
for (i=0; i<=n-2; i++)
if (vect[i]>vect[i+1]){
aux=vect[i];
vect[i]=vect[i+1];
vect[i+1]=aux;
gata = FALSE;}
}

Exerciţiul 4.4.: Să se citească elementele matricilor A(MXN), B(NXP) şi C(MXN), unde


M<=10, N<=10 şi P<=10. Să se interschimbe liniile matricii A în modul următor: prima cu
ultima, a doua cu penultima, etc. Să se calculeze şi să se afişeze matricile: AT=A T , SUM=A+C,
PROD=AXB. Implementarea citirilor şi afişărilor se va completa conform exemplului dat în
capitolul 4.2.
#include <iostream.h>
void main()
{
double a[10][10], b[10][10], c[10][10];
int m,n,p,j;
cout<<"m="; cin>>m; cout<<"n="; cin>>n; cout<<"p="; cin>>p;
// de completat secvenţa de citire a elementelor matricii a, cu m linii şi n coloane
// de completat secvenţa de citire a elementelor matricii b, cu n linii şi p coloane
// de completat secvenţa de afişare a matricii a
//interschimbarea liniilor matricii A:
for (i=0; i<m/2; i++)
for (j=0; j<n; j++){
double aux=a[i][j];a[i][j]=a[m-1-i][j];a[m-1-i][j]=aux;}
cout<<"Matricea A cu liniile interschimbate:\n";
// de completat secvenţa de afişare a matricii a
// calculul matricii AT =A T
double at[10][10]; // at este matricea transpusă
for (i=0; i<n; i++)
for (j=0; j<m; j++)
at[i][j]=a[j][i];
cout<<"A transpus=\n";
// de completat secvenţa de afişare a matricii at, cu n linii si m coloane
// de completat secvenţa de citire a elementelor matricii c, cu m linii şi n coloane
// calculul matricii SUM=A+C, SUM(MxN):
double sum[10][10]; // sum este matricea sumă dintre a şi c
for (i=0; i<m; i++)
for (j=0; j<n; j++)
sum[i][j]=a[i][j]+ c[i][j];
cout<<"Matricea SUM=A+C este:\n";
// de completat secvenţa de afişare a matricii sum
double prod[10][10]; // prod este matricea produs dintre a şi b
for (i=0; i<m; i++)
for (j=0; j<p; j++){
prod[i][j]=0;
for (k=0; k<n; k++)
prod[i][j]+=a[i][k]*b[k][j];
}

70
CAPITOLUL 4 Tablouri

cout<<"Matricea produs dintre A si B este:\n";


// de completat secvenţa de afişare a matricii prod, cu m linii si p coloane
}

Se observă că fiecare element din matricea produs PROD=AXB ( A(MXN), B(NXP) ),


n −1
PROD(MXP) este de forma: prod i, j = ∑a i ,k * bk , j , unde i= 0, m − 1 şi j= 0, n − 1 .
k =0

Exerciţiul 4.5.: Să se citească elementele unei matrici de întregi şi să se afişeze matricea în


“spirală”. De exmplu, afişarea în “spirală” pentru o matrice de m linii şi n coloane va fi:
q 00 q 01 q 02 . . . q 0 ,n−1
q 10 q 11 q 12 . . . q 1,n−1
= . . . . . . . . . . . . . . ,Q m× n
q m−1,0 q m−1,1 q m−1,2 . . . q m −1,n −1

q 00 q 01 . . . q 0,n −1 q 1,n −1 . . . q m−1,n −1 q m −1, n− 2 q m −1, n−3 . . . q m−1,1 q m−1,0

q m − 2, 0 q m −3, 0 . . . q 10 q 11 . . . q 2, n − 2 q 3,n − 2 .. .

#include<stdio.h>
#include<iostream.h>
#include<conio.h>
void main()
{clrscr(); int nrl,nrc,a[10][10],i,j;cin>>nrl>>nrc);
//se va completa cu secvenţele de citire şi afişare a matricii
cout<<"Matricea citita in spirala este :\n";
int l=0,c=0,p=0,nl=nrl-1,nc=nrc-1,d;
if(nrl==nrc) d=1; //matr patratica
else d=0;
do
{ while(c<nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c++;}
while(l<nl && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l++;}
while(c>=nrc-nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c--; }
while(l>=nrl-nl+d && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l--; }
nc--; nl--;
}while(p<nrl*nrc);
}

4.5. ÎNTREBĂRI ŞI PROBLEME


ÎNTREBĂRI

1. Care este diferenţa dintre şirurile de 4. De ce tablourile reprezintă date


caractere şi vectorii de caractere? structurate?
2. Ce sunt tablourile? 5. Cum sunt memorate tabourile?
3. Prin ce se referă elementele unui tablou? 6. Cine impune tipul unui tablou?

71
CAPITOLUL 4 Tablouri

PROBLEME

1. Să se implementeze programele cu exemplele prezentate.

2. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.

3. Se citesc de la tastatură elementele unei matrici de caractere (nr. linii=nr. coloane),


A(NXN), N<=10.
a) Să se afişeze matricea A;
b) Să se formeze şi să se afişeze cuvântul format din caracterele pe pe diagonala
principală a matricii A;
c) Să se calculeze şi să se afişeze numărul de litere mari, litere mici şi cifre din matrice;
d) Să se afişeze cuvântul format din caracterele aflate pe diagonala secundară;
e) Să se afişeze procentul literelor mari, al literelor mici şi al cifrelor de pe cele 2
diagonale;
f) Să se afişeze caracterele comune aflate pe liniile p şi q (p, q < N, p şi q citite de la
tastatură);
g) Să se afişeze în ordine alfabetică, crescătoare, literele mari aflate pe coloanele impare.

4. Se citesc de la tastatură elementele unei matrici cu elemente reale, B (N X N), N<=8.


a) Să se afişeze matricea B;
b) Să se calculeze şi să se afişeze produsul elementelor de pe coloanele impare;
c) Să se calculeze şi să se afişeze matricea A, unde: A = ( B + B T ) 2 ;
d) Să se formeze şi să se afişeze vectorul V, ale cărui elemente sunt elementele pozitive
din matricea A;
e) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

f) Să se calculeze procentul elementelor pozitive aflate pe diagonala secundară;


g) Să se calculeze şi să se afişeze matricea C, unde: C = 3 * BT + B2 ;
h) Să se calculeze şi să se afişeze matricea D, unde: D = B + B 2 + B 3 + B 4
i) Să se interschimbe coloanele matricii A: prima cu ultima, a doua cu penultima, etc.

5. Se citesc de la tastatură elementele unei matrici de numere întregi C (N X N), N<=10.


a) Să se afişeze matricea C;
b) Să se calculeze şi să se afişeze procentul elementelor impare de pe liniile pare;
c) Să se calculeze şi să se afişeze matricea B, unde: B=C 2 ;
d) Să se calculeze şi să se afişeze matricea E, unde: E = (C + C T ) 2 + I, unde I este
matricea unitate;
e) Să se afle elementul minim din matricea C;
f) Să se înlocuiască elementul maxim din matricea C cu valoarea val, introdusă de la
tastatură;
g) Să se afişeze elementele matricii C care sunt numere prime;
h) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

72
CAPITOLUL 4 Tablouri

4. TABLOURI

4.1. Declararea tablourilor 4.3. Tablouri bidimensionale


4.2. Tablouri unidimensionale 4.4. Şiruri de caractere

4.1. DECLARAREA TABOURILOR


Numim tablou o colecţie (grup, mulţime ordonată) de date, de acelaşi tip, situate într-o zonă
de memorie continuă (elementele tabloului se află la adrese succesive). Tablourile sunt
variabile compuse (structurate), deoarece grupează mai multe elemente. Variabilele tablou au
nume, iar tipul tabloului este dat de tipul elementelor sale. Elementele tabloului pot fi referite
prin numele tabloului şi indicii (numere întregi) care reprezintă poziţia elementului în cadrul
tabloului.

În funcţie de numărul indicilor utilizaţi pentru a referi elementele tabloului, putem întâlni
tablouri unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri
bidimensionale).

Ca şi variabilele simple, variabilele tablou trebuie declarate înainte de utilizare.

Modul general de declarare:


<tip> <nume_tablou>[<dim_1>][[<dim_2>],…[<dim_n>]];
unde: tip reprezintă tipul elementelor tabloului; dim_1, dim_2,...,dim_n sunt numere întregi
sau expresii constante întregi (a căror valoare este evaluată la compilare), reprezentând
limitele superioare (valorile maxime posibile) ale indicilor tabloului.

Exemplul 4.1.:
//1
int vect[20]; //declararea tabloului vect, de maximum 20 de elemente, de tip int.
// Se rezervă 20*sizeof(int)=20 * 2 = 40 octeţi

//2
double p,q,tab[10];
// declararea variabilelor simple p, q şi a vectorului tab, de max. 10 elemente, tip double

//3
#define MAX 10
char tabc[MAX];
/*declararea tabloului tabc, de maximum MAX (10) elemente de tip char*/

//4
double matrice[2][3]; // declararea tabloului matrice (bidimensional),
// maximum 2 linii şi maximum 3 coloane, tip double

63
CAPITOLUL 4 Tablouri

4.2. TABLOURI UNIDIMENSIONALE


Tablourile unidimensionale sunt colecţii indexate de componente cu un singur indice
(corespund conceptului matematic de vectori). Dacă tabloul conţine maximum dim_1
elemente, indicii elementelor au valori întregi în intervalul [0, dim_1-1].
La întâlnirea declaraţiei unei variabile tablou, compilatorul alocă o zonă de memorie continuă
(dată de produsul dintre dimensiunea maximă şi numărul de octeţi corespunzător tipului
tabloului) pentru păstrarea valorilor elementelor sale. Numele tabloului poate fi utilizat în
diferite expresii şi valoarea lui este chiar adresa de început a zonei de memorie care i-a fost
alocată. Un element al unui tablou poate fi utilizat ca orice altă variabilă (în exemplul
următor, atribuirea de valori elementelor tabloului vector). Se pot efectua operaţii asupra
fiecărui element al tabloului, nu asupra întregului tablou.

Exemplul 4.2.:
// Declararea tabloului unidimensional vector
100 vector[0]
int vector[6];
101 vector[1]
// Iniţializarea elementelor tabloului 102 vector[2]
vector[0]=100;
vector[1]=101; 103 vector[3]
vector[2]=102;
vector[3]=103; 104 vector[4]
vector[4]=104; 105 vector[5]
vector[5]=105;

Exemplul 4.3.: Figura 4.1.


double alpha[5], beta[5], gama[5];
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis

Variabilele tablou, ca şi variabilele simple, pot fi iniţializate în momentul declarării:


<declaraţie_tablou>=<listă_valori>;
Lista de valori cuprinde valorile cu care vor fi iniţializate componentele tabloului, valori
separate prin virgulă şi cuprinse între acolade, ca în exemplele următoare:

Exemplul 4.4.:
//1
int vector[6]={100,101,102,103,104,105};
vector 100 101 102 103 104 105
vector[0] vector[5]
//2
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};

La declararea unui vector cu iniţializarea elementelor sale, numărul maxim de elemente ale
tabloului poate fi omis, caz în care compilatorul determină automat mărimea tabloului, în
funcţie de numărul elementelor iniţializate.

64
CAPITOLUL 4 Tablouri

Exemplul 4.5.: tab


char tab[]={ ’A’, ’C’, ’D’, ’C’}; ’A’ ’B’ ’C’ ’D’
tab[0] tab[3]

float data[5]={ 1.2, 2.3, 3.4 }; data 1.2 2.3 3.4 ? ?


data[0] data[4]
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculată astfel:
adresa_elementului_i = adresa_de_bază + i ∗ lungime_element

Exerciţiul 4.1.:
//1 Citirea elementelor unui vector:
double a[5]; int i;
for (i=0; i<5; i++)
{ cout<<”a["<<i<<”]=”;//afişarea unui mesaj prealabil citirii fiecărui element
cin>>a[i]; } //citirea valorii elementului de indice i
//Sau:
double a[20]; int i, n; cout<<”Dim. Max. =”; cin>>n;
for (i=0; i<n; i++)
{ cout<<”a[“<<i<<”]=”; cin>>a[i]; }
//2 Afişarea elementelor unui vector:
cout<<”Vectorul introdus este:\n”;
for (i=0; i<n; i++) cout<<a[i]<<’ ’;
//3 Afişarea elementelor unui vector în ordine inversă:
cout<<”Elementele vectorului în ordine inversă:\n”;
for (i=n-1; i>=0; i--) cout<<a[i]<<’ ’;
//3 Vectorul sumă (c) a vectorilor a şi b, cu acelaşi număr de elemente, n:
for (i=0; i<n; i++) c[i]=a[i]+b[i];
//4 Vectorul diferenţă (c) a vectorilor a şi b, cu acelaşi număr de elemente:
for (i=0; i<n; i++) c[i]=a[i] - b[i];
//5 Produsul scalar (p) a vectorilor a şi b, cu acelaşi număr de elemente:
n −1
p= ∑ a i ∗ bi double p=0;
i =0
for (i=0; i<n; i++) p += a[i] ∗ b[i];

4.3. TABLOURI BIDIMENSIONALE

Din punct de vedere conceptual, elementele unui tablou bidimensional sunt plasate în spaţiu
pe două direcţii. Matricea reprezintă o aplicaţie naturală a tablourilor bidimensionale.
În matematică:

q 11 q 12 q 13 . . . q 1n
q 21 q 22 q 23 . . . q 2n
Q = ,Q m× n
. . . . . . . . . . . . .
q m1 q m2 q m3 . . . q mn

65
CAPITOLUL 4 Tablouri

În limbajele C/C++, indicii de linie şi de coloană pornesc de la 0:

q 00 q 01 q 02 . . . q 0,n−1

Q = q 10 q 11 q 12 . . . q 1,n−1 ,Q m× n
. . . . . . . . . . . . . .
q m−1,0 q m−1,1 q m−1,2 . . . q m−1,n −1

Exemplul 4.6.:
double q[3][2]; // declararea matricii q, cu maxim3 linii şi 2 coloane, tip double

În memorie, elementele unei matrici sunt memorate pe linii:


q 00 q 01 q 10 q 11 q 20 q 21 . . .
Dacă notăm cu k poziţia în memorie a unui element, valoarea lui k = i ∗ m + j (unde m
este numărul maxim de linii, i este indicele de linie, j este indicele de coloană).

q[0][0] q[0][1] q[0][2] . . q[0][n-1] q[1][0] . . .q[m-1][0] . . q[m-1][n-1]

Dacă se doreşte iniţializarea elementelor unei matrici în momentul declarării acesteia, se


poate proceda astfel:
int mat[4][3] = {
{10, -50, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 19} };
Prin această construcţie, elementele matricii mat se iniţializează în modul următor:
mat[0][0]=10, mat[0][1]=-50, mat[0][2]=3
mat[1][0]=32, mat[1][1]=20, mat[1][2]=1
mat[2][0]=-1, mat[2][1]=1, mat[2][2]=-2
mat[3][0]=7, mat[3][1]=-8, mat[3][2]=19

La declararea unei matrici şi iniţializarea elementelor sale, se poate omite numărul maxim de
linii, în schimb, datorită modului de memorare, trebuie specificat numărul maxim de coloane,
ca în exemplul următor (construcţia are acelaşi efect ca precedenta):
int mat[][3] = {
{10, -5, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 9} };

În declaraţia cu iniţializare:
int mat[][3] = {
{1, 1},
{ -1},
{3, 2, 1}};
mat reprezintă o matrice 3 ∗ 3 (elemente întregi), ale cărei elemente se iniţializează astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2,
mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt iniţializate. Ele au valoarea zero
dacă tabloul este global şi valori iniţiale nedefinite dacă tabloul este automatic.

Construcţiile utilizate la iniţializarea tablourilor bidimensionale se extind pentru tablouri


multidimensionale, cu mai mult de doi indici.

66
CAPITOLUL 4 Tablouri

Exemplul 4.7.:
int a[2][2][3]={
{ {10, 20}, {1, -1}, {3, 4}},
{ {20, 30}, {50, -40}, {11, 12}}
};

Exerciţiul 4.2.: Să se citească de la tastatură elementele unei matrici de maxim 10 linii şi 10


coloane. Să se afişeze matricea citită.

#include <iostream.h>
void main(void)
{int A[10][10];int nr_lin, nr_col;
cout<<"Nr.linii:"; cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]=";//afişarea unui mesaj prealabil citirii
cin>>A[i][j]; }
//afişarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n';}//după afiş. elem-lor unei linii, se trece pe linia următoare
}

4.4. ŞIRURI DE CARACTERE


Şirurile de caractere sunt vectori de caractere, care au ca ultim element un terminator de şir,
caracterul null (zero ASCII), ’\0’.

Exemplul 4.8.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};//tablou de caractere
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};//şir de car., cu elementele abcd
Limbajul C/C++ permite iniţializarea unui tablou de caractere printr-o constantă şir (şir între
ghilimele), care include automat caracterul null. Deci ultima iniţializare este echivalentă cu:
char sc[5] = ”abcd”; //sau cu
char sc[] = ”abcd”;

Exemplul 4.9.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};
char sc1[5] = ”abcd”;
char s[10];
cout<<sc<<’\n’; //afişează abcd
cout<<tc<<’\n’;
//eroare: tabloul de caractere nu conţine terminatorul de şir; nu poate fi afişat ca şir
cout<<s<<’\n’; // eroare: tablou neiniţializat
cout<<sc1[2]; // afişează al treilea element din şirul sc1
sc1[1]=’K’; // elementului din şir de indice 1 i se atribuie valoarea ‘K’;

67
CAPITOLUL 4 Tablouri

4.4.1. FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE

Funcţiile pentru operaţii cu şiruri de caractere au prototipurile în header-ul <string.h>. În


continuare sunt prezentate câteva dintre funcţiile utilizate în mod frecvent:

strlen (<nume_şir>)
Funcţia returnează un număr întreg care reprezintă lungimea şirului de caractere primit ca
argument, fără a număra terminatorul de şir.

strcmp (<şir_1>, <şir_2>)


Funcţia compară cele două şiruri date ca argument şi returnează o valoare întreagă. În
BorlandC valoarea returnată este egală cu -1 (dacă <şir_1> este mai mic lexicografic decât
<şir_2>), 0 (dacă <şir_1> şi <şir_2> sunt egale lexicografic) sau 1 (dacă <şir_1> este mai
mare lexicografic decât <şir_2>); în GNUC++ valoarea returnată reprezintă diferenţa dintre
codurile ASCII ale primelor caractere care nu coincid.

strcpy (<şir_destinaţie>, <şir_sursă>)


Funcţia copie şirul sursă în şirul destinaţie. Pentru a fi posibilă copierea, lungimea şirului
destinaţie trebuie să fie mai mare sau egală cu cea a şirului sursă, altfel pot apare erori grave.

strcat (<şir_destinaţie>, <şir_sursă>)


Funcţia concatenează cele două şiruri: şirul sursă este adăugat la sfârşitul şirului destinaţie.
Tabloul care conţine şirul destinaţie trebuie să aibă suficiente elemente.

Exemplul 4.10.:
#include <iostream.h>
#include <string.h>
void main()
{char sir1[]=”abcd”, sir2[]=”abcde”, sir3[]= "abcdef”;
char sir4[]=”de”; cout<<sizeof(sir4); // afişare: 3
cout<<strcmp(sir1, sir2)<<’\n’; // afişare: -1
// Cod ’e’ = 101, Cod ’a’ = 97, Cod ’d’ = 100
cout<<strcmp(sir2, sir1)<<’\n’; //afişare: 1
cout<<strcmp(sir1, "")<<’ ';//compararea variabilei sir1 cu constanta şir vid
char str1[20]=”hello”; char str2[20]=”goodbye”; char str3[20];
int difer, lungime;
cout<<”str1=”<<str1<<” str2=”<<str2<<’\n’;
difer=strcmp(str1, str2);
if (difer == 0) cout<<”Siruri echivalente!\n”;
else if (difer>0)
cout<<str1<<”mai mare (lexicografic) decât “<<str2<<’\n’;
else
cout<<str1<<” mai mic (lexicografic) decât “<<str2<<’\n’;
cout<<”str1=”<<str1<<’\n’; cout<<”str3=”<<str3<<’\n’;
strcpy (str3, str1); cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
strcat (str3, str1);
cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
char nume[40];
strcpy(nume, "Pop");strcat(nume, " ");strcat(nume, "Oana");
cout<<"Nume="<<nume<<'\n';
for (int h=0; h<=7; h++) cout<<nume[h]<<'\n'; }
68
CAPITOLUL 4 Tablouri

Exerciţiul 4.3.: Să se citească elementele unui vector cu maxim 100 de elemente reale.
a) Să se interschimbe elementele vectorului în modul următor: primul cu ultimul, al doilea cu
penultimul, etc.
b) Să se ordoneze crescător elementele vectorului. 1 vect[i]

// a) aux 2
#define FALSE 0
#define TRUE 1 3 vect[n-i-1]
#include <iostream.h>
void main()
{ double vect[100]; Figura 4.2. Interschimbarea a
int n; //n-numărul de elemente ale vectorului două variabile
cout<<"Nr. elemente"; cin>>n; double aux;
// de completat exemplul cu secvenţa de citire a elementelor vectorului
for (int i=0; i<n/2; i++){
aux=vect[i];
vect[i]=vect[n-1-i];
vect[n-1-i]=aux;
}
// de completat exemplul cu secvenţa de afişare a vectorului
}

Pentru interschimbarea elementelor vectorului s-a folosit variabila auxiliară aux (figura 4.2.).
Fără această variabilă, la atribuirea vect[i]=vect[n-1-i], valoarea elementului vect[i]
s-ar fi pierdut. Trebuie observat, de asemenea, că variabila contor i ia valori între 0 şi n/2 (de
exemplu, dacă vectorul are 4 sau 5 elemente sunt necesare 2 interschimbări).

b) Pentru ordonarea elementelor vectorului, este prezentat un algoritm de sortare. Metoda


Bubble Sort compară fiecare element al vectorului cu cel vecin, iar dacă este cazul, le
schimbă între ele.
ALGORITM Bubble_Sort
INCEPUT
gata ← false
CIT TIMP not gata REPETA
INCEPUT
gata ← true
PENTRU i=0 LA n-2 REPETA
INCEPUT
DACA vect[i] > vect[i+1] ATUNCI
` INCEPUT
aux ← vect[i]
vect[i] ← vect[i+1]
vect[i+1] ← aux
gata ← fals
SFARSIT
SFARSIT
SFARSIT
SFARSIT

69
CAPITOLUL 4 Tablouri

// implementarea metodei BubbleSort


// constantele simbolice TRUE şi FALSE au valorile 1, respectiv 0
int gata = FALSE;int i;
while (!gata){
gata = TRUE;
for (i=0; i<=n-2; i++)
if (vect[i]>vect[i+1]){
aux=vect[i];
vect[i]=vect[i+1];
vect[i+1]=aux;
gata = FALSE;}
}

Exerciţiul 4.4.: Să se citească elementele matricilor A(MXN), B(NXP) şi C(MXN), unde


M<=10, N<=10 şi P<=10. Să se interschimbe liniile matricii A în modul următor: prima cu
ultima, a doua cu penultima, etc. Să se calculeze şi să se afişeze matricile: AT=A T , SUM=A+C,
PROD=AXB. Implementarea citirilor şi afişărilor se va completa conform exemplului dat în
capitolul 4.2.
#include <iostream.h>
void main()
{
double a[10][10], b[10][10], c[10][10];
int m,n,p,j;
cout<<"m="; cin>>m; cout<<"n="; cin>>n; cout<<"p="; cin>>p;
// de completat secvenţa de citire a elementelor matricii a, cu m linii şi n coloane
// de completat secvenţa de citire a elementelor matricii b, cu n linii şi p coloane
// de completat secvenţa de afişare a matricii a
//interschimbarea liniilor matricii A:
for (i=0; i<m/2; i++)
for (j=0; j<n; j++){
double aux=a[i][j];a[i][j]=a[m-1-i][j];a[m-1-i][j]=aux;}
cout<<"Matricea A cu liniile interschimbate:\n";
// de completat secvenţa de afişare a matricii a
// calculul matricii AT =A T
double at[10][10]; // at este matricea transpusă
for (i=0; i<n; i++)
for (j=0; j<m; j++)
at[i][j]=a[j][i];
cout<<"A transpus=\n";
// de completat secvenţa de afişare a matricii at, cu n linii si m coloane
// de completat secvenţa de citire a elementelor matricii c, cu m linii şi n coloane
// calculul matricii SUM=A+C, SUM(MxN):
double sum[10][10]; // sum este matricea sumă dintre a şi c
for (i=0; i<m; i++)
for (j=0; j<n; j++)
sum[i][j]=a[i][j]+ c[i][j];
cout<<"Matricea SUM=A+C este:\n";
// de completat secvenţa de afişare a matricii sum
double prod[10][10]; // prod este matricea produs dintre a şi b
for (i=0; i<m; i++)
for (j=0; j<p; j++){
prod[i][j]=0;
for (k=0; k<n; k++)
prod[i][j]+=a[i][k]*b[k][j];
}

70
CAPITOLUL 4 Tablouri

cout<<"Matricea produs dintre A si B este:\n";


// de completat secvenţa de afişare a matricii prod, cu m linii si p coloane
}

Se observă că fiecare element din matricea produs PROD=AXB ( A(MXN), B(NXP) ),


n −1
PROD(MXP) este de forma: prod i, j = ∑a i ,k * bk , j , unde i= 0, m − 1 şi j= 0, n − 1 .
k =0

Exerciţiul 4.5.: Să se citească elementele unei matrici de întregi şi să se afişeze matricea în


“spirală”. De exmplu, afişarea în “spirală” pentru o matrice de m linii şi n coloane va fi:
q 00 q 01 q 02 . . . q 0 ,n−1
q 10 q 11 q 12 . . . q 1,n−1
= . . . . . . . . . . . . . . ,Q m× n
q m−1,0 q m−1,1 q m−1,2 . . . q m −1,n −1

q 00 q 01 . . . q 0,n −1 q 1,n −1 . . . q m−1,n −1 q m −1, n− 2 q m −1, n−3 . . . q m−1,1 q m−1,0

q m − 2, 0 q m −3, 0 . . . q 10 q 11 . . . q 2, n − 2 q 3,n − 2 .. .

#include<stdio.h>
#include<iostream.h>
#include<conio.h>
void main()
{clrscr(); int nrl,nrc,a[10][10],i,j;cin>>nrl>>nrc);
//se va completa cu secvenţele de citire şi afişare a matricii
cout<<"Matricea citita in spirala este :\n";
int l=0,c=0,p=0,nl=nrl-1,nc=nrc-1,d;
if(nrl==nrc) d=1; //matr patratica
else d=0;
do
{ while(c<nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c++;}
while(l<nl && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l++;}
while(c>=nrc-nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c--; }
while(l>=nrl-nl+d && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l--; }
nc--; nl--;
}while(p<nrl*nrc);
}

4.5. ÎNTREBĂRI ŞI PROBLEME


ÎNTREBĂRI

1. Care este diferenţa dintre şirurile de 4. De ce tablourile reprezintă date


caractere şi vectorii de caractere? structurate?
2. Ce sunt tablourile? 5. Cum sunt memorate tabourile?
3. Prin ce se referă elementele unui tablou? 6. Cine impune tipul unui tablou?

71
CAPITOLUL 4 Tablouri

PROBLEME

1. Să se implementeze programele cu exemplele prezentate.

2. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.

3. Se citesc de la tastatură elementele unei matrici de caractere (nr. linii=nr. coloane),


A(NXN), N<=10.
a) Să se afişeze matricea A;
b) Să se formeze şi să se afişeze cuvântul format din caracterele pe pe diagonala
principală a matricii A;
c) Să se calculeze şi să se afişeze numărul de litere mari, litere mici şi cifre din matrice;
d) Să se afişeze cuvântul format din caracterele aflate pe diagonala secundară;
e) Să se afişeze procentul literelor mari, al literelor mici şi al cifrelor de pe cele 2
diagonale;
f) Să se afişeze caracterele comune aflate pe liniile p şi q (p, q < N, p şi q citite de la
tastatură);
g) Să se afişeze în ordine alfabetică, crescătoare, literele mari aflate pe coloanele impare.

4. Se citesc de la tastatură elementele unei matrici cu elemente reale, B (N X N), N<=8.


a) Să se afişeze matricea B;
b) Să se calculeze şi să se afişeze produsul elementelor de pe coloanele impare;
c) Să se calculeze şi să se afişeze matricea A, unde: A = ( B + B T ) 2 ;
d) Să se formeze şi să se afişeze vectorul V, ale cărui elemente sunt elementele pozitive
din matricea A;
e) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

f) Să se calculeze procentul elementelor pozitive aflate pe diagonala secundară;


g) Să se calculeze şi să se afişeze matricea C, unde: C = 3 * BT + B2 ;
h) Să se calculeze şi să se afişeze matricea D, unde: D = B + B 2 + B 3 + B 4
i) Să se interschimbe coloanele matricii A: prima cu ultima, a doua cu penultima, etc.

5. Se citesc de la tastatură elementele unei matrici de numere întregi C (N X N), N<=10.


a) Să se afişeze matricea C;
b) Să se calculeze şi să se afişeze procentul elementelor impare de pe liniile pare;
c) Să se calculeze şi să se afişeze matricea B, unde: B=C 2 ;
d) Să se calculeze şi să se afişeze matricea E, unde: E = (C + C T ) 2 + I, unde I este
matricea unitate;
e) Să se afle elementul minim din matricea C;
f) Să se înlocuiască elementul maxim din matricea C cu valoarea val, introdusă de la
tastatură;
g) Să se afişeze elementele matricii C care sunt numere prime;
h) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

72
CAPITOLUL 4 Tablouri

4. TABLOURI

4.1. Declararea tablourilor 4.3. Tablouri bidimensionale


4.2. Tablouri unidimensionale 4.4. Şiruri de caractere

4.1. DECLARAREA TABOURILOR


Numim tablou o colecţie (grup, mulţime ordonată) de date, de acelaşi tip, situate într-o zonă
de memorie continuă (elementele tabloului se află la adrese succesive). Tablourile sunt
variabile compuse (structurate), deoarece grupează mai multe elemente. Variabilele tablou au
nume, iar tipul tabloului este dat de tipul elementelor sale. Elementele tabloului pot fi referite
prin numele tabloului şi indicii (numere întregi) care reprezintă poziţia elementului în cadrul
tabloului.

În funcţie de numărul indicilor utilizaţi pentru a referi elementele tabloului, putem întâlni
tablouri unidimensionale (vectorii) sau multidimensionale (matricile sunt tablouri
bidimensionale).

Ca şi variabilele simple, variabilele tablou trebuie declarate înainte de utilizare.

Modul general de declarare:


<tip> <nume_tablou>[<dim_1>][[<dim_2>],…[<dim_n>]];
unde: tip reprezintă tipul elementelor tabloului; dim_1, dim_2,...,dim_n sunt numere întregi
sau expresii constante întregi (a căror valoare este evaluată la compilare), reprezentând
limitele superioare (valorile maxime posibile) ale indicilor tabloului.

Exemplul 4.1.:
//1
int vect[20]; //declararea tabloului vect, de maximum 20 de elemente, de tip int.
// Se rezervă 20*sizeof(int)=20 * 2 = 40 octeţi

//2
double p,q,tab[10];
// declararea variabilelor simple p, q şi a vectorului tab, de max. 10 elemente, tip double

//3
#define MAX 10
char tabc[MAX];
/*declararea tabloului tabc, de maximum MAX (10) elemente de tip char*/

//4
double matrice[2][3]; // declararea tabloului matrice (bidimensional),
// maximum 2 linii şi maximum 3 coloane, tip double

63
CAPITOLUL 4 Tablouri

4.2. TABLOURI UNIDIMENSIONALE


Tablourile unidimensionale sunt colecţii indexate de componente cu un singur indice
(corespund conceptului matematic de vectori). Dacă tabloul conţine maximum dim_1
elemente, indicii elementelor au valori întregi în intervalul [0, dim_1-1].
La întâlnirea declaraţiei unei variabile tablou, compilatorul alocă o zonă de memorie continuă
(dată de produsul dintre dimensiunea maximă şi numărul de octeţi corespunzător tipului
tabloului) pentru păstrarea valorilor elementelor sale. Numele tabloului poate fi utilizat în
diferite expresii şi valoarea lui este chiar adresa de început a zonei de memorie care i-a fost
alocată. Un element al unui tablou poate fi utilizat ca orice altă variabilă (în exemplul
următor, atribuirea de valori elementelor tabloului vector). Se pot efectua operaţii asupra
fiecărui element al tabloului, nu asupra întregului tablou.

Exemplul 4.2.:
// Declararea tabloului unidimensional vector
100 vector[0]
int vector[6];
101 vector[1]
// Iniţializarea elementelor tabloului 102 vector[2]
vector[0]=100;
vector[1]=101; 103 vector[3]
vector[2]=102;
vector[3]=103; 104 vector[4]
vector[4]=104; 105 vector[5]
vector[5]=105;

Exemplul 4.3.: Figura 4.1.


double alpha[5], beta[5], gama[5];
int i=2;
alpha[2*i-1] = 5.78;
alpha[0]=2*beta[i]+3.5;
gama[i]=aplha[i]+beta[i]; //permis
gama=alpha+beta; //nepermis

Variabilele tablou, ca şi variabilele simple, pot fi iniţializate în momentul declarării:


<declaraţie_tablou>=<listă_valori>;
Lista de valori cuprinde valorile cu care vor fi iniţializate componentele tabloului, valori
separate prin virgulă şi cuprinse între acolade, ca în exemplele următoare:

Exemplul 4.4.:
//1
int vector[6]={100,101,102,103,104,105};
vector 100 101 102 103 104 105
vector[0] vector[5]
//2
double x=9.8;
double a[5]={1.2, 3.5, x, x-1, 7.5};

La declararea unui vector cu iniţializarea elementelor sale, numărul maxim de elemente ale
tabloului poate fi omis, caz în care compilatorul determină automat mărimea tabloului, în
funcţie de numărul elementelor iniţializate.

64
CAPITOLUL 4 Tablouri

Exemplul 4.5.: tab


char tab[]={ ’A’, ’C’, ’D’, ’C’}; ’A’ ’B’ ’C’ ’D’
tab[0] tab[3]

float data[5]={ 1.2, 2.3, 3.4 }; data 1.2 2.3 3.4 ? ?


data[0] data[4]
Adresa elementului de indice i dintr-un tablou unidimensional poate fi calculată astfel:
adresa_elementului_i = adresa_de_bază + i ∗ lungime_element

Exerciţiul 4.1.:
//1 Citirea elementelor unui vector:
double a[5]; int i;
for (i=0; i<5; i++)
{ cout<<”a["<<i<<”]=”;//afişarea unui mesaj prealabil citirii fiecărui element
cin>>a[i]; } //citirea valorii elementului de indice i
//Sau:
double a[20]; int i, n; cout<<”Dim. Max. =”; cin>>n;
for (i=0; i<n; i++)
{ cout<<”a[“<<i<<”]=”; cin>>a[i]; }
//2 Afişarea elementelor unui vector:
cout<<”Vectorul introdus este:\n”;
for (i=0; i<n; i++) cout<<a[i]<<’ ’;
//3 Afişarea elementelor unui vector în ordine inversă:
cout<<”Elementele vectorului în ordine inversă:\n”;
for (i=n-1; i>=0; i--) cout<<a[i]<<’ ’;
//3 Vectorul sumă (c) a vectorilor a şi b, cu acelaşi număr de elemente, n:
for (i=0; i<n; i++) c[i]=a[i]+b[i];
//4 Vectorul diferenţă (c) a vectorilor a şi b, cu acelaşi număr de elemente:
for (i=0; i<n; i++) c[i]=a[i] - b[i];
//5 Produsul scalar (p) a vectorilor a şi b, cu acelaşi număr de elemente:
n −1
p= ∑ a i ∗ bi double p=0;
i =0
for (i=0; i<n; i++) p += a[i] ∗ b[i];

4.3. TABLOURI BIDIMENSIONALE

Din punct de vedere conceptual, elementele unui tablou bidimensional sunt plasate în spaţiu
pe două direcţii. Matricea reprezintă o aplicaţie naturală a tablourilor bidimensionale.
În matematică:

q 11 q 12 q 13 . . . q 1n
q 21 q 22 q 23 . . . q 2n
Q = ,Q m× n
. . . . . . . . . . . . .
q m1 q m2 q m3 . . . q mn

65
CAPITOLUL 4 Tablouri

În limbajele C/C++, indicii de linie şi de coloană pornesc de la 0:

q 00 q 01 q 02 . . . q 0,n−1

Q = q 10 q 11 q 12 . . . q 1,n−1 ,Q m× n
. . . . . . . . . . . . . .
q m−1,0 q m−1,1 q m−1,2 . . . q m−1,n −1

Exemplul 4.6.:
double q[3][2]; // declararea matricii q, cu maxim3 linii şi 2 coloane, tip double

În memorie, elementele unei matrici sunt memorate pe linii:


q 00 q 01 q 10 q 11 q 20 q 21 . . .
Dacă notăm cu k poziţia în memorie a unui element, valoarea lui k = i ∗ m + j (unde m
este numărul maxim de linii, i este indicele de linie, j este indicele de coloană).

q[0][0] q[0][1] q[0][2] . . q[0][n-1] q[1][0] . . .q[m-1][0] . . q[m-1][n-1]

Dacă se doreşte iniţializarea elementelor unei matrici în momentul declarării acesteia, se


poate proceda astfel:
int mat[4][3] = {
{10, -50, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 19} };
Prin această construcţie, elementele matricii mat se iniţializează în modul următor:
mat[0][0]=10, mat[0][1]=-50, mat[0][2]=3
mat[1][0]=32, mat[1][1]=20, mat[1][2]=1
mat[2][0]=-1, mat[2][1]=1, mat[2][2]=-2
mat[3][0]=7, mat[3][1]=-8, mat[3][2]=19

La declararea unei matrici şi iniţializarea elementelor sale, se poate omite numărul maxim de
linii, în schimb, datorită modului de memorare, trebuie specificat numărul maxim de coloane,
ca în exemplul următor (construcţia are acelaşi efect ca precedenta):
int mat[][3] = {
{10, -5, 3},
{32, 20, 1},
{-1, 1, -2},
{7, -8, 9} };

În declaraţia cu iniţializare:
int mat[][3] = {
{1, 1},
{ -1},
{3, 2, 1}};
mat reprezintă o matrice 3 ∗ 3 (elemente întregi), ale cărei elemente se iniţializează astfel:
mat[0][0]=1, mat[0][1]=1, mat[1][0]=-1, mat[2][0]=3, mat[2][1]=2,
mat[2][2]=1
Elementele mat[0][2], mat[1][1], mat[1][2] nu sunt iniţializate. Ele au valoarea zero
dacă tabloul este global şi valori iniţiale nedefinite dacă tabloul este automatic.

Construcţiile utilizate la iniţializarea tablourilor bidimensionale se extind pentru tablouri


multidimensionale, cu mai mult de doi indici.

66
CAPITOLUL 4 Tablouri

Exemplul 4.7.:
int a[2][2][3]={
{ {10, 20}, {1, -1}, {3, 4}},
{ {20, 30}, {50, -40}, {11, 12}}
};

Exerciţiul 4.2.: Să se citească de la tastatură elementele unei matrici de maxim 10 linii şi 10


coloane. Să se afişeze matricea citită.

#include <iostream.h>
void main(void)
{int A[10][10];int nr_lin, nr_col;
cout<<"Nr.linii:"; cin>>nr_lin;
cout<<"Nr. coloane:"; cin>>nr_col;int i, j;
//citirea elementelor unei matrici
for (i=0; i<nr_lin; i++)
for (j=0; j<nr_col; j++) {
cout<<"A["<<i<<","<<j<<"]=";//afişarea unui mesaj prealabil citirii
cin>>A[i][j]; }
//afişarea elementelor matricii
for (i=0; i<nr_lin; i++) {
for (j=0; j<nr_col; j++)
cout<<A[i][j]<<'\t';
cout<<'\n';}//după afiş. elem-lor unei linii, se trece pe linia următoare
}

4.4. ŞIRURI DE CARACTERE


Şirurile de caractere sunt vectori de caractere, care au ca ultim element un terminator de şir,
caracterul null (zero ASCII), ’\0’.

Exemplul 4.8.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};//tablou de caractere
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};//şir de car., cu elementele abcd
Limbajul C/C++ permite iniţializarea unui tablou de caractere printr-o constantă şir (şir între
ghilimele), care include automat caracterul null. Deci ultima iniţializare este echivalentă cu:
char sc[5] = ”abcd”; //sau cu
char sc[] = ”abcd”;

Exemplul 4.9.:
char tc[5] = {’a’, ’b’, ’c’, ’d’, ’e’};
char sc[5] = {’a’, ’b’, ’c’, ’d’, ’\0’};
char sc1[5] = ”abcd”;
char s[10];
cout<<sc<<’\n’; //afişează abcd
cout<<tc<<’\n’;
//eroare: tabloul de caractere nu conţine terminatorul de şir; nu poate fi afişat ca şir
cout<<s<<’\n’; // eroare: tablou neiniţializat
cout<<sc1[2]; // afişează al treilea element din şirul sc1
sc1[1]=’K’; // elementului din şir de indice 1 i se atribuie valoarea ‘K’;

67
CAPITOLUL 4 Tablouri

4.4.1. FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE

Funcţiile pentru operaţii cu şiruri de caractere au prototipurile în header-ul <string.h>. În


continuare sunt prezentate câteva dintre funcţiile utilizate în mod frecvent:

strlen (<nume_şir>)
Funcţia returnează un număr întreg care reprezintă lungimea şirului de caractere primit ca
argument, fără a număra terminatorul de şir.

strcmp (<şir_1>, <şir_2>)


Funcţia compară cele două şiruri date ca argument şi returnează o valoare întreagă. În
BorlandC valoarea returnată este egală cu -1 (dacă <şir_1> este mai mic lexicografic decât
<şir_2>), 0 (dacă <şir_1> şi <şir_2> sunt egale lexicografic) sau 1 (dacă <şir_1> este mai
mare lexicografic decât <şir_2>); în GNUC++ valoarea returnată reprezintă diferenţa dintre
codurile ASCII ale primelor caractere care nu coincid.

strcpy (<şir_destinaţie>, <şir_sursă>)


Funcţia copie şirul sursă în şirul destinaţie. Pentru a fi posibilă copierea, lungimea şirului
destinaţie trebuie să fie mai mare sau egală cu cea a şirului sursă, altfel pot apare erori grave.

strcat (<şir_destinaţie>, <şir_sursă>)


Funcţia concatenează cele două şiruri: şirul sursă este adăugat la sfârşitul şirului destinaţie.
Tabloul care conţine şirul destinaţie trebuie să aibă suficiente elemente.

Exemplul 4.10.:
#include <iostream.h>
#include <string.h>
void main()
{char sir1[]=”abcd”, sir2[]=”abcde”, sir3[]= "abcdef”;
char sir4[]=”de”; cout<<sizeof(sir4); // afişare: 3
cout<<strcmp(sir1, sir2)<<’\n’; // afişare: -1
// Cod ’e’ = 101, Cod ’a’ = 97, Cod ’d’ = 100
cout<<strcmp(sir2, sir1)<<’\n’; //afişare: 1
cout<<strcmp(sir1, "")<<’ ';//compararea variabilei sir1 cu constanta şir vid
char str1[20]=”hello”; char str2[20]=”goodbye”; char str3[20];
int difer, lungime;
cout<<”str1=”<<str1<<” str2=”<<str2<<’\n’;
difer=strcmp(str1, str2);
if (difer == 0) cout<<”Siruri echivalente!\n”;
else if (difer>0)
cout<<str1<<”mai mare (lexicografic) decât “<<str2<<’\n’;
else
cout<<str1<<” mai mic (lexicografic) decât “<<str2<<’\n’;
cout<<”str1=”<<str1<<’\n’; cout<<”str3=”<<str3<<’\n’;
strcpy (str3, str1); cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
strcat (str3, str1);
cout<<”str1=”<<str1<<’\n’;
cout<<”str3=”<<str3<<’\n’;
char nume[40];
strcpy(nume, "Pop");strcat(nume, " ");strcat(nume, "Oana");
cout<<"Nume="<<nume<<'\n';
for (int h=0; h<=7; h++) cout<<nume[h]<<'\n'; }
68
CAPITOLUL 4 Tablouri

Exerciţiul 4.3.: Să se citească elementele unui vector cu maxim 100 de elemente reale.
a) Să se interschimbe elementele vectorului în modul următor: primul cu ultimul, al doilea cu
penultimul, etc.
b) Să se ordoneze crescător elementele vectorului. 1 vect[i]

// a) aux 2
#define FALSE 0
#define TRUE 1 3 vect[n-i-1]
#include <iostream.h>
void main()
{ double vect[100]; Figura 4.2. Interschimbarea a
int n; //n-numărul de elemente ale vectorului două variabile
cout<<"Nr. elemente"; cin>>n; double aux;
// de completat exemplul cu secvenţa de citire a elementelor vectorului
for (int i=0; i<n/2; i++){
aux=vect[i];
vect[i]=vect[n-1-i];
vect[n-1-i]=aux;
}
// de completat exemplul cu secvenţa de afişare a vectorului
}

Pentru interschimbarea elementelor vectorului s-a folosit variabila auxiliară aux (figura 4.2.).
Fără această variabilă, la atribuirea vect[i]=vect[n-1-i], valoarea elementului vect[i]
s-ar fi pierdut. Trebuie observat, de asemenea, că variabila contor i ia valori între 0 şi n/2 (de
exemplu, dacă vectorul are 4 sau 5 elemente sunt necesare 2 interschimbări).

b) Pentru ordonarea elementelor vectorului, este prezentat un algoritm de sortare. Metoda


Bubble Sort compară fiecare element al vectorului cu cel vecin, iar dacă este cazul, le
schimbă între ele.
ALGORITM Bubble_Sort
INCEPUT
gata ← false
CIT TIMP not gata REPETA
INCEPUT
gata ← true
PENTRU i=0 LA n-2 REPETA
INCEPUT
DACA vect[i] > vect[i+1] ATUNCI
` INCEPUT
aux ← vect[i]
vect[i] ← vect[i+1]
vect[i+1] ← aux
gata ← fals
SFARSIT
SFARSIT
SFARSIT
SFARSIT

69
CAPITOLUL 4 Tablouri

// implementarea metodei BubbleSort


// constantele simbolice TRUE şi FALSE au valorile 1, respectiv 0
int gata = FALSE;int i;
while (!gata){
gata = TRUE;
for (i=0; i<=n-2; i++)
if (vect[i]>vect[i+1]){
aux=vect[i];
vect[i]=vect[i+1];
vect[i+1]=aux;
gata = FALSE;}
}

Exerciţiul 4.4.: Să se citească elementele matricilor A(MXN), B(NXP) şi C(MXN), unde


M<=10, N<=10 şi P<=10. Să se interschimbe liniile matricii A în modul următor: prima cu
ultima, a doua cu penultima, etc. Să se calculeze şi să se afişeze matricile: AT=A T , SUM=A+C,
PROD=AXB. Implementarea citirilor şi afişărilor se va completa conform exemplului dat în
capitolul 4.2.
#include <iostream.h>
void main()
{
double a[10][10], b[10][10], c[10][10];
int m,n,p,j;
cout<<"m="; cin>>m; cout<<"n="; cin>>n; cout<<"p="; cin>>p;
// de completat secvenţa de citire a elementelor matricii a, cu m linii şi n coloane
// de completat secvenţa de citire a elementelor matricii b, cu n linii şi p coloane
// de completat secvenţa de afişare a matricii a
//interschimbarea liniilor matricii A:
for (i=0; i<m/2; i++)
for (j=0; j<n; j++){
double aux=a[i][j];a[i][j]=a[m-1-i][j];a[m-1-i][j]=aux;}
cout<<"Matricea A cu liniile interschimbate:\n";
// de completat secvenţa de afişare a matricii a
// calculul matricii AT =A T
double at[10][10]; // at este matricea transpusă
for (i=0; i<n; i++)
for (j=0; j<m; j++)
at[i][j]=a[j][i];
cout<<"A transpus=\n";
// de completat secvenţa de afişare a matricii at, cu n linii si m coloane
// de completat secvenţa de citire a elementelor matricii c, cu m linii şi n coloane
// calculul matricii SUM=A+C, SUM(MxN):
double sum[10][10]; // sum este matricea sumă dintre a şi c
for (i=0; i<m; i++)
for (j=0; j<n; j++)
sum[i][j]=a[i][j]+ c[i][j];
cout<<"Matricea SUM=A+C este:\n";
// de completat secvenţa de afişare a matricii sum
double prod[10][10]; // prod este matricea produs dintre a şi b
for (i=0; i<m; i++)
for (j=0; j<p; j++){
prod[i][j]=0;
for (k=0; k<n; k++)
prod[i][j]+=a[i][k]*b[k][j];
}

70
CAPITOLUL 4 Tablouri

cout<<"Matricea produs dintre A si B este:\n";


// de completat secvenţa de afişare a matricii prod, cu m linii si p coloane
}

Se observă că fiecare element din matricea produs PROD=AXB ( A(MXN), B(NXP) ),


n −1
PROD(MXP) este de forma: prod i, j = ∑a i ,k * bk , j , unde i= 0, m − 1 şi j= 0, n − 1 .
k =0

Exerciţiul 4.5.: Să se citească elementele unei matrici de întregi şi să se afişeze matricea în


“spirală”. De exmplu, afişarea în “spirală” pentru o matrice de m linii şi n coloane va fi:
q 00 q 01 q 02 . . . q 0 ,n−1
q 10 q 11 q 12 . . . q 1,n−1
= . . . . . . . . . . . . . . ,Q m× n
q m−1,0 q m−1,1 q m−1,2 . . . q m −1,n −1

q 00 q 01 . . . q 0,n −1 q 1,n −1 . . . q m−1,n −1 q m −1, n− 2 q m −1, n−3 . . . q m−1,1 q m−1,0

q m − 2, 0 q m −3, 0 . . . q 10 q 11 . . . q 2, n − 2 q 3,n − 2 .. .

#include<stdio.h>
#include<iostream.h>
#include<conio.h>
void main()
{clrscr(); int nrl,nrc,a[10][10],i,j;cin>>nrl>>nrc);
//se va completa cu secvenţele de citire şi afişare a matricii
cout<<"Matricea citita in spirala este :\n";
int l=0,c=0,p=0,nl=nrl-1,nc=nrc-1,d;
if(nrl==nrc) d=1; //matr patratica
else d=0;
do
{ while(c<nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c++;}
while(l<nl && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l++;}
while(c>=nrc-nc && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; c--; }
while(l>=nrl-nl+d && p<nrl*nrc)
{ cout<<a[l][c]<<" "; p++; l--; }
nc--; nl--;
}while(p<nrl*nrc);
}

4.5. ÎNTREBĂRI ŞI PROBLEME


ÎNTREBĂRI

1. Care este diferenţa dintre şirurile de 4. De ce tablourile reprezintă date


caractere şi vectorii de caractere? structurate?
2. Ce sunt tablourile? 5. Cum sunt memorate tabourile?
3. Prin ce se referă elementele unui tablou? 6. Cine impune tipul unui tablou?

71
CAPITOLUL 4 Tablouri

PROBLEME

1. Să se implementeze programele cu exemplele prezentate.

2. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.

3. Se citesc de la tastatură elementele unei matrici de caractere (nr. linii=nr. coloane),


A(NXN), N<=10.
a) Să se afişeze matricea A;
b) Să se formeze şi să se afişeze cuvântul format din caracterele pe pe diagonala
principală a matricii A;
c) Să se calculeze şi să se afişeze numărul de litere mari, litere mici şi cifre din matrice;
d) Să se afişeze cuvântul format din caracterele aflate pe diagonala secundară;
e) Să se afişeze procentul literelor mari, al literelor mici şi al cifrelor de pe cele 2
diagonale;
f) Să se afişeze caracterele comune aflate pe liniile p şi q (p, q < N, p şi q citite de la
tastatură);
g) Să se afişeze în ordine alfabetică, crescătoare, literele mari aflate pe coloanele impare.

4. Se citesc de la tastatură elementele unei matrici cu elemente reale, B (N X N), N<=8.


a) Să se afişeze matricea B;
b) Să se calculeze şi să se afişeze produsul elementelor de pe coloanele impare;
c) Să se calculeze şi să se afişeze matricea A, unde: A = ( B + B T ) 2 ;
d) Să se formeze şi să se afişeze vectorul V, ale cărui elemente sunt elementele pozitive
din matricea A;
e) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

f) Să se calculeze procentul elementelor pozitive aflate pe diagonala secundară;


g) Să se calculeze şi să se afişeze matricea C, unde: C = 3 * BT + B2 ;
h) Să se calculeze şi să se afişeze matricea D, unde: D = B + B 2 + B 3 + B 4
i) Să se interschimbe coloanele matricii A: prima cu ultima, a doua cu penultima, etc.

5. Se citesc de la tastatură elementele unei matrici de numere întregi C (N X N), N<=10.


a) Să se afişeze matricea C;
b) Să se calculeze şi să se afişeze procentul elementelor impare de pe liniile pare;
c) Să se calculeze şi să se afişeze matricea B, unde: B=C 2 ;
d) Să se calculeze şi să se afişeze matricea E, unde: E = (C + C T ) 2 + I, unde I este
matricea unitate;
e) Să se afle elementul minim din matricea C;
f) Să se înlocuiască elementul maxim din matricea C cu valoarea val, introdusă de la
tastatură;
g) Să se afişeze elementele matricii C care sunt numere prime;
h) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în
triunghiurile haşurate:

72
CAPITOLUL 6 Funcţii

6. FUNCŢII

6.1. Structura unei funcţii 6.6. Supraîncărcarea funcţiilor


6.2. Transferul parametrilor unei funcţii 6.7. Clase de memorare
6.3. Funcţii cu parametri impliciţi 6.8. Moduri de alocare a memoriei
6.4. Funcţii cu număr variabil de 6.9. Funcţii recursive
parametri 6.10. Pointeri către funcţii
6.5. Funcţii predefinite 6.11. Întrebări şi probleme

6.1. STRUCTURA UNEI FUNCŢII


Un program în limbajul C/C++ este un ansamblu de funcţii, fiecare dintre acestea efectuând o
activitate bine definită. Din punct de vedere conceptual, funcţia reprezintă o aplicaţie definită
pe o mulţime D (D=mulţimea, domeniul de definiţie), cu valori în mulţimea C (C=mulţimea
de valori, codomeniul), care îndeplineşte condiţia că oricărui element din D îi corespunde un
unic element din C.

Funcţiile comunică prin argumente: ele primesc ca parametri (argumente) datele de intrare,
efectuează prelucrările descrise în corpul funcţiei asupra acestora şi pot returna o valoare
(rezultatul, datele de ieşire). Execuţia oricărui program începe cu funcţia principală, numită
main. Funcţiile pot fi descrise în cadrul aceluiaşi fişier, sau în fişiere diferite, care sunt testate
şi compilate separat, asamblarea lor realizându-se cu ajutorul linkeditorului de legături.

O funcţie este formata din antet şi corp:


<antet_funcţie>
{
<corpul_funcţiei>
}
Sau:
<tip_val_ret> <nume_func>(<lista_declaraţiilor_param_ formali>)
{
<declaraţii_variabile_locale>
<instrucţiuni>
[return <valoare>;]
}

Prima linie reprezintă antetul funcţiei, în care se indică: tipul funcţiei, numele acesteia şi lista
declaraţiilor parametrilor formali. La fel ca un operand sau o expresie, o funcţie are un tip, dat
de tipul valorii returnate de funcţie în funcţia apelantă. Dacă funcţia nu întoarce nici o valoare,
în locul tip_val_ret se specifică void. Dacă tip_val_ret lipseşte, se consideră, implicit, că
acesta este int. Nume_func este un identificator.
Lista_declaraţiilor_param_formali (încadrată între paranteze rotunde) constă într-o listă
(enumerare) care conţine tipul şi identificatorul fiecărui parametru de intrare, despărţite prin
virgulă. Tipul unui parametru poate fi oricare, chiar şi tipul pointer. Dacă lista parametrilor
formali este vidă, în antet, după numele funcţiei, apar doar parantezele ( ), sau (void).

85
CAPITOLUL 6 Funcţii

Corpul funcţiei este un bloc, care implementează algoritmul de calcul folosit de către funcţie.
În corpul funcţiei apar (în orice ordine) declaraţii pentru variabilele locale şi instrucţiuni. Dacă
funcţia întoarce o valoare, se foloseşte instrucţiunea return <valoare>. La execuţie, la
întâlnirea acestei instrucţiuni, se revine în funcţia apelantă.

6.1.1. DECLARAŢII ŞI DEFINIŢII DE FUNCŢII

În limbajul C/C++ se utilizează declaraţii şi definiţii de funcţii.


Declaraţia constă în specificarea antetului funcţiei şi are rolul de a informa compilatorul
asupra tipului, numelui funcţiei şi a listei declaraţiilor parametrilor formali (în care se poate
indica doar tipul parametrilor formali, nu şi numele acestora). Fiind doar declarate, funcţiile
pot fi utilizate, corpul acestora urmând să se specifice anterior. Declaraţiile de funcţii din care
lipsesc numele parametrilor formali.se numesc prototipuri.
Definiţia conţine antetul funcţiei şi corpul acesteia. Nu este admisă definirea unei funcţii în
corpul altei funcţii.

O formă învechită a antetului unei funcţii este aceea în care se specifică în lista parametrilor
formali doar numele acestora, nu şi tipul, ceea ce poate conduce la erori.

<tip_val_ret> <nume_func> (<lista_parametrilor_ formali>)


<declararea_parametrilor_formali>
{ <declaraţii_variabile_locale>
<instrucţiuni>
[return <valoare>;]
}

6.1.2. APELUL FUNCŢIILOR

În cazul în care o funcţie nu returnează nici o valoare, ea poate fi apelată printr-o construcţie
urmată de punct şi virgulă, numită instrucţiune de apel, de forma:
<nume_funcţie> (<lista_parametrilor_efectivi>);
În cazul în care funcţia returnează o valoare, apelul funcţiei va constitui operandul unei
expresii.

La apelul unei funcţii, parametrii efectivi trebuie să corespundă cu cei formali, ca ordine şi tip.
În momentul apelului unei funcţii, se atribuie parametrilor formali valorile parametrilor
efectivi, după care se execută instrucţiunile din corpul funcţiei. La revenirea din funcţie,
controlul este redat funcţiei apelante, şi execuţia continuă cu instrucţiunea următoare (din
funcţia apelantă) instrucţiunii de apel.

Parametrii declaraţi în antetul unei funcţii sunt numiţi formali, pentru a sublinia faptul că ei
nu reprezintă valori concrete, ci numai ţin locul acestora pentru a putea exprima procesul de
calcul realizat prin funcţie. Ei se concretizează la execuţie prin apelurile funcţiei.
Parametrii folosiţi la apelul unei funcţii sunt parametri reali, efectivi, concreţi, iar valorile lor
vor fi atribuite parametrilor formali, la execuţie. Utilizarea parametrilor formali la
implementarea funcţiilor şi atribuirea de valori concrete pentru ei, la execuţie, reprezintă un
prim nivel de abstractizare în programare. Acest mod de programare se numeşte programare
procedurală şi realizează un proces de abstractizare prin parametri.

86
CAPITOLUL 6 Funcţii

Variabilele declarate în interiorul unei funcţii, cât şi parametrii formali ai acesteia nu pot fi
accesaţi decât în interiorul acesteia. Aceste variabile sunt numite variabile locale şi nu pot fi
accesate din alte funcţii. Domeniul de vizibilitate a unei variabile este porţiunea de cod la a
cărei execuţie variabila respectivă este accesibilă. Deci, domeniul de vizibilitate a unei
variabile locale este funcţia în care ea a fost definită (vezi şi paragraful 6.7.).

Exemplu:
int f1(void)
{ double a,b; int c;
. . .
return c; // a, b, c - variabile locale, vizibile doar în corpul funcţiei
}
void main()
{ . . . . . . // variabile a şi b nu sunt accesibile în main()
}

Dacă în interiorul unei funcţii există instrucţiuni compuse (blocuri) care conţin declaraţii de
variabile, aceste variabile nu sunt vizibile în afara blocului.

Exemplu:
void main()
{ int a=1, b=2;
cout << "a=”<<a<<” b=”<<b<<” c=”<<c’\n’; // a=1 b=2, c nedeclarat
. . . . . . . .
{ int a=5; b=6; int c=9;
cout << "a=”<<a<<” b=”<<b<<’\n’; // a=5 b=6 c=9
. . . . . . . .
}
cout << "a=”<<a<<” b=”<<b<<” c=”<<c’\n’; // a=1 b=6, c nedeclarat
. . . . . . . . . . . .
}

Exerciţiul 1: Să se scrie următorul program (pentru înţelegerea modului de apel al unei


funcţii) şi să se urmărească rezultatele execuţiei acestuia.
#include <iostream.h>
void f_afis(void)
{
cout<<”Se execută instrucţiunile din corpul funcţiei\n”;
double a=3, b=9.4; cout<<a<<”*”<<b<<”=”<<a*b<<’\n’;
cout<<”Ieşire din funcţie!\n”; }

void main()
{
cout<<”Intrare în funcţia principală\n”;
f_afis( ); //apelul funcţiei f_afis, printr-o instrucţiune de apel
cout<<”Terminat MAIN!\n”; }

Exerciţiul 2: Să se scrie un program care citeşte două numere şi afişează cel mai mare divizor
comun al acestora, folosind o funcţie îl calculează.
#include <iostream.h>
int cmmdc(int x, int y)
{if (x==0 || y==1 || x==1 || y==0) return 1;
if (x<0) x=-x;
if (y<0) y=-y;

87
CAPITOLUL 6 Funcţii

while (x != 0){
if ( y > x ) {int z=x; x=y; y=z; }
x-=y; // sau: x%=y;
}
return y;}

void main()
{
int n1,n2; cout<<”n1=”;cin>>n1; cout<<”n2=”;cin>>n2;
int diviz=cmmdc(n1,n2);
cout<<”Cel mai mare divizor comun al nr-lor:”<<n1<<” şi ”;
cout<<n2<<” este:”<<diviz<<’\n’;
/* sau:
cout<<”Cel mai mare divizor comun al nr-lor:”<<n1<<” şi ”;
cout<<n2<<” este:”<<cmmdc(n1,n2)<<’\n’;*/ }

Exerciţiul 3: Să se calculeze valoarea lui z, ştiind că u (real) şi m (natural) sunt citite de la


tastatură: z=2 ω ( 2 ϕ (u) + 1, m) + ω (2 u 2 - 3, m + 1), unde:
n
ω (x,n)= ∑ sin(ix ) cos(2ix ) , ϕ (x)= 1 + e − x , ω : R x N → R, ϕ : R → R
2

i =1

#include <iostream.h>
#include <math.h>
double omega(double x, int n)
{ double s=0; int i;
for (i=1; i<=n; i++) s+=sin(i*x)*cos(i*x);
return s; }

double psi( double x)


{ return sqrt( 1 + exp (- pow (x, 2)));}

void main()
{double u, z; int m; cout<<”u=”; cin>>u; cout<<”m=”; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1);
cout<<”z=”<<z<<’\n’; }

În exemplele anterioare, înainte de apelul funcţiilor folosite, acestea au fost definite


(antet+corp). Să modificăm implementarea exerciţiului 3, folosind declaraţiile funcţiilor
omega şi psi.
Există însă şi cazuri în care definirea unei funcţii nu poate fi făcută înaintea apelului acesteia
(cazul funcţiilor care se apelează unele pe altele), şi atunci, sunt absolut necesare declaraţiile
funcţiilor.

Exerciţiu:
#include <iostream.h>
#include <math.h>
double omega(double, int);
// prototipul funcţiei omega - antet din care lipsesc numele parametrilor formali
double psi(double); // prototipul funcţiei psi
void main()
{double u, z; int m; cout<<”u=”; cin>>u; cout<<”m=”; cin>>m;
z=2*omega(2* psi(u) + 1, m) + omega(2*pow(u,2) - 3, m+1);
cout<<”z=”<<z<<’\n’; }

88
CAPITOLUL 6 Funcţii

double omega(double x, int i) // definiţia funcţiei omega


{ double s=0; int i;
for (i=1; i<=n; i++) s += sin (i*x) * cos (i*x);
return s; }

double psi( double x) // definiţia funcţiei psi


{ return sqrt( 1 + exp (- pow (x, 2))); }

Prototipurile funcţiilor din biblioteci (predefinite), cum ar fi exemplul funcţiilor matematice,


se găsesc în headere (de exemplu, math.h). Utilizarea aceszor funcţii impune doar includerea
în program a headerului asociat, cu ajutorul directivei preprocesor #include. În plus,
programatorul îşi poate crea propriile headere, care să conţină declaraţii de funcţii, tipuri
globale, macrodefiniţii, etc.

Similar cu declaraţia de variabilă, domeniul de vizibilitate a unei funcţii este:


 fişierul sursă, dacă declaraţia funcţiei apare în afara oricărei funcţii (la nivel global);
 funcţia sau blocul în care apare declaraţia.

6.2. TRANSFERUL PARAMETRILOR UNEI FUNCŢII


Să ne reamintim faptul că funcţiile comunică între ele prin argumente (parametri). Transferul
(transmiterea) parametrilor către funcţiile apelate se poate realiza în următoarele moduri:
 Transfer prin valoare (specific limbajului C);
 Transfer prin pointeri;
 Transfer prin referinţă (specific limbajului C++).

6.2.1. TRANFERUL PARAMETRILOR PRIN VALOARE

În toate exemplele anterioare, parametrii - de la funcţia apelantă către funcţia apelată - au fost
transmişi prin valoare. În momentul apelului unei funcţii, se transmit valorile parametrilor
efectivi, reali, care vor fi atribuite parametrilor formali. Deci procedeul de transmitere a
parametrilor prin valoare constă în încărcarea valorii parametrilor efectivi în zona de
memorie a parametrilor formali (în stivă). La apelul unei funcţii, parametrii reali trebuie să
corespundă - ca ordine şi tip - cu cei formali.

Exerciţiu: Să se scrie următorul program (care ilustrează transmiterea parametrilor prin


valoare) şi să se urmărească rezultatele execuţiei acestuia.
void f1(float intr,int nr)// intr, nr - parametri formali data
{for (int i=0; i<nr;i++) intr *= 2.0; 1.5
cout<<”Val. Param. intr=”<<intr<<’\n’;// intr=12
} Copiere valoare
void main()
{ 1.5
float data=1.5; f1(data,3);
intr
// apelul funcţiei f1, cu parametrii efectivi data şi 3
cout<<”data=”<<data<<’\n’;
// data=1.5 (nemodificat) Figura 6.1. Transmiterea
} parametrilor prin valoare

89
CAPITOLUL 6 Funcţii

Fiecare argument efectiv utilizat la apelul funcţiei este evaluat, iar valoarea obţinută este
atribuită parametrului formal corespunzător. În funcţia apelată, parametrul formal reprezintă o
copie locală a valorii parametrului efectiv. Orice modificare a valorii parametrului formal în
funcţia apelată (printr-o operaţie din corpul funcţiei), va determina doar modificarea copiei
locale a parametrului efectiv (figura 6.1.), neinfluenţând în nici un mod valoarea parametrului
efectiv corespunzător. Faptul că variabila din programul apelant (parametrul efectiv) şi
parametrul formal sunt obiecte distincte, poate constitui un mijloc util de protecţie. În
exerciţiul anterior, în corpul funcţiei f1, valoarea parametrului formal intr este modificată
(alterată) prin instrucţiunea ciclică for, însă valoarea parametrului efectiv (data) din funcţia
apelantă, rămâne nemodificată.
În cazul transmiterii parametrilor prin valoare, parametrii efectivi pot fi chiar expresii.
Acestea sunt evaluate, iar valoarea lor va fi atribuită, la apel, parametrilor formali (vezi
exemplul următor).

Exemplu:
double psi(int a, double b)
{if (a > 0) return a*b*2;
else return -a+3*b; }
void main()
{ int x=4; double y=12.6, z;
z=psi ( 3*x+9, y-5) + 28; //parametrii efectivi sunt expresii
cout<<”z=”<<z<<’\n’; }

Transferul valorii parametrilor este însoţit de eventuale conversii de tip. Aceste conversii pot
fi realizate automat de compilator, în urma verificării apelului de funcţie, pe baza
informaţiilor despre funcţie, sau pot fi conversii explicite, specificate de programator, prin
operatorul “cast”.

Exemplu:
float f1(double, int);
void main()
{
int a, b; float g=f1(a, b); // conversie automată: int a -> double a
float h=f1( (double) a, b); // conversie explicită
}

Limbajul C este numit limbajul apelului prin valoare, deoarece, de fiecare dată când o
funcţie transmite argumente unei funcţii apelate, este transmisă, de fapt, o copie a parametrilor
efectivi. În acest mod, dacă valoarea parametrilor formali (iniţializaţi cu valorile parametrilor
efectivi) se modifică în interiorul funcţiei apelate, valorile parametrilor efectivi din funcţia
apelantă nu vor fi afectate.

6.2.2. TRANSFERUL PARAMETRILOR PRIN POINTERI

Există şi situaţii în care parametrii transmişi unei funcţii sunt pointeri (variabile care conţin
adrese). În aceste cazuri, parametrii formali ai funcţiei apelate vor fi iniţializaţi cu valorile
parametrilor efectivi, deci cu valorile unor adrese. Astfel, funcţia apelată poate modifica
conţinutul locaţiilor spre care pointează argumentele (pointerii).

90
CAPITOLUL 6 Funcţii

Exerciţiu: Să se citească 2 valori întregi şi să se interschimbe cele două valori. Se va folosi o


funcţie de interschimbare.
#include <iostream.h>
void schimbă(int *, int *); //prototipul functiei schimba
void main()
{int x, y, *ptx, *pty; ptx=&x; pty=&y; cout<<”x=”;cin>>x;
cout<<”y=”;cin>>y;cout<<”x=”<<x;cout<<”y=”<<y<<’\n’;
cout<<"Adr. lui x:"<<&x<<" Val lui x:"<<x<<'\n';
cout<<"Adr.lui y:"<<&y<<" Val y:"<<y<<'\n';
cout<<"Val. lui ptx:"<<ptx;
cout<<" Cont. locaţiei spre care pointează ptx:”<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<"Cont. locaţiei spre care pointează pty:"<<*pty;
schimba(ptx, pty);
// SAU: schimba(&x, &y);
cout<<"Adr. lui x:"<<&x<<" %x Val lui x: %d\n”, &x, x);
cout<<"Adr. y:"<<&y<<" Val lui y:"<<y<<'\n';
cout<<"Val. lui ptx:"<<ptx;
cout<<" Cont. locaţiei spre care pointează ptx:”<<*ptx<<'\n';
cout<<"Val. lui pty:"<<pty;
cout<<" Cont. locaţiei spre care pointează pty:"<<*pty<<'\n';
}
void schimbă( int *p1, int *p2)
{cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaţiei spre care pointează p1:"<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaţiei spre care pointează p2:"<<*p2<<'\n';
int t = *p1; // int *t ; t=p1;
*p2=*p1; *p1=t;
cout<<"Val. lui p1:"<<p1;
cout<<" Cont. locaţiei spre care pointează p1:”<<*p1<<'\n';
cout<<"Val. lui p2:"<<p2;
cout<<" Cont. locaţiei spre care pointează p2:"<<*p2<<'\n'; }

Dacă parametrii funcţiei schimbă ar fi fost transmişi prin valoare, în corpul acesteia s-ar fi
interschimbat copiile parametrilor formali, iar în funcţia main modificările asupra
parametrilor transmişi nu s-ar fi păstrat. În figura 6.2. este prezentat mecanismul de
transmitere a parametrilor prin pointeri.
x y
0x34 10 30 0x5A 30 10 Parametrii formali p1 şi p2, la apelul
funcţiei schimbă, primesc valorile
ptx pty
parametrilor efectivi ptx şi pty
0x34 0x5A
( adresele variabilelor x şi y). Astfel,
variabilele pointer p1 şi ptx,
respectiv p2 şi pty pointează către x
şi y. Modificările asupra valorilor
variabilelor x şi y realizate în corpul
p1 p2 funcţiei schimbă, se păstrează şi în
0x34 0x5A funcţia main.

Figura 6.2. Transmiterea parametrilor unei funcţii prin pointeri

91
CAPITOLUL 6 Funcţii

Exerciţiu: Să se scrie următorul program şi să se urmărească rezultatele execuţiei acestuia.


#include <iostream.h>
double omega (long *k)
{cout<<"k=", k);
// k conţine adr. lui i În funcţia main În funcţia omega
cout<<”*k=”; k
cout<<k<<’\n’; i
0x451 (adr.lui i)
// *k = 35001 0x451 35001 (apoi 35017)
double s=2+(*k)-3;
// s = 35000
cout<<”s=”<<s<<’\n’; w s
*k+=17; // *k = 35017 35000 35000
cout<<”*k=”<<*k;
cout<<’\n’;
return s; } Figura 6.3. Transferul parametrilor prin pointeri
void main()
{long i = 35001; double w;
cout<<"i="<<i;cout<<" Adr.lui i:"<<&i<<'\n';
w=omega(&i); cout<<”i=”<<i<< w=”<<w<<’\n’; }// i = 350017 w = 35000

6.2.2.1. Funcţii care returnează pointeri

Însăşi valoarea returnată de o funcţie poate fi un pointer, aşa cum se observă în exemplul
următor:

Exemplu:
#include <iostream.h>
double *f (double *w, int k)
{ // w conţine adr. de început a vectorului a
cout<<"w="<<w<<" *w="<<*w<<'\n'; // w= adr. lui a ;*w = a[0]=10
return w+=k; /*incrementeaza pointerului w cu 2(val. lui k); deci w pointează
către elementul de indice 2 din vectorul a*/
}

void main()
{double a[10]={10,1,2,3,4,5,6,7,8,9}; int i=2;
cout<<"Adr. lui a este:"<<a;
double *pa=a; // double *pa; pa=a;
cout<<"pa="<<pa<<'\n';// pointerul pa conţine adresa de început a tabloului a
// a[i] = * (a + i)
// &a[i] = a + i
pa=f(a,i); cout<<"pa="<<pa<<" *pa="<<*pa<<'\n';
// pa conţine adr. lui a[2], adica adr. a + 2 * sizeof(double);
*pa=1000;
cout<<"pa="<<pa<<"*pa="<<*pa<<'\n';//pa=0x *pa=1000
for (int j=0; j<10; j++)
cout<<"a["<<j<<"]="<<*(a+j)<<'\t';
// a[0]=10 a[1]=1 a[2]=1000 a[3]=3 a[4]=4 a[5]=5 a[6]=6 a[7]=7 a[8]=8 a[9]=9
}

92
CAPITOLUL 6 Funcţii

6.2.3. TRANSFERUL PARAMETRILOR PRIN REFERINŢĂ

6.2.3.1. Variabile referinţă

În limbajul C++ variabila referinţă reprezintă un sinonim (alt nume) al altei variabile. În
exemplul următor definim variabila br, variabilă referinţă către variabila b. Variabilele b şi
br se găsesc, în memorie, la aceeaşi adresă (pentru variabila referinţă br nu se alocă spaţiu de
memorie) şi sunt variabile sinonime. Aşa cum se observă din exemplu, în orice expresie,
înlocuirea variabilei b cu br (sau invers) nu va modifica valoarea expresiei.

Exemplu:
#include <stdio.h> b, br 7 12
#include <iostream.h>
void main()
{ c 12
int b,c;
int &br=b; //br referinţă la variabila b
br=7; Figura 6.4. Variabilele referinţă b, br
cout<<"b="<<b<<'\n'; //b=7
cout<<"br="<<br<<'\n'; //br=7
cout<<"Adr. br este:"<<&br; //Adr. br este:0xfff4
printf("Adr. b este:"<<&b<<'\n'; //Adr. b este:0xfff4
b=12; cout<<"br="<<br<<'\n'; //br=12
cout<<"b="<<b<<'\n'; //b=12
c=br; cout<<"c="<<c<<'\n'; //c=12
}

În limbajul C++, se face diferenţă între variabilele pointer (au ca valoare o adresă) şi cele
referinţă (nume diferite pentru aceeaşi zonă de memorie).

Exemplu:
int a=100, b=1000, *pa=&a, &ra=a; pa=&b;
//pa variabilă pointer, ra referinţă, sinonim al variabilei a

Pentru variabilele întregi a, b şi pointerul pa se alocă spaţiu de memorie, în timp ce pentru


pentru variabila referinţă ra nu se alocă spatiu în memorie (ra este un alt nume dat variabilei
a). Valoarea pointerului pa poate fi modificată (pa = &b, deci noua valoare a lui pa este
adresa variabilei b), în timp ce referinta ra rămâne permanent asociată variabilei a, neputând
fi modificată.

6.2.3.2. Parametrii transmişi prin referinţă

În limbajul C++, parametrii unei funcţii pot fi variabile referinţă. În acest mod de transmitere
a parametrilor, unui parametru formal i se poate asocia (atribui) chiar obiectul parametrului
efectiv. Astfel, parametrul efectiv poate fi modificat direct prin operaţiile din corpul funcţiei
apelate (vezi exemplul următor şi figura 6.5., care ilustrează modul de transmitere a
parametrilor funcţiei f: primul parametru este transmis prin valoare, al doilea - prin referinţă).

93
CAPITOLUL 6 Funcţii

Exemplu:
#include <iostream.h>
#include <stdio.h>
void f(int, int &);
void main()
{int count = 7, index = 12;
printf("Val.inainte apel f:count=%3d index=%3d\n", count, index);
f(count, index);
printf("Val. dupa apel f:count=%3d index=%3d\n", count, index);
}
count index, in2
void f(int in1, int &in2)
{ in1 = in1 + 100; 7 12 112
in2 = in2 + 100;
printf("In corp f: %3d %3d\n", in1, in2);} Copiere valoare
//Rezultatele execuţiei
7 107
// Val.inainte apel f: count= 7 index= 12
in1
// In corp f: 107 112
// Val. dupa apel f: count= 7 index=112 Figura 6.5.
Exemplul clasic pentru explicarea apelului prin referinţă este cel al funcţiei de permutare
(interschimbare) a două variabile.

Modul de implementare a funcţiei de interschimbare în care acesteia i se transmit parametrii


prin valoare (ca în exemplul următor, funcţia schimb) este inadecvat, deoarece modificarea
parametrilor formali (interschimbarea acestora) nu va determina şi modificarea celor efectivi.

Fie funcţia schimb definită astfel:


void schimb (double x, double y) Parametri funcţiei schimb sunt transmişi
{ double t=x; x=y; y=t; } prin valoare: parametrilor formali x, y li se
atribuie (la apel) valorile parametrilor
void main()
efectivi a, b. Funcţia schimb permută
{ double a=4.7, b=9.7;
. . . . . . . . . . . valorile parametrilor formali x şi y, dar
schimb(a, b); // apel funcţie permutarea nu are efect asupra parametrilor
. . . . . . . . . . . } efectivi a şi b.

Pentru ca funcţia de interschimbare să poată permuta valorile parametrilor efectivi, în limbajul


C/C++ parametrii formali trebuie să fie pointeri către valorile care trebuie interschimbate:

void pschimb(double *x, double *y) Se atribuie pointerilor x şi y (parametrii


{ int t=*x; *x=*y; *y=t; }
formali) valorile pointerilor pa, pb
void main() (parametrii efectivi), deci adresele
{ double a=4.7, b=9.7; variabilelor a şi b. Funcţia pschimb
. . . . . . . . . . . permută valorile spre care pointează
pschimb(&a, &b); // apel funcţie pointerii x şi y, deci valorile lui a şi b
/* SAU: (figura 6.5).
double *pa, *pb;
pa=&a; pb=&b;
pschimb(pa, pb);*/
. . . . . . . . . . . }

94
CAPITOLUL 6 Funcţii

pschimb main rschimb main


*x &a a 4.7 9.7
4.7 9.7
aux 4.7 x,a
*y &b b 9.7 4.7
y;b 9.7 4.7
aux 4.7

Figura 6.6. Transferul parametrilor Figura 6.7. Transferul parametrilor


prin pointeri prin referinţă

În limbajul C++ funcţia de interschimbare poate fi implementată astfel încât parametrii


formali să fie variabile referinţe.

void rschimb(double &x, double &y)


{ int t=x; x=y; y=t; }

void main()
{ double a=4.7, b=9.7;
. . . . . . . . . . . . . . .
rschimb(a, b); // apel funcţie
. . . . . . . . . . . . . . . }

În acest caz, x şi y sunt sinonime cu a şi b (nume diferite pentru aceleaşi grupuri de locaţii de
memorie). Interschimbarea valorilor variabilelor de x şi y înseamnă, de fapt, chiar
interschimbarea valorilor variabilelor a şi b (fig. 6.7.).

Comparând funcţiile pschimb şi rschimb, se observă că diferenţa dintre ele constă în modul
de declarare a parametrilor formali. În cazul funcţiei pschimb parametrii formali sunt
pointeri (de tip double*), iar la apelul funcţiei, aceştia primesc valorile parametrilor efectivi,
deci adresele variabilelor care vor fi interschimbate. În cazul funcţiei rschimb, parametrii
formali sunt referinţe către date de tip double, referă aceleaşi locaţii de memorie (sunt
sinonime pentru) parametrii efectivi, deci interschimbarea din corpul funcţiei acţionează chiar
asupra parametrilor efectivi.

Comparând cele trei moduri de transmitere a parametrilor către o funcţie, se poate observa:
1. La apelul prin valoare transferul datelor este unidirecţional, adică valorile se transferă
numai de la funcţia apelantă către cea apelată. La apelul prin referinţă transferul datelor
este bidirecţional, deoarece o modificare a parametrilor formali determină modificarea
parametrilor efectivi, care sunt sinonime (au nume diferite, dar referă aceleaşi locaţii de
memorie).
2. La transmiterea parametrilor prin valoare, ca parametrii efectivi pot apare expresii sau
nume de variabile. La transmiterea parametrilor prin referinţă, ca parametri efectivi nu pot
apare expresii, ci doar nume de variabile. La transmiterea parametrilor prin pointeri, ca
parametri efectivi pot apare expresii de pointeri.
3. Transmiterea parametrilor unei funcţii prin referinţă este specifică limbajului C++.
4. Limbajul C este numit limbajul apelului prin valoare. Apelul poate deveni, însă, apel prin
referinţă în cazul variabilelor simple, folosind pointeri, sau aşa cum vom vedea în
paragraful 6.4., în cazul în care parametru efectiv este un tablou.
5. În limbajul C++ se poate alege, pentru fiecare parametru, tipul de apel: prin valoare sau
prin referinţă, aşa cum ilustrează exemplele următoare.

95
CAPITOLUL 6 Funcţii

Exerciţiul 1: Să se scrie următorul program şi să se urmărească rezultatele execuţiei acestuia.


#include <iostream.h>
#include <stdio.h>

double func(int a, double b, double *c, double &d)


{cout<<"*********************** func *****************\n";
cout<<"a="<<a<<" b="<<b; //a=7 (a=t prin val); b=21 (b=u prin val)
cout<<" c="<<c<<" *c="<<*c<<'\n';// c=ffe(c=w=&u) *c=21
cout<<" d="<<d; //d=17
cout<<"Adr d="<<&d<<'\n'; //Adr d=ffe6 (adr d=adr v)
a+=2; cout<<"a="<<a<<'\n'; //a=9
d=2*a+b; cout<<"d="<<d<<'\n'; //d=39
*c=500;cout<<" c="<<c<<" *c="<<*c<<'\n'; // c=ffe(c=w=&u) *c=500
cout<<"*********************** func *****************\n";
return b+(*c); }

void main()
{cout<<"\n\n \n MAIN MAIN";
int t=7;double u=12, v=17, *w, z; cout<<"u="<<u<<'\n'; //u=12
w=&u;*w=21;cout<<"t="<<t<<" u="<<u<<" v="<<v;
//t=7 u=21 v=17
*w=21;cout<<" *w="<<*w<<" u="<<u<<'\n'; //*w=21 u=21
printf("w=%x Adr. u=%x\n",w,&u); //w=ffee Adr. u=ffee
printf("v=%f Adr v=%x\n",v,&v); //v=17.000000 Adr v=ffe6
z=func(t,u,w, v);
cout<<"t="<<t<<"u="<<u<<"v="<<v; //t=7 u=500 v=39 (v=d)
cout<<" *w="<<*w<<" z="<<z<<'\n'; //*w=500 w=ffee z=521
printf(" w=%x\n",w);}

Exemplul ilustrează următoarele probleme:


La apelul funcţiei func, parametrii t şi u sunt transmişi prin valoare, deci valorile lor vor fi
atribuite parametrilor formali a şi b. Orice modificare a parametrilor formali a şi b, în funcţia
func, nu va avea efect asupra parametrilor efectivi t şi u. Al treilea parametru formal al
funcţiei func este pointer, deci c este de tip double * (pointer către double), sau *c este de
tip double.
La apelul funcţiei, valoarea pointerului w (adresa lui u : w=&u) este atribuită pointerului c.
Deci pointerii w şi c conţin aceeaşi adresă, pointând către un real. Dacă s-ar modifica valoarea
spre care pointează c în func (vezi instrucţiunile din comentariu *c=500), această modificare
ar fi reflectată şi în funcţia apelantă, deoarece pointerul w are acelaşi conţinut ca şi pointerul c,
deci pointează către aceeaşi locaţie de memorie. Parametrul formal d se transmite prin
referinţă, deci, d şi v sunt sinonime (memorate la aceeaşi adresă). Modificarea valorii
variabilei d în func înseamnă, de fapt, modificarea variabilei d (parametrul efectiv din main).

Exerciţiul 2: Să se scrie următorul program (care ilustrează legătura dintre pointeri şi vectori)
şi să se urmărească rezultatele execuţiei acestuia.
#include <iostream.h>
#include <stdio.h>
double omega(long &k)
{printf("Adr k=%x Val k=%ld\n",&k,k); //Adr k=0xfff2 Val k=200001
double s=2+k-3;cout<<"s="<<s<<'\n'; //s=200000
k+=17;printf("Adr.k=%xVal.k=%ld\n",&k,k);//Adr.k=0xfff2 Val.k=200018
return s; }

96
CAPITOLUL 6 Funcţii

void main()
{long a=200001;
printf("Adr a=%x Val a=%ld\n",&a,a); //Adr a=0xfff2 Val a=200001
double w=omega(a); cout<<"w="<<w<<'\n'; //s=200000
}

Aşa cum s-a prezentat în paragrafele 2.5.3.2. şi 5.6., modificatorii sunt cuvinte cheie utilizaţi
în declaraţii sau definiţii de variabile sau funcţii. Modificatorul const poate apare în:
 Declaraţia unei variabile (precede tipul variabilei) restricţionând modificarea valorii datei;
 La declararea variabilelor pointeri definind pointeri constanţi către date neconstante,
pointeri neconstanţi către date constante şi pointeri constanţi către date constante.
 În lista declaraţiilor parametrilor formali ai unei funcţii, conducând la imposibilitatea de
a modifica valoarea parametrului respectiv în corpul funcţiei, ca în exemplul următor:

Exerciţiul 3:
#include <iostream.h>
#include <stdio.h>
int func(const int &a)
{printf("Adr a=%x Val a=%d\n",&a,a);int b=2*a+1;
//modificarea valorii parametrului a nu este permisă
cout<<"b="<<b<<'\n';return b;}
void main()
{const int c=33;int u;printf("Adr c=%x Val c=%d\n",&c,c);
u=func(c);cout<<"u="<<u<<'\n'; }

6.2.3.3. Funcţii care returnează referinţe

Însăşi valoarea returnată de o funcţie poate fi o referinţă, aşa cum ilustrează exemplul
următor:

Exemplu:
#include <iostream.h>
#include <stdio.h>

double &func (double &a, double b)


{ printf("În funcţie:\n");
printf("Val a=%f Adr a=%x\n", a, &a); //Val a=1.200000 Adr a=0xfffe
cout<<"b="<<b<<'\n'; //b=2.200000
a=2*b+1; printf(" După atrib: val a=%f Adr a=%x\n", a, &a);
//Dupa atrib: val a=5.40 Adr a=0xfffe
return a;
}

void main()
{double c=1.2;cout<<"***************MAIN****************\n";
printf("Val c=%f Adr c=%x\n",c, &c); //Val c=1.200000 Adr c=0xfffe
double d; printf("Adr. d=%x\n", &d); //Adr. d=0xffe6
d=func(c,2.2);
printf("Val d=%f Adr d=%x\n", d, &d); //Val d=5.400000 Adr d=0xffe6
}

97
CAPITOLUL 6 Funcţii

6.2.4. TABLOURI CA PARAMETRI

În limbajul C, cazul parametrilor tablou constituie o excepţie de la regula transferului


parametrilor prin valoare. O variabilă (structurată) tablou are ca valoare adresa de început a
tabloului (este un pointer constant).

Exerciţiu: Să se afle elementul minim dintr-un vector de maxim 10 elemente. Se vor scrie
două funcţii: de citire a elementelor vectorului şi de aflare a elementului minim:
#include <iostream.h>
int min_tab(int a[], int nr_elem)
{int elm=a[0];
for (int ind=0; ind<nr_elem; ind++)
if (elm>=a[ind]) elm=a[ind];
return elm;
}

void citireVector(int b[], int nr_el)


{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>b[ind];}
}

void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a,n);
int min=min_tab(a,n); cout<<"Elem. min:"<<min<<'\n'; }

Aceleeaşi problemă poate fi implementată folosind aritmetica pointerilor:

#include <iostream.h>
void citireVector(int *b, int nr_el)
{ for (int ind=0; ind<nr_el; ind++){
cout<<"Elem "<<ind+1<<"="; cin>>*(b+ind);}
}

int min_tab(int *a, int nr_elem)


{int elm=*a;
for (int ind=0; ind<nr_elem; ind++)
if ( elm>=*(a+ind) ) elm=*(a+ind);
return elm;
}

void main()
{
int a[10]; int i,j,n; cout<<"n="; cin>>n;
citireVector(a, n);
int min=min_tab(a,n);
cout<<"Elem. min:"<<min<<'\n';
}

În exemplul anterior au fost implementate funcţiile min_tab, care calculează şi returnează


valoarea elementului minim dintr-un tablou unidimensional (vector) de întregi şi
citireVector, care citeşte valorile elementelor vectorului. Ambelor funcţii li se transmite
ca parametru, tabloul unidimensional (vectorul).

98
CAPITOLUL 6 Funcţii

Din exemplele anterioare se poate observa:


1. Prototipul funcţiei min_tab poate fi unul dintre:
int min_tab(int a[], int nr_elem);
int min_tab(int *a, int nr_elem);
2. Echivalenţe:
int *a ⇔ int a[]
a[i] ⇔ *(a+i)
&a[i] ⇔ a+i
3. Apelul funcţiilor:
citireVector(a,n);
int min=min_tab(a,n);
4. Pentru tablourile unidimensionale, la apel, se transmit numele tabloului sau pointerul care
are ca valoare adresa de început a zonei de memorie rezervate pentru tablou şi numărul
de elemente (nr_elem).

Exerciţiu: Să se scrie următorul program şi să se urmărească rezultatele execuţiei acestuia.


#include <iostream.h>
#include <stdio.h>
double omega(int j, double x, double t[], double *w)
{double s; cout<<"În funcţia omega:";
cout<<"j="<<j<<" t[j]="<<t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//j=2 (=i din main) t[j]=-3.21 t[j+1]=7.44
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
//j=2 (=i din main) w[j]=-21.16 w[j+1]=92.2
t[j]=100; *(t+j+1)=200; w[j]=300; *(w+j+1)=400;
cout<<"După atribuiri:\n";
cout<<"j="<<j<<" t[j]="<< t[j]<<" t[j+1]="<<t[j+1]<<'\n';
//După atribuiri: j=2 t[j]=100 t[j+1]=200
cout<<"j="<<j<<" w[j]="<<w[j]<<" w[j+1]="<<w[j+1]<<'\n';
//j=2 w[j]=300 w[j+1]=400
int i=2*j+1; x=x+2.29*i; s=x+2*t[0]-w[1];
cout<<"i="<<i<<" x="<<x<<" s="<<s<<'\n';
//i=5 x=1.123+2.29*5 s=x+2*1.32-(-15.34) i=5 x=12.573 s=30.553
return s;}

void switch1(double *x, double *y)


{double t=*x; *x=*y; *y=t;}
void switch2(double &x, double &y)
{double t; t=x;x=y;y=t;}
void main()
{double a=123, b=456, u=1.123;
int i=2;
double r[]={1.32, 2.15, -3.21, 7.44, -15.8};
double q[]={12.26, -15.34, -21.16, 92.2, 71.6};
cout<<"i="<<i<<" u="<<u<<'\n';//i=2 u=1.123
double y=omega(i,u,r,q);getch();
cout<<"i="<<i<<" u="<<u<<'\n';
//i=2 u=1.123
cout<<"omega(i,u,r,q)=y="<<y<<'\n';//omega(i,u,r,q)=y=30.553
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1];
cout<<" q[i]="<<q[i]<<" q[i+1]="<<q[i]<<'\n';
//r[i]=100 r[i+1]=200 q[i]=300 q[i+1]=400
cout<<"a="<<a<<" b="<<b<<'\n'; //a=123 b=456
switch1(&a,&b);
cout<<"Rez.intersch.a="<<a<<" b="<<b<<'\n';//Rez.intersch.a=456 b=123

99
CAPITOLUL 6 Funcţii

switch2(a,b);
cout<<"Rez.intersch.a="<<a<<" b="<<b<<'\n';//Rez.intersch.a=123 b=456
cout<<"r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';//r[i]=100 r[i+1]=200
switch1(r+i,r+i+1);
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
// Rez.intersch. r[i]=200 r[i+1]=100
switch2(r[i],r[i+1]);
//switch2(*(r+i),*(r+i+1));
cout<<"Rez. intersch. r[i]="<<r[i]<<" r[i+1]="<<r[i+1]<<'\n';
// Rez.intersch. r[i]=100 r[i+1]=200
}

În exemplul anterior, parametrii formali i şi x din funcţia omega sunt transmişi prin valoare;
parametrii t şi w sunt parametri tablou, transmişi prin referinţă (referinţă şi pointeri). În
funcţia switch1 parametrii sunt transmişi prin pointeri. În funcţia switch2 parametrii sunt
transmişi prin referinţă.

Pentru tablourile multidimensionale, pentru ca elementele tabloului să poată fi referite în


funcţie, compilatorul trebuie informat asupra modului de organizare a tabloului.
Pentru tablourile bidimensionale (vectori de vectori), poate fi omisă doar precizarea
numărului de linii, deoarece pentru a adresa elementul a[i][j], compilatorul utilizează
relaţia: &mat[i][j]=&mat+(i* N+j)*sizeof(tip), în care N reprezintă numărul de
coloane, iar tip reprezintă tipul tabloului.

Exerciţiu: Fie o matrice de maxim 10 linii şi 10 coloane, ale cărei elemente se introduc de la
tastatură. Să se implementeze două funcţii care afişează matricea şi calculează elementul
minim din matrice.

#include <iostream.h>
int min_tab(int a[][10], int nr_lin, int nr_col)
{int elm=a[0][0];
for (int il=0; il<nr_lin; il++)
for (int ic=0; ic<nr_col; ic++)
if (elm>=a[il][ic]) elm=a[il][ic];
return elm; }

void afisare(int a[][10], int nr_lin, int nr_col)


{
for (int i=0; i<nr_lin; i++)
{for (int j=0; j<nr_col; j++) cout<<a[i][j]<<'\t';
cout<<'\n';
}
}

void main()
{int mat[10][10];int i, j, M, N;cout<<"Nr. linii:"; cin>>M;
cout<<"Nr. coloane:"; cin>>N;
for (i=0; i<M; i++)
for (j=0; j<N; j++)
{ cout<<"mat["<<i<<","<<j<<"]="; cin>>mat[i][j];}
afisare(mat, M, N);
int min=min_tab(mat, M, N);
cout<<"Elem. min:"<<min<<'\n';
}

100
CAPITOLUL 6 Funcţii

6.2.5. TRANSFERUL PARAMETRILOR CĂTRE FUNCŢIA main

În unele situaţii este necesară transmiterea unor informaţii (opţiuni, date iniţiale, etc) către un
program la lansarea în execuţie a acestuia, ceea ce implică transmiterea unor parametri către
funcţia main. Pentru a putea transmite parametrii (în vederea prelucrării ulterioare a acestora),
trebuie inclus headerul stdarg.h, iar prototipul funcţiei main are forma:
main (int argc, char *argv[ ], char *env[ ])

Funcţia main poate returna o valoare întreagă: în antetul funcţiei se specifică la tipul valorii
returnate int, sau nu se specifică nimic (implicit, tipul este int), iar în corpul funcţiei apare
instrucţiunea return valoare_intreagă;. Numărul returnat este transferat sistemului de operare
(programul apelant) şi poate fi tratat ca un cod de eroare sau de succes al încheierii execuţiei
programului. Dacă funcţia main nu returnează nici o valoare, în antetul său, la tipul valorii
returnate, se specifică void.

Dacă nu se lucrează cu un mediu de programare integrat, argumentele transmise către funcţia


main trebuie editate (specificate) în linia de comandă prin care se lansează în execuţie
programul respectiv. Linia de comandă tastată la lansarea în execuţie a programului este
formată din grupuri de caractere delimitate de spaţiu sau tab. Fiecare grup este memorat într-
un şir de caractere. Dacă se lucrează cu un mediu integrat (de exemplu, BorlandC), selecţia
comanzii Arguments… din meniul Run determină afişarea unei casete de dialog în care
utilizatorul poate introduce argumentele care vor fi transmise funcţiei main.

Semnificaţia parametrilor (argc, argv şi env) din antet este:


 Adresele de început ale acestor şiruri de caractere sunt memorate în tabloul de pointeri
argv[], în ordinea în care apar în linia de comandă (argv[0] memorează adresa şirului
care constituie numele programului, argv[1] - adresa primului argument, etc.).
 Parametrul întreg argc memorează numărul de elemente din tabloul argv (argc>=1).
 Parametrul env[] este un tablou de pointeri către şiruri de caractere care pot specifica
parametri ai sistemului de operare.

Exerciţiul 1: Să se implementeze un program care afişează argumentele transmise către


funcţia main.
#include <iostream.h>
#include <stdarg.h>
void main(int argc, char *argv[], char *env[])
{cout<<"Nume program:"<<argv[0]<<'\n';
//argv[0] contine numele programului
if(argc==1)
cout<<"Lipsa argumente!\n";
else
for (int i=1; i<argc; i++)
cout<<"Argumentul "<<i<<":"<<argv[i]<<'\n';
}

Exerciţiul 2: Să se implementeze un program care, la lansarea în execuţie, primeşte ca


parametrii o întrebare formată din mai multe cuvinte. Ultimul cuvânt din întrebare este un
grup de caractere, care vor fi căutate, pe rînd, în componenţa celorlalte cuvinte din întrebare.
Întrebarea (cu excepţia ultimului cuvânt) va fi afişată pe ecran. În situaţia în care unul din
caracterele din acest ultim cuvînt este întâlnit în cadrul celorlalte cuvinte, programul

101
CAPITOLUL 6 Funcţii

returnează o valoare întreagă care indică poziţia caracterului în ultimul cuvânt. De exemplu,
dacă se transmite ca parametru către funcţia main întrebarea "Ce mai faci? AFC", rezultatul
este: afişarea întrebării "Ce mai faci?"; la întâlnirea caracterului A, se returnează valoarea 1;
în condiţiile în care caracterul A nu ar fi fost întâlnit, ar fi fost căutat următorul caracter (F
din AFC), iar la întâlnirea acestuia, s-ar fi returnat valoarea 2, etc.; în condiţiile în care
caracterul F nu ar fi fost întâlnit, ar fi fost căutat următorul caracter (C din AFC), iar la
întâlnirea acestuia, s-ar fi returnat valoarea 3, etc.; dacă nici unul din caracterele componente
ale cuvântului AFC nu ar fi fost conţinut în întrebare, s-ar fi returnat codul 0.

#include <stdio.h>
#include <ctype.h>
#include <conio.h>
#include <process.h>

main(int argc,char *argv[])


{int index, c, code; char next_char, *point;
if (argc < 3) /* testarea prezenţei argumentelor în linia de comandă*/
{ printf("Intrebare!!!!\n");exit(0); }
argc--;
for(index = 1;index < argc;index++)
printf("%s ",argv[index]); /*afişarea cuv. 2, 3, …, n-1 (fără cel care
conţine caract. de comparare) din întrebare */
c = getch(); printf("%c\n",c);
if (islower(c)) c = toupper(c);
point = argv[argc]; code = 0; index = 0;
do { next_char = *(point + index);
if (islower(next_char)) next_char = toupper(next_char);
if(next_char == c) code = index + 1;
index++;
} while (*(point + index)); /* NULL */
exit(code); /* returnarea codului de eroare */ }

6.3. FUNCŢII CU PARAMETRI IMPLICIŢI


Spre deosebire de limbajul C, în limbajul C++ se pot face iniţializări ale parametrilor formali.
Parametrii formali iniţializaţi se numesc parametri impliciţi.
<tip_ret> <nume_fc>(<list_par_form_nein> <par_init>=<val1>[,...] );

De exemplu, antetul funcţiei cmmdc (care calculează şi returnează cel mai mare divizor
comun al numerelor întregi primite ca argumente) poate avea următoarea formă:
int cmmdc(int x, int y = 1);
Parametrul formal y este iniţializat cu valoarea 1 şi este parametru implicit. La apelul
funcţiilor cu parametri impliciţi, unui parametru implicit, poate să-i corespundă sau nu, un
parametru efectiv. Dacă la apel nu îi corespunde un parametru efectiv, atunci parametrul
formal va primi valoarea prin care a fost iniţializat (valoarea implicită). Dacă la apel îi
corespunde un parametru efectiv, parametrul formal va fi iniţializat cu valoarea acestuia,
negijându-se astfel valoarea implicită a parametrului formal. În exemplul anterior, la apelul:
int div=cmmdc(9);
x va lua valoarea 9, iar y va lua valoarea 1 (implicită).
Dacă în lista declaraţiilor parametrilor formali ai unei funcţii există şi parametri impliciţi şi
parametri neiniţializaţi, parametrii impliciţi trebuie să ocupe ultimele poziţii în listă, nefiind
permisă intercalarea acestora printre parametrii neiniţializaţi.

102
CAPITOLUL 6 Funcţii

Exerciţiu: Să se scrie următorul program care calculează volumul unui paralelipiped, cu


ajutorul unei funcţii cu parametrii impliciţi. Să se urmarească rezultatele execuţiei.
#include <iostream.h>
#include <stdio.h>
int calcul_volum(int lung, int lat = 2, int inalt = 3);
//prototipul funcţiei cu parametrii impliciţi
void main()
{int x = 10, y = 12, z = 15;
cout<<"Volum paralelipiped " << calcul_volum(x, y, z) << "\n";
//Lung= 10 Lat= 12 Inalt= 15 Volum paralelipiped 1800
cout << "Volum paralelipiped " << calcul_volum(x, y) << "\n";
//Lung= 10 Lat= 12 Inalt= 3 Volum paralelipiped 360
cout << "Volum paralelipiped " << calcul_volum(x) << "\n";
//Lung= 10 Lat= 2 Inalt= 3 Volum paralelipiped 60
cout << "Volum paralelipiped ";
cout << calcul_volum(x, 7) << "\n";
//Volum paralelipiped Lung= 10 Lat= 7 Inalt= 5 210
cout << "Volum paralelipiped ";
cout << calcul_volum(5, 5, 5) << "\n";
//Volum paralelipiped Lung= 5 Lat= 5 Inalt= 5 125
}
int calcul_volum(int lung, int lat, int inalt)
{printf("Lung=%4d Lat=%4d Inalt=%4d ", lung, lat, inalt);
return lung * lat * inalt;}

6.4. FUNCŢII CU NUMĂR VARIABIL DE PARAMETRI


În limbajele C şi C++ se pot defini funcţii cu un număr variabil de parametri. Parametrii care
trebuie să fie prezenţi la orice apel al funcţiei se numesc parametri ficşi, ceilalţi se numesc
parametri variabili. În antetul unei funcţii cu număr variabil de parametri, parametrii ficşi
ocupă primele poziţii din listă, iar prezenţa parametrilor variabili se indică prin trei puncte
care se scriu după ultimul parametru fix al funcţiei:
<tip_val_ret> <nume_f>(<lista-decl_p_form_ficsi>, . . . );

Exemplu: Fie antetul funcţiei numite vârf:


void vârf (int n, double a, . . . );
Funcţia vârf are doi parametri ficşi (n şi a) şi parametri variabili, pentru care nu se
precizează numărul şi tipul, care diferă de la un apel al funcţiei la altul.

Funcţiile predefinite cu număr variabil de parametri sunt, de obicei, funcţii de bibliotecă (ex:
printf, scanf). Pentru a-şi defini propriile funcţii cu număr variabil de parametri,
utilizatorul trebuie să folosească macrouri speciale, care permit accesul la parametrii variabili
şi se găsesc în headerul stdarg.h, aşa cum ilustrează exemplul următor:

Exemplu:
#include <iostream.h>
#include <stdarg.h>
void afisare(int, ...);//prototip functie cu nr. variabil de parametri
void main()
{int i = 5;int pv_unu = 1, pv_doi = 2;
afisare(pv_unu, i); /* Param.fix=1 Parametrii variabili sunt 5 */
afisare(3,i,i+pv_doi,i+pv_unu);/*Param.fix=3 Parametrii var. sunt 5 7 6 */

103
CAPITOLUL 6 Funcţii

afisare(pv_doi, 70, 300); /* Param.fix=2 Parametrii variabili sunt 70 300 */ }

void afisare(int nr, ...)


{va_list param_pt;
cout<<"Param.fix="<<nr<<'\n';
va_start(param_pt,nr); // Apel macro setup
cout << "Parametrii variabili sunt ";
for (int i = 0 ; i < nr ; i++)
cout << va_arg(param_pt,int) << " "; // Extragere parametru
cout << "\n";
va_end(param_pt); /* Inchidere macro*/ }

6.5. FUNCŢII PREDEFINITE


Orice mediu de programare este prevăzut cu una sau mai multe biblioteci de funcţii
predefinite. Orice bibliotecă este formată din:
 fişierele header (conţine prototipurile funcţiilor, declaraţiile de variabile);
 biblioteca (arhiva) propriu-zisă (conţine definiţii de funcţii).

Pentru ca funcţiile predefinite să poată fi utilizate într-un program, fişierele header în care se
găsesc prototipurile acestora trebuie incluse printr-o directivă preprocesor (exemplu
#include <stdio.h>). Deasemenea, utilizatorul îşi poate crea propriile headere. Pentru a
putea utiliza funcţiile din headerele proprii, utilizatorul trebuie să includă aceste headere în
programul apelant (exemplu #include "my_header.h").

Pentru funcţiile predefinite, au fost create fişiere header orientate pe anumite numite tipuri de
aplicaţii. De exemplu, funcţiile matematice se găsesc în headerul <math.h>. Headerul
<stdlib.h> conţine funcţii standard, headerul <values.h> defineşte o serie de constante
simbolice (exemplu MAXINT, MAXLONG) care reprezintă, în principal, valorile maxime şi
minime ale diferitelor tipuri de date, etc.

6.5.1. FUNCŢII MATEMATICE (headerul <math.h>)

Funcţii aritmetice

Valori absolute
int abs(int x);
Returnează un întreg care reprezintă valoarea absolută a argumentului.
long int labs(long int x);
Analog cu abs, cu deosebirea că argumentul şi valoarea returnată sunt de tip long int.
double fabs(double x);
Returnează un real care reprezintă valoarea absolută a argumentului real.

Funcţii de rotunjire
double floor(double x);
Returnează un real care reprezintă cel mai apropiat număr, fără zecimale, mai mic sau
egal cu x (rotunjire prin lipsă).
double ceil(double x);
Returnează un real care reprezintă cel mai apropiat număr, fără zecimale, mai mare sau
egal cu x (rotunjire prin adaos).

104
CAPITOLUL 6 Funcţii

Funcţii trigonometrice
double sin(double x);
Returnează valoarea lui sin(x), unde x este dat în radiani; valoarea reală returnată se află
în intervalul [-1, 1].
double cos(double x);
Returnează valoarea lui cos(x), unde x este dat în radiani. Numărul real returnat se află
în intervalul [-1, 1].
double tan(double x);
Returnează valoarea lui tg(x), unde x este dat în radiani.

Funcţii trigonometrice inverse


double asin(double x);
Returnează valoarea lui arcsin(x), unde x se află în intervalul [-1, 1]. Numărul real
returnat (în radiani) se află în intervalul [-pi/2, pi/2].
double acos(double x);
Returnează valoarea lui arccos(x), unde x se află în intervalul [-1, 1]. Numărul real
returnat se află în intervalul [0, pi].
double atan(double x);
Returnează valoarea lui arctg(x), unde x este dat în radiani. Numărul real returnat se află
în intervalul [0, pi].
double atan2(double y, double x);
Returnează valoarea lui tg(y/x), cu excepţia faptului că semnele argumentelor x şi y
permit stabilirea cadranului şi x poate fi zero. Valoarea returnată se află în intervalul [-
pi,pi]. Dacă x şi y sunt coordonatele unui punct în plan, funcţia returnează valoarea
unghiului format de dreapta care uneşte originea axelor carteziene cu punctul, faţă de
axa absciselor. Funcţia foloseşte, deasemenea, la transformarea coordonatelor cartezine
în coordonate polare.

Funcţii exponenţiale şi logaritmice


double exp(double x);
long double exp(long double x);
Returnează valoarea e x .
double log(double x);
Returnează logaritmul natural al argumentului ( ln(x) ).
double log10(double x);
Returnează logaritmul zecimal al argumentului (lg (x) ).
double pow(double baza, double exponent);
Returnează un real care reprezintă rezultatul ridicării bazei la exponent (baza exp onent ).
double sqrt(double x);
Returnează rădăcina pătrată a argumentului x.
double hypot(double x, double y);
Funcţia distanţei euclidiene - returnează x 2 + y 2 , deci lungimea ipotenuzei unui
triunghi dreptunghic, sau distanţa punctului P(x, y) faţă de origine.

Funcţii de generare a numerelor aleatoare


int rand(void) <stdlib.h>
Generează un număr aleator în intervalul [0, RAND_MAX].

105
CAPITOLUL 6 Funcţii

6.5.2. FUNCŢII DE CLASIFICARE (TESTARE) A CARACTERELOR

Toate aceste funcţii (headerul <ctype.h>) primesc ca argument un caracter şi returnează un


număr întreg care este pozitiv dacă argumentul îndeplineşte o anumită condiţie, sau valoarea
zero dacă argumentul nu îndeplineşte condiţia.
int isalnum(int c);
Returnează valoare întreagă pozitivă daca argumentul este literă sau cifră. Echivalentă
cu: isalpha(c)||isdigit(c)
int isalpha(int c);
Testează dacă argumentul este literă mare sau mică. Echivalentă cu isupper(c)||
islower(c).
int iscntrl(int c);
Testează dacă argumentul este caracter de control (neimprimabil).
int isdigit(int c);
Testează dacă argumentul este cifră.
int isxdigit(int c);
Testează dacă argumentul este cifră hexagesimală (0-9, a-f, A-F).
int islower(int c);
Testează dacă argumentul este literă mică.
int isupper(int c);
Testează dacă argumentul este literă mare.
int ispunct(int c);
Testează dacă argumentul este caracter de punctuaţie (imprimabil, nu literă sau spaţiu).
int isspace(int c);
Testează dacă argumentul este spaţiu alb (' ', '\n', '\t', '\v', '\r')
int isprint(int c);
Testează dacă argumentul este caracter imprimabil, inclusiv blancul.

6.5.3. FUNCŢII DE CONVERSIE A CARACTERELOR (prototip în <ctype.h>)

int tolower(int c);


Funcţia transformă caracterul primit ca argument din literă mare, în literă mică şi
returnează codul ASCII al literei mici. Dacă argumentul nu este literă mare, codul
returnat este chiar codul argumentului.
int toupper(int c);
Funcţia transformă caracterul primit ca argument din literă mică, în literă mare şi
returnează codul acesteia. Dacă argumentul nu este literă mică, codul returnat este chiar
codul argumentului.

6.5.4. FUNCŢII DE CONVERSIE DIN ŞIR ÎN NUMĂR (prototip în <stdlib.h>)

long int atol(const char *npr);


Funcţia converteşte şirul transmis ca argument (spre care pointează npr) într-un număr
cu semn, care este returnat ca o valoare de tipul long int. Şirul poate conţine caracterele
'+' sau '-'. Se consideră că numărul este în baza 10 şi funcţia nu semnalizează
eventualele erori de depăşire care pot apare la conversia din şir în număr.
int atoi(const char *sir);
Converteste şirul spre care pointeaza argumentul într-un număr întreg.
double atof(const char *sir);
Funcţia converteste şirul transmis ca argument într-un număr real cu semn (returnează
valoare de tipul double). În secvenţa de cifre din şir poate apare litera 'e' sau 'E'

106
CAPITOLUL 6 Funcţii

(exponentul), urmată de caracterul '+' sau '-' şi o altă secvenţă de cifre. Funcţia nu
semnalează eventualele erori de depăşire care pot apare.

6.5.5. FUNCŢII DE TERMINARE A UNUI PROCES (PROGRAM) ( <process.h>)

void exit(int status);


Termină execuţia unui program. Codul returnat de terminarea corectă este memorat în
constanta simbolică EXIT_SUCCES, iar codul de eroare - în EXIT_FAILURE.
void abort();
Termină forţat execuţia unui program.
int system(const char *comanda); prototip în <system.h>
Permite execuţia unei comenzi DOS, specificate prin şirul de caractere transmis ca
parametru.

6.5.6. FUNCŢII DE INTRARE/IEŞIRE (prototip în <stdio.h>)

Streamurile (fluxurile de date) implicite sunt: stdin (fişierul, dispozitivul standard de


intrare), stdout (fişierul, dispozitivul standard de ieşire), stderr (fişier standard pentru
erori), stdprn (fişier standard pentru imprimantă) şi stdaux (dispozitivul auxiliar
standard). De câte ori este executat un program, streamurile implicite sunt deschise automat
de către sistem. În headerul <stdio.h> sunt definite şi constantele NULL (definită ca 0) şi
EOF (sfârşit de fişier, definită ca -1, CTRL/Z).

int getchar(void);
Citeşte un caracter (cu ecou) din fişierul standard de intrare (tastatură).
int putchar(int c);
Afişează caracterul primit ca argument în fişierul standard de ieşire (monitor).
char *gets(char *sir);
Citeşte un şir de caractere din fişierul standard de intrare (până la primul blank întâlnit
sau linie nouă). Returnează pointerul către şirul citit.
int puts(const char *sir);
Afişează şirul argument în fişierul standard de ieşire şi adaugă terminatorul de şir.
Returnează codul ultimului caracter al şirului (cel care precede NULL) sau -1 la eroare.
int printf(const char *format, ... );
Funcţia scrie în fişierul standard de ieşire (pe monitor) datele, într-un anumit format.
Funcţia returnează numărul de octeţi (caractere) afişaţi, sau –1 în cazul unei erori.
1. Parametrul fix al funcţiei conţine:
 Succesiuni de caractere afişate ca atare
Exemplu:
printf("\n Buna ziua!\n\n”); // afişare: Buna ziua!
 Specificatori de format care definesc conversiile care vor fi realizate asupra
datelor de ieşire, din formatul intern, în cel extren (de afişare).
2. Parametrii variabili ai funcţiei sunt expresii. Valorile obţinute în urma evaluării
acestora sunt afişate corespunzător specificatorilor de format care apar în
parametrul fix. De obicei, parametrul fix conţine atât specificatori de format, cât şi
alte caractere. Numărul şi tipul parametrilor variabili trebuie să corespundă
specificatorului de format.

Forma generală a specificatorului de format (parametrul fix) este:


% [-|c|][<sir_cifre_eventual_punct_zecimal>] <una_sau_doua_lit>

107
CAPITOLUL 6 Funcţii

- Implicit, datele se cadrează (aliniază) la dreapta câmpului în care se scriu. Prezenţa


caracterului – determină cadrarea la stânga.
Şirul de cifre defineşte dimensiunea câmpului în care se scrie data. Dacă scrierea datei
necesită un câmp de lungime mai mare, lungimea indicată în specificator este ignorată.
Dacă scrierea datei necesită un câmp de lungime mai mică, data se va scrie în câmp,
cadrată la dreapta sau la stânga (dacă apare semnul - ), completându-se restul câmpului
cu caracterele nesemnificative implicite, adica spaţii. Şirul de cifre aflate dupa punct
definesc precizia (numarul de zecimale cu care este afişat un numar real - implicit sunt
afişate 6 zecimale).
Literele definesc tipul conversiei (din formatul intern în cel extern) aplicat datei afişate:
c – Afişează un caracter
s – Afişează un şir de caractere
d– Afişează date întregi; cele negative sunt precedate de semnul -.
o – Afişează date de tip int sau unsigned int în octal.
x sau X - Afişează date de tip int sau unsigned int în hexagesimal.
f–Afişează date de tip float sau double în forma: parte_întreagă.parte_fract
e sau E-Afişează date de tip float sau double în forma:
parte_întreagă.parte_fractionară exponent
Exponentul începe cu e sau E şi defineşte o putere a lui zece care înmulţită cu restul
numărului dă valoarea reală a acestuia.
g sau G–Afişează o dată reală fie ca în cazul specificatorului terminat cu f, fie ca în
cazul specificatorului terminat cu e. Criteriul de afisare se alege automat, astfel încât
afişarea să ocupe un număr minim de poziţii în câmpul de afişare.
l – Precede una din literele d, o, x, X, u. La afişare se fac conversii din tipul long sau
unsigned long.
L – Precede una din literele f, e, E, g, G. La afişare se fac conversii din tipul long
double.

int scanf(const char *format, ... );


Funcţia citeşte din fişierul standard de intrare (tastatura) valorile unor variabile, le
converteşte din format extern în cel intern (conform specificatorului de format) şi le
memorează la adresele specificate. Funcţia returnează numărul câmpurilor citite corect.
1. Parametrul fix al funcţiei conţine:
Specificatorii de format care definesc conversiile aplicate datelor de intrare, din
formatul extern, în cel intren (în care sunt memorate). Specificatorii de format sunt
asemănători celor folosiţi de funcţia printf: c, s, d, o, x sau X, u, f, l, L.
2. Parametrii variabili - listă de adrese ale variabilelor care vor fi citite, deci în
această listă, numele unei variabile simple va fi precedată de operatorul adresă &.

int sprintf(char *sir_cu_format, const char *format, ... );


Funcţia permite scrierea unor date, conform unui anumit format, în şirul transmis ca
prim argument. Returnează numărul de octeţi (caractere) scrise în şir, sau –1 la eroare.

int sscanf(char *sir_cu_format, const char *format, ... );


Funcţia extrage valori din şirul transmis ca prim argument şi le depune în memorie, la
adresele specificate. Returnează numărul câmpurilor citite corect.

108
CAPITOLUL 6 Funcţii

Exerciţiul 1: Să se scrie următorul program (care ilustrează modalităţile de folosire a


funcţiilor predefinite) şi să se urmărească rezultatele execuţiei acestuia.

#include <iostream.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
#include <stdio.h>
#include <conio.h>
void main()
{clrscr();
int x=-34;int a=abs(x);cout<<"a="<<a<<'\n';long int y=-566666;
cout<<"labs(y)="<<labs(y)<<"fabs(-45.67)="<<fabs(-45.67)<<'\n';
cout<<"fabs(45.67)="<<fabs(45.67)<<'\n';
cout<<floor(78.99)<<'\n'; cout<<floor(78.45)<<'\n'; //78 78
cout<<floor(-78.45)<<'\n'; cout<<ceil(78.99)<<'\n'; //-79 79
cout<<ceil(78.45)<<'\n'; cout<<ceil(-78.45)<<'\n'; //79 -78
cout<<isalpha('8')<<'\n'; cout<<isalpha('f')<<'\n'; /*0 val dif.de
zero */ cout<<"Apasa tasta…."; getch();
cout<<isalpha('%')<<'\n'; cout<<tolower('D')<<'\n';//0 100 (cod 'd')
cout<<toupper('a')<<'\n'; //65 (codul caracterului 'A')
char s1[]="-56.234 h mk";cout<<atol(s1)<<'\n'; //-56
cout<<atoi(s1)<<'\n'; cout<<atof(s1)<<'\n'; //-56 -56.234
cout<<atof("45E+3 n")<<'\n'; //45000
cout<<"EXECUTIA COMENZII DOS DIR\n";int cod_ret=system("dir");
cout<<"Val. cod retur="<<cod_ret<<'\n';
int c;cout<<"Astept car:";c=getchar();//Presupunem caracter introdus: e
cout<<"Caracterul citit este:"<<putchar(c);//Caracterul citit este: 101
// 101=codul carcterului e
cout<<'\n';puts(s1);cout<<'\n';printf("Afisarea unui mesaj\n");
int intreg=-45;
printf("VALOAREA VARIABILEI INTREG ESTE:%d\n", intreg);
printf("VALOAREA VARIABILEI INTREG ESTE:%10d\n", intreg);
printf("VALOAREA VARIABILEI INTREG ESTE:%-10d\n", intreg);
double real=2.45; cout<<"Apasa tasta…."; getch();
printf("VALOAREA VARIABILEI real ESTE:%f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%10.3f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%10.5f\n", real);
printf("VALOAREA VARIABILEI real ESTE:%e\n", real);
printf("VAL.VAR.real:%f si\neste mem. la adr%x\n",real,&real );
printf("astept sir:");scanf("%s",s1);
printf("Sir citit:%s\n", s1);
char sir_f[100], C; cout<<"Apasa tasta…."; getch();
sprintf(sir_f,"Codul caracterului %c este:%d",C, (int)C);
puts(sir_f);
/* se citeste cate un caracter de la tastatura, pana la intalnirea caracterului 'X' si se
afiseaza fiecare caracter citit */
char cc;
do { puts("Caracter=");
cc = getchar(); /* citire caracter */
putchar(cc); /* afisare caracter citit */
} while (cc != 'X');
cout<<"Apasa tasta…."; getch();
}

109
CAPITOLUL 6 Funcţii

Exerciţiul 2: Să se scrie următorul program (care ilustrează modalităţile de folosire a


funcţiilor predefinite) şi să se urmărească rezultatele execuţiei acestuia.

#include <stdio.h>
#include <conio.h>
void main()
{ int a,b,c; char *format1; clrscr();
format1 = "\n %04X %s %04X = %04X";
char *format2 = "\n %c%04X = %04X";
a = 0x0FF0; b = 0xFF00;
printf(" OPERATII LOGICE LA NIVEL DE BIT.\n\n");
c = a << 4; printf(format1,a,"<<",4,c);
printf(" Deplas stanga cu 4 sau cu o cifra hexa.");
c = a >> 4; printf(format1,a,">>",4,c);
printf(" Deplas dreapta cu 4 sau cu o cifra hexa.");
printf(" Right shift 4 bits or one hex digit.");
c = a & b; printf(format1,a,"&",b,c);
printf(" SI ");
c = a | b; printf(format1,a,"|",b,c);printf(" SAU ");
c = a ^ b; printf(format1,a,"^",b,c);
printf(" SAU EXCLUSIV (XOR).");
c = ~a; printf(format2,'~',a,c);
printf(" NOT .");
c = -a; printf(format2,'-',a,c);
printf(" Complement aritmetic in hexa.");
printf("\n");getch();}

Exerciţiul 3: Să se scrie următorul program (care ilustrează modalităţile de folosire a


funcţiilor predefinite) şi să se urmărească rezultatele execuţiei acestuia.

#include <stdio.h>
#include <conio.h>
void main()
{ clrscr();
int n[5]={100,101,102,103,104}, rez[5], index;char linie[80];
sprintf(linie,"Vct:%d %d %d %d %d\n",n[0],n[1],n[2],n[3],n[4]);
printf("%s",linie); }

Exerciţiul 4: Să se scrie un program care pentru un număr natural, n, citit de la tastatură,


determină numărul k, k<n, astfel încât k are numărul maxim de divizori primi, diferiţi.

#include<iostream.h>
#include<conio.h>
#include<math.h>
int prim(int x)
{for(int i=2;i<=sqrt(x);i++)
if(!(x%i)) return 0;
return 1;}
void main()
{long k=1, n; cout<<"Introduceti valoarea lui n"; cin>>n;
for(int i=2;i<=n/2;i++)
if(prim(i) && (k*i)<n) k*=i;
cout<<"Numarul mai mic decât "<<n;
cout<<" cu cei mai multi divizori primi este "<< k<<'\n';
getch(); }

110
CAPITOLUL 6 Funcţii

Exerciţiul 5: Să se rearanjeze elementele unei matrici de întregi astfel încât să fie ordonate
crescător atât pe linii, cât şi pe coloane.
#include<iostream.h>
#include<conio.h>
#include<stdio.h>
void citire(int a[][10], int m, int n)
{for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
cout<<"a["<<i<<","<<j<<"]=";cin>>a[i][j];}
}
void afisare(int a[][10], int m, int n)
{for(int i=0;i<m;i++)
{ cout<<'\n';
for(int j=0;j<n;j++) cout<<'\t'<<a[i][j]; }
}
void ord(int a[][10], int m, int n, int dir, int k)
{int i,j,x;
if(dir==1)
{for(i=0;i<n-1;i++)
for(j=i+1;j<n;j++)
if(a[k][i]>a[k][j]){x=a[k][i];a[k][i]=a[k][j];a[k][j]=x;}
}
else if(dir==2)
{for(i=0;i<m-1;i++)
for(j=i+1;j<m;j++)
if(a[i][k]>a[j][k]){x=a[i][k];a[i][k]=a[j][k];a[j][k]=x;}
}
}
void main()
{int A[10][10],n,m; int i,j;cout<<"Nr. linii="; cin>>m;
cout<<"Nr. coloane="; cin>>n;
citire(A,m,n);cout<<"Matricea initiala:\n";afisare(A,m,n);
for(i=0;i<m;i++) ord(A,m,n,1,i);
for(j=0;j<n;j++) ord(A,m,n,2,j);
cout<<"Matricea obtinuta:\n";afisare(A,m,n);getch();}

Exerciţiul 6: Să se scrie un program care descompune un număr natural, n, citit de la


tastatură, într-un produs de factori primi, sub forma:
n=factor1^puterea1*factor2^puterea2*…

#include<math.h>
#include<stdio.h>
#include<iostream.h>
#include<conio.h>
int prim(int k)
{for(int i=2;i<=sqrt(k);i++)
if(k%i==0) return 0;
return 1; }
void main()
{long n,d=2,k;clrscr(); cout<<"Dati n: ";cin>>n; clrscr();
cout<<n<<"=";
do { k=0;
while(n%d==0) { n/=d; k++; }
if(k!=0) cout<<d<<"^"<<k<<"*";
do d++; while(prim(d)==0);
}while(n!=1);
cout<<"\b \b"; }

111
CAPITOLUL 6 Funcţii

Exerciţiul 7: Să se scrie un program care citeşte un număr natural, n, scris cu cifre arabe şi îl
afişează folosind cifrele romane.

#include<iostream.h>
#include<string.h>
#include<conio.h>
#include<stdlib.h>
const char *rom="IVXLCDMP"; char sir[20];
void transforma(char n, int r)
{int i,j,x;char ret[4]="";r=2*r;x=(int)n-(int)'0';
if(x>=1&&x<=3)
{ for(i=1;i<=x;i++)
ret[i-1]=rom[r];
ret[i-1]='\x0'; }
else if(x==4)
{ ret[0]=rom[r];
ret[1]=rom[r+1];
ret[2]='\x0'; }
else if(x>5&&x<9)
{ ret[0]=rom[r+1];
for(i=6;i<=x;i++)
ret[i-5]=rom[r];
ret[i-5]='\x0'; }
else if(x==9)
{ ret[0]=rom[r];
ret[1]=rom[r+2];
ret[2]='\x0'; }
strcat(sir,ret); }

void main()
{clrscr();unsigned int n;char nr[4];
cout<<"Dati numar scris cu cifre arabe :"; cin>>n;
itoa(n,nr,10);int i,j;
for(j=0,i=strlen(nr);i>0;i--,j++)
transforma(nr[j],i-1);
cout<<"Numarul "<<n<<" scris cu cifre romane:"<<sir;getch();}

6.6. SUPRAÎNCĂRCAREA FUNCŢIILOR


Limbajul C++ oferă posibilitatea de supraîncărcare a numelui unei funcţii (pe scurt,
supraîncărcarea funcţiilor), ceea ce conduce la utilizarea unor funcţii cu acelaşi nume, care
execută prelucrări diferite. Prototipurile unei funcţii supraîncărcate trebuie să difere între ele
prin numărul şi/sau tipul parametrilor formali şi/sau prin tipul valorii returnate. Selecţia
funcţiei se realizează în momentul compilării.
Să urmărim exemplul următor, în care funcţia afis este supraîncărcată (patru funcţii cu
acelaşi nume, dar cu prototipuri diferite). În momentul apelului, selecţia uneia dintre cele
patru funcţii se realizează pe baza parametrilor efectivi transmişi, sau a valorii returnate.

Exemplu:
#include <iostream.h>
// prototipurile funcţiei afis, supraîncărcată
int afis(const int);
//returnează o valoare întreagă egală cu pătratul valorii argumentului întreg
int afis(float); /*returnează o valoare întreagă obţinută prin conversia

112
CAPITOLUL 6 Funcţii

float -> int a triplului valorii argumentului real simplă precizie*/


float afis(const float, float); //returnează media aritmetică a arg-lor
char * afis();//returnează un şir de caractere
void afis(const char*);//afişează şirul constant transmis ca parametru
void main()
{int a = 12; float a1 = 14.33, a3 = 34.33;
cout << "Apel afis " << afis(a) << "\n";
cout << "Apel afis " << afis(2 * a) << "\n";
cout << "Apel afis " << afis(a1) << "\n";
cout << "Apel afis " << afis(a3) << "\n";
cout << "Apel afis " << afis(a1,a3) << "\n";
char *p=afis();
cout<<"p="<<p<<'\n';
afis("AFISARE SIR ARGUMENT!\n")
int afis(const int val)
{return val * val; }
int afis(float val)
{ return (int)(3.0 * val);}
float afis(const float i1, float i2)
{ return (i1 + i2)/2.0;}
char * afis()
{char *pp="Sir de caractere!!!!"; return pp;}
void afis(const char*s)
{cout<<s;}

6.7. CLASE DE MEMORARE


Definiţii:
Variabilele declarate în afara oricărei funcţii sunt variabilele globale.
Variabilele declarate în interiorul unui bloc sunt variabilele locale.
Porţiunea de cod în care o variabilă este accesibilă reprezintă scopul (domeniul de
vizibilitate) al variabilei respective.

Parametrii formali ai unei funcţii sunt variabile locale ale funcţiei respective.
Domeniul de vizibilitate al unei variabile locale este blocul în care variabila respectivă este
definită.
În situaţia în care numele unei variabile globale coincide cu numele unei variabile locale,
variabila locală o "maschează" pe cea globală, ca în exemplul următor: în interiorul blocului
din funcţia main s-a redefinit variabila a, care este variabilă locală în interiorul blocului.
Variabila locală a maschează variablila globală numită tot a.

Exemplu:
#include <stdio.h>
void main()
{ int a,b; a=1; b=2;
printf("În afara blocului a=%d b=%d\n", a, b);
{int a=5; b=6;
printf("În interiorul blocului a=%d b=%d\n",a,b);
}
printf("În afara blocului a=%d b=%d\n", a, b); }

113
CAPITOLUL 6 Funcţii

În cazul variabilelor locale, compilatorul alocă memorie în momentul execuţiei blocului sau
funcţiei în care acestea sunt definite. Când execuţia funcţiei sau blocului se termină, se
eliberează memoria pentru acestea şi valorile pentru variabilele locale se pierd.

Definiţii:
Timpul de viaţă a unei variabile locale este durata de execuţie a blocului (sau a
funcţiei) în care aceasta este definită.
Timpul de viaţă a unei variabile globale este durata de execuţie a programului.

În exemplul următor, variabila întreagă x este vizibilă atât în funcţia main, cât şi în funcţia
func1 (x este variabila globală, fiind definită în exteriorul oricărei funcţii). Variabilele a şi b
sunt variabile locale în funcţia main (vizibile doar în main). Variabilele c şi d sunt variabile
locale în funcţia func1 (vizibile doar în func1). Varabila y este variabilă externă şi este
vizibilă din punctul în care a fost definită, până la sfârşitul fişierului sursă (în acest caz, în
funcţia func1).

Exemplu:
int x;
void main()
{int a,b;
//- - - - - - - - -
}
int y;
void func1(void)
{int c,d;
//- - - - - - - -
}

O variabilă se caracterizează prin: nume, tip, valoare şi clasă de memorare.

Clasa de memorare se specifică la declararea variabilei, prin unul din cuvintele cheie:
 auto;
 register;
 extern;
 static.

Clasa de memorare determină timpul de viaţă şi domeniul de vizibilitate (scopul) unei


variabile (tabelul 6.1).

Exemplu:
auto int a;
static int x;
extern double y;
register char c;

 Clasa de memorare auto


Dacă o variabilă locală este declarată fără a se indica în mod explicit o clasă de
memorare, clasa de memorare considerată implicit este auto. Pentru acea variabilă se
alocă memorie automat, la intrarea în blocul sau în funcţia în care ea este declarată. Deci
domeniul de vizibilitate a variabilei este blocul sau funcţia în care aceasta a fost definită.
Timpul de viaţă este durata de execuţie a blocului sau a funcţiei.

114
CAPITOLUL 6 Funcţii

 Clasa de memorare register


Variabilele din clasa register au acelaşi domeniu de vizibilitate şi timp de viaţă ca şi cele
din clasa auto. Pentru memorarea variabilelor register se utilizează regiştrii interni
(creşterea eficienţei) ai procesorului şi ca urmare, unei astfel de variabile nu i se poate
aplica operatorul de referenţiere.

 Clasa de memorare extern


O variabilă globală declarată fără specificarea unei clase de memorare, este considerată ca
având clasa de memorare extern. Domeniul de vizibilitate este din momentul declarării
până la sfârşitul fişierului sursă. Timpul de viaţă este durata execuţiei fişierului. O
variabilă din clasa extern este iniţializată automat cu valoarea 0.

 Clasa de memorare static


Clasa de memorare static poate fi specificată atât pentru variabilele locale, cât şi pentru
cele globale:
 Variabilele locale statice au ca domeniu de vizibilitate blocul sau funcţia în care sunt
definite, iar ca timp de viaţă - durata de execuţie a programului. Se iniţializează
automat cu 0.
 Variabilele globale statice au ca domeniu de vizibilitate punctul în care au fost definite
până la sfârşitul fişierului sursă, iar ca timp de viaţă - durata execuţiei programului.

Tabelul 6.1.
Clasa de Variabila Domeniu vizibilitate Timp de viaţă
memorare
auto locală Blocul sau funcţia în care Durata de execuţie a blocului
(register) (internă) au fost definite sau a funcţiei
extern globală  Din punctul definirii, Durata de execuţie a blocului
până la sfârşitul fiş-lui sau a programului
(ROF)
 Alte fişiere
static globală ROF -”-
locală Bloc sau funcţie -”-
nespecificat globală Vezi extern Vezi extern
locală Vezi auto Vezi auto

Exemplul: Să se scrie următorul program (care utilizează variabile cu diferite clase de


memorare) şi să se urmărească rezultatele execuţiei acestuia.
#include <stdio.h>

void f1(void);
void f2(void);
void f3(void);
int nr; /* variabla globala */
static int sg; /* variabla globala statica */

void main()
{ register int index; /* Variabila locala register, in main */
printf("Var glob nr=%d\n", nr);// Var glob nr=0
printf("Var glob statica sg=%d\n", sg); // Var glob statica sg=0
f1(); f2(); f3();

115
CAPITOLUL 6 Funcţii

for (index = 8;index > 0;index--) {


for (int stuff = 0;stuff <= 6;stuff++) /* stuff variabila locala
instructiunii compuse */
printf("%d ",stuff);
printf(" index este acum %d\n",index); }
//0123456 index este acum 8
//0123456 index este acum 7
//0123456 index este acum 6
//0123456 index este acum 5
//0123456 index este acum 4
//0123456 index este acum 3
//0123456 index este acum 2
//0123456 index este acum 1
}

int counter; /* domeniu de vizibilitate ROF*/

void f1(void)
{int index; /* Variabila locala in f1 */
index = 23;printf("In f1, index= %d\n",index);//In f1 index=23
printf("In f1, var globala counter= %d\n",counter);
//In f1, var globala counter=0
sg=99;printf("In f1, var globala statica sg= %d\n",sg); /*In f1,
var globala statica sg=99*/ }

void f2(void)
{int count; /* Variabila count locala functiei f2, o mascheaza pe cea globala */
static int sl;printf("In f2 sl= %d\n",sl); //in f2 sl=0
count = 53; printf("In f2 count= %d\n",count); //In f2 count=53
counter = 77;printf("In f2 var glob counter= %d\n",counter);
/*In f2 var glob counter=77*/ }
void f3(void)
{ printf("In f3 var globala counter=%d\n",counter);
/*In f3 var globala counter=77*/}

6.8. MODURI DE ALOCARE A MEMORIEI


Alocarea memoriei se poate realiza în următoarele moduri:
 alocare statică;
 alocare dinamică;
 alocare pe stivă.

Se alocă static memorie în următoarele cazuri:


 pentru instrucţiunile de control propriu-zise;
 pentru variabilele globale şi variabilele locale declarate în mod explicit static.

Se alocă memorie pe stivă pentru variabilele locale.

Se alocă dinamic memorie în mod explicit, cu ajutorul funcţiilor de alocare dinamică, aflate
în headerul <alloc.h> (în limbajul C), sau cu ajutorul operatorului new (în limbajul C++).

116
CAPITOLUL 6 Funcţii

Exemplu: Să se urmărească modul de declarare a variabilelor din secvenţa următoare şi


alocarea memoriei pentru acestea.

Stivă Alocare statică


int a,b;
c double x; a
v b
double f1(int c, double v)
b
{int b; x
w static double z;
} z
a
double w; w
b int f1(int w)
c {double a;}
k
void main()
{
double b, c;
int k;
b=f1(k,c);}

Figura 6.8. Alocarea statică şi pe stivă

Pentru toate tipurile de date (simple sau structurate), la declararea acestora, compilatorul alocă
automat un număr de locaţii de memorie (corespunzător tipului datei). Dimensiunea zonei de
memorie necesară pentru păstrarea valorilor datelor este fixată înaintea lansării în execuţie a
programului. În cazul declarării unui tablou de întregi cu maximum 100 de elemente vor fi
alocaţi 100*sizeof(int) locaţii de memorie succesive. În situaţia în care la un moment
dat tabloul are doar 20 de elemente, pentru a aloca doar atâta memorie cât este necesară în
momentul respectiv, se va aloca memorie în mod dinamic.

Este de dorit ca în cazul datelor a căror dimensiune nu este cunoscută a priori sau variază în
limite largi, să se utilizeze o altă abordare: alocarea memoriei în mod dinamic. În mod
dinamic, memoria nu mai este alocată în momentul compilării, ci în momentul execuţiei.
Alocarea dinamică elimină necesitatea definirii complete a tuturor cerinţelor de memorie în
momentul compilării.

6.8.1. FUNCŢII DE ALOCARE DINAMICĂ A MEMORIEI

În limbajul C, alocarea memoriei în mod dinamic se face cu ajutorul funcţiilor malloc,


calloc, realloc; eliberarea zonei de memorie se face cu ajutorul funcţiei free.
Funcţiile de alocare/dealocare a memoriei au prototipurile în header-ele <stdlib.h> şi
<alloc.h>:

void *malloc(size_t nr_octei_de_alocat);


Funcţia malloc necesită un singur argument (numărul total de octeţi care vor fi reyervaţi) şi
returnează un pointer generic către zona de memorie alocată (pointerul conţine adresa
primului octet al zonei de memorie rezervate).

117
CAPITOLUL 6 Funcţii

void *calloc(size_t nr_elem, size_t mărimea_unui_elem);


Funcţia calloc lucrează în mod similar cu malloc; alocă memorie pentru un tablou de
nr_elem, pentru fiecare element rezervându-se un număr de octeţi specificat prin
mărimea_unui_elem şi returnează un pointer către zona de memorie alocată.

void *realloc(void *ptr, size_t mărime);


Funcţia realloc permite modificarea zonei de memorie alocată dinamic cu ajutorul
funcţiilor malloc sau calloc.

Observaţii:
1. În cazul în care nu se reuşeşte alocarea dinamică a memoriei (de exemplu, memorie
insuficientă), funcţiile malloc, calloc şi realloc returnează un pointer null.
2. Deoarece funcţiile malloc, calloc, realloc returnează un pointer generic, rezultatul poate fi
atribuit oricărui tip de pointer. La atribuire, este indicat să se utilizeze operatorul de
conversie explicită (vezi exemplu).

Eliberarea memoriei (alocate dinamic cu una dintre funcţiile malloc, calloc sau realloc) se
realizează cu ajutorul funcţiei free, cu prototipul:
void free(void *ptr);
Funcţia primeşte ca argument adresa de început a zonei de memorie care va fi eliberată.

Exemplu: Să se aloce dinamic memorie pentru 20 de valori întregi.


int *p;
p=(int*)malloc(20*sizeof(int));
//p=(int*)calloc(20, sizeof(int));

Exerciţiul 1: Să se scrie un program care implementează funcţia numită introd_val.


Funcţia trebuie să permită introducerea unui număr de valori reale, pentru care se alocă
memorie dinamic. Valorile citite cu ajutorul funcţiei introd_val sunt prelucrate în funcţia
main, apoi memoria este eliberată.

#include <stdio.h>
#include <stdlib.h>
#include <alloc.h>
float *introd_val()
/* pentru a putea realiza eliberarea memoriei în funcţia main, funcţia introd_val trebuie
să returneze adresa de început a zonei de memorie alocate dinamic */
{double *p; int nr;printf("Număr valori:"); scanf("%d", nr);
if (!(p=(float*)malloc(nr*sizeof(float))) ){
printf("Memorie insuficientă!\n");return NULL;
}
for (int i=0; i<nr; i++){
printf("Val %d=", i+1); scanf("%lf", p+i); return p;}
}

void main()
{float *pt; pt=introd_val();
// prelucrare tablou
free(pt);
}

118
CAPITOLUL 6 Funcţii

Exerciţiu: Să se scrie un program care citeşte numele tuturor angajaţilor unei întreprinderi.
Numărul angajaţilor este transmis ca argument către funcţia main. Alocarea memoriei pentru
cei nr_ang angajaţi, cât şi pentru numele fiecăruia dintre aceştia se va face în mod dinamic.

#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void main(int argc, char *argv[])
{char **ang_ptr;
char *nume;
int nr_ang, i;
if (argc==2){
nr_ang=atoi(argv[1]);/* numărul angajaţilor este transmis ca argument
către funcţia main. El este convertit din şir de caractere în număr */
ang_ptr=(char**)calloc(nr_ang, sizeof(char*));
if ((ang_ptr==0){
printf("Memorie insuficientă!\n");exit(1);}
nume=(char*)calloc(30, sizeof(char));
for (i=0; i<nr_ang; ++i){
printf("Nume angajat:");
scanf("%s",nume);
ang_ptr[i]=(char*)calloc(strlen(nume)+1, sizeof(char));
strcpy(ang_ptr[i], nume);
}
free(nume);
printf("\n");
for (i=0; i<nr_ang; i++)
printf("Angajat nr %d: %s\n", i+1, ang_ptr[i]);}
else
printf("Lans.în execuţie:%s număr angajaţi\n", argv[0]);}

Pentru a putea afla memoria RAM disponibilă la un moment dat, se poate utiliza funcţia
coreleft, cu prototipul:
unsigned coreleft(void);

6.8.2. OPERATORI DE ALOCARE DINAMICĂ A MEMORIE

În limbajul C++ alocarea dinamică a memoriei şi eliberarea ei se pot realiza cu operatorii


new şi delete. Folosirea acestor operatori reprezintă o metodă superioară, adaptată
programării orientate obiect.
Operatorul new este un operator unar, care oferă posibilitatea alocării dinamice de memoriei
atât pentru date de tip predefinit, cât şi pentru date de tip definit de utilizator. Operatorul
returnează un pointer la zona de memorie alocată dinamic. În situaţia în care nu există
suficientă memorie şi alocarea nu reuşeşte, operatorul new returnează pointerul NULL.
Operatorul delete eliberează zona de memorie spre care pointează argumentul său.
Sintaxa:
<tipdata_pointer> = new <tipdata>;
<tipdata_pointer> = new <tipdata>(<val_iniţializare>);
//pentru iniţializarea datei pentru care se alocă memorie dinamic
<tipdata_pointer> = new <tipdata>[nr_elem];
//alocarea memoriei pentru un tablou
delete <tipdata_pointer>;
delete [<nr_elem>] <tipdata_pointer>;
//eliberarea memoriei pentru tablouri
119
CAPITOLUL 6 Funcţii

<tipdata> reprezintă tipul datei (predefinit sau obiect) pentru care se alocă dinamic
memorie, iar <tipdata_pointer> este o variabilă pointer către tipul tipdata.

Exerciţiul 1: Să se aloce dinamic memorie pentru o dată de tip întreg:


int *pint;
pint=new int;
//Sau:
int &i=*new int;
i=100; //i permite referirea la întregul păstrat în zona de memorie alocată dinamic

Exerciţiul 2: Să se aloce dinamic memorie pentru o dată reală, dublă precizie, iniţializând-o
cu valoarea -7.2.
double *p;
p=new double(-7.2);
//Sau:
double &p=* new double(-7.2);

Exerciţiul 3: Să se aloce dinamic memorie pentru un vector de m elemente reale.


double *vector; vector=new double[m];

Exerciţiul 4: Să se urmărească rezultatele execuţiei următorului program, care utilizează


pentru alocarea dinamică, respectiv eliberarea memoriei, operatorii new şi delete.
#include <iostream.h>
void main()
{
int index, *p1, *p2; p1 = &index; *p1 = 100;
p2 = new int(173);// *p2 = 173;
cout << "Valori:" <<index << " " <<*p1 << " " << *p2 << "\n";
//Valori: 100 100 173
p1 = new int; p2 = p1; *p1 = 9999;
cout << "Valori:" <<index << " " <<*p1 << " " << *p2 << "\n";
//Valori: 100 9999 9999
delete p1;
float *fp1, *fp2 = new float;
fp1 = new float;*fp2 = 3.14159;*fp1 = 3 * (*fp2);
delete fp2;delete fp1;
char *c_p;c_p = new char[50];delete c_p;
c_p = new char[sizeof('A') + 133];delete c_p;
}

Exemplu: Să se urmărească rezultatele execuţiei următorului program, care utilizează funcţia


coreleft.
#include <iostream.h>
#include <alloc.h>
#include <conio.h>
void main()
{ int *a,*b; clrscr();
cout<<"Mem. libera inainte de alocare:"<<coreleft()<<'\n';
cout<<"Adr. pointerilor a si b:"<<&a<<" "<<&b<<'\n';
cout<<"Val.point. a, b inainte de alocare:"<<a<<" "<<b<<'\n';
a=new int; b=new int[10];
cout<<"Mem. libera dupa alocare:"<<coreleft()<<'\n';
cout<<"Val.point. a, b dupa alocare:"<<a<<" "<<b<<'\n';
cout<<"Contin. Mem. alocate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
for (int k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k];
cout<<'\n'; getch();
120
CAPITOLUL 6 Funcţii

*a=1732;
for (int u=0;u<10;u++) b[u]=2*u+1;
cout<<"Cont. zonelor alocate dupa atrib:"<<"\n*a="<<*a<<"\nb=";
for (u=0;u<10;u++) cout<<"\nb["<<u<<"]="<<b[u];
delete a; delete b;
cout<<"Mem. libera dupa eliberare:"<<coreleft()<<'\n';
cout<<"Val. point a si b dupa eliberare:"<<a<<" "<<b<<'\n';
cout<<"Cont. mem. eliberate:\n"<<"*a="<<*a<<"\n*b="<<*b<<'\n';
for (k=0;k<10;k++) cout<<"\nb["<<k<<"]="<<b[k];
cout<<'\n'; cout<<b[3]; getch(); }

6.9. FUNCŢII RECURSIVE


O funcţie este numită funcţie recursivă dacă ea se autoapelează, fie direct (în definiţia ei se
face apel la ea însăşi), fie indirect (prin apelul altor funcţii). Limbajele C/C++ dispun de
mecanisme speciale care permit suspendarea execuţiei unei funcţii, salvarea datelor şi
reactivarea execuţiei la momentul potrivit. Pentru fiecare apel al funcţiei, parametrii şi
variabilele automatice se memorează pe stivă, având valori distincte la fiecare reapelare. Orice
apel al unei funcţii conduce la o revenire în funcţia respectivă, în punctul următor instrucţiunii
de apel. La revenirea dintr-o funcţie, stiva este curăţată (revine la starea dinaintea apelului).

Proiectarea unui algoritm recursiv trebuie să asigure ieşirea din recursivitate. De aceea, apelul
recursiv este întotdeauna inclus într-o structură de control de decizie sau repetitivă.

Un exemplu de funcţie recursivă este funcţia de calcul a factorialului, definită astfel:


fact(n)=1, dacă n=0; (parte a procesului recursiv care nu se defineşte prin el însuşi)
fact(n)=n*fact(n-1), dacă n>0;

Exemplu: Să se implementeze recursiv funcţia care calculează n!, unde n este introdus de la
tastatură:
#include <iostream.h>
int fact(int n)
{if (n<0){
cout<<"Argument negativ!\n";
exit(2);
}
else if (n==0) return 1;
else return n*fact(n-1);
}
void main()
{int nr, f; cout<<"nr="; cin>>nr;
f=fact(nr); cout<<nr<<"!="<<f<<'\n'; }

Se observă că în corpul funcţiei fact se apelează însăşi funcţia fact. Presupunem că nr=4
(iniţial, funcţia fact este apelată pentru a calcula 4!). Să urmărim diagramele din figurile 6.9. şi
6.10. La apelul funcţiei fact, valoarea parametrului de apel nr (nr=4) iniţializează
parametrul formal n. Pe stivă se memorează adresa de revenire în funcţia apelantă (adr1) şi
valoarea lui n (n=4) (figura 6.7.a.). Deoarece n>0, se execută intrucţiunea de pe ramura else
(return n*fact(n-1)). Funcţia fact se autoapelează direct. Evaluarea expresiei 4*fact(3) necesită
cunoaşterea operandului fact(3). Ca urmare, evaluarea se suspendă temporar, executându-se
apelul funcţiei fact(3). Se memorează pe stivă noua adresă de revenire şi noua valoare a
parametrului n (n=3) (figura 6.9.b.).

121
CAPITOLUL 6 Funcţii

La noul reapel al funcţiei fact, se execută din nou intrucţiunea de pe ramura else (return
n*fact(n-1)). Se memorează pe stivă adresa de revenire şi noua valoare a parametrului n (n=2)
(figura 6.9.c.). La noul reapel al funcţiei fact, se execută din nou intrucţiunea de pe ramura
else (return n*fact(n-1)). Se memorează pe stivă adresa de revenire şi noua valoare a
parametrului n (n=1) (figura 6.9.d.). La noul reapel al funcţiei fact, se execută din nou
intrucţiunea de pe ramura else (return n*fact(n-1)). Se memorează pe stivă adresa de revenire
şi noua valoare a parametrului n (n=0) (figura 6.9.e.).

În acest moment n=0 şi se revine din funcţie cu valoarea 1 (1*fact(0)=1*1), la configuraţia


stivei din figura 6.9.d.) (se curăţă stiva şi se ajunge la configuraţia din figura 6.9.d.). În acest
moment n=1 şi se revine cu valoarea 2*fact(1)=2*1=2, se curaţă stiva şi se ajunge la
configuraţia stivei din figura 6.9.c. În acest moment n=2 şi se revine cu valoarea
3*fact(2)=3*2=6, se curaţă stiva şi se ajunge la configuraţia stivei din figura 6.9.b. Se curăţă
stiva şi se ajunge la configuraţia stivei din figura 6.9.a.. În acest moment n=3 şi se revine cu
valoarea 4*fact(3)=4*6=24.

O funcţie recursivă poate fi realizată şi iterativ. Modul de implementare trebuie ales în funcţie
de problemă. Deşi implementarea recursivă a unui algoritm permite o descriere clară şi
compactă, recursivitatea nu conduce la economie de memorie şi nici la execuţia mai rapidă a
programelor. În general, se recomandă utilizarea funcţiilor recursive în anumite tehnici de
programare, cum ar fi unele metode de căutare (backtracking).

4 24
adr1 adr2 adr2 adr2 adr2
fact
n=4 n=3 n=2 n=1 n=0 0!= 3 6
adr1 adr2 adr2 adr2
fact
n=4 n=3 n=2 n=1
2 2
adr1 adr2 adr2
n=2 fact
(a) n=4 n=3
adr2 1 1
adr1
(b) n=4 n=3 fact
adr1 0 1
(c)
n=4 fact
(d)
Figura 6.9. Configuraţia stivei (e) Figura 6.10. Parametri funcţiei
fact

Exerciţiul 1: Fie şirul lui Fibonacci, definit astfel: f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-
2), dacă n>1. Să se scrie un program care implementează algoritmul de calcul al şirului
Fibonacci atât recursiv, cât şi iterativ. Să se compare timpul de execuţie în cele două situaţii.
#include <iostream.h>
#include <stdlib.h>
#include <conio.h>
#include <time.h>
#include <stdio.h>
long int iterativ_fib(long int n)//varianta de implementare iterativă
{if (n==0) return 0;
if (n==1) return 1;
int i; long int a, b, c; a=0; b=1;
for (i=2; i<=n; i++){
c=b; b+=a; a=c;}
return b; }

122
CAPITOLUL 6 Funcţii

long int recursiv_fib(long int n)//varianta de implementare recursivă


{if (n==0) return 0;
if (n==1) return 1;
long int i1=recursiv_fib(n-1);
long int i2=recursiv_fib(n-2);
return i1+i2;
}

void main()
{int n; clrscr();
cout<<MAXLONG<<'\n';
for (n=10; n<=40; n++) {
clock_t t1, t2, t3;
cout<<CLK_TCK<<'\n';
t1=clock(); long int f1=iterativ_fib(n);
t2=clock(); long f2=recursiv_fib(n); t3=clock();
double timp1=(double)(t2-t1)/CLK_TCK;
double timp2=(double)(t3-t2)/CLK_TCK;
printf("ITERATIV: %10ld t=%20.10lf\n",f1,timp1);
printf("RECURSIV: %10ld t=%20.10lf\n",f2,timp2);
cout<<"Apasa o tasta....\n"; getch();
}
}

În exemplul anterior, pentru măsurarea timpului de execuţie s-a utilizat funcţia clock, al
cărei prototip se află în header-ul time.h. Variabilele t1, t2 şi t3 sunt de tipul clock_t,
tip definit în acelaşi header. Constanta simbolică CLK_TCK defineşte numărul de bătăi ale
ceasului, pe secundă.

Exerciţiul 2: Să se calculeze suma S=1+2+3+…+n, unde n este introdus de la tastatură. Pentru


calculul sumei, se va folosi o funcţie recursivă.
#include <iostream.h>
#include <conio.h>

int sum_rec(int n)
{if (n==0) return 0;
else return (n+sum_rec(n-1));}

void main()
{clrscr();int nr, S;nr=9;
S= sum_rec(9);
cout<<"S="<<S<<'\n'; }

În general, orice algoritm care poate fi implementat iterativ, poate fi implementat şi recursiv.
Timpul de execuţie a unei recursii este semnificativ mai mare decât cel necesar execuţiei
iteraţiei echivalente.

Exerciţiul 3: Să se implementeze şi să se testeze un program care:


a) Generează aleator şi afişează elementele unui vector ;
b) Sortează aceste elemente, crescător, aplicând metodele de sortare BubbleSort,
InsertSort, şi QuickSort;
c) Să se compare viteza de sortare pentru vectori de diverse dimensiuni (10,30,50,100
elemente).

 Metoda BubbleSort a fost prezentată în capitolul 4.

123
CAPITOLUL 6 Funcţii

 Metoda QuickSort reprezintă o altă metodă de sortare a elementelor unui vector.


Algoritmul este recursiv: se împarte vectorul în două partiţii, faţă de un element pivot (de
obicei, elementul din “mijlocul vectorului”). Partiţia stângă începe de la indexul i (la
primul apel i=0), iar partiţia dreaptă se termină cu indexul j (la primul apel j=n-1)
(figura 6.11.).

... ....
i pivot j 0 n-1
n-1
0 j i
Figura 6.11. Sortare prin metoda QuickSort
Partiţia stângă este extinsă la dreapta (i incrementat) până când se găseşte un element mai
mare decât pivotul; partiţia dreaptă este extinsă la stânga (j decrementat) până când se găseşte
un element mai mic decât pivotul. Cele două elemente găsite, vect[i] şi vect[j], sunt
interschimbate.
Se reia ciclic extinderea partiţiilor până când i şi j se "încrucişează" (i devine mai mare ca
j). În final, partiţia stângă va conţine elementele mai mici decât pivotul, iar partiţia dreaptă -
elementele mai mari decât pivotul, dar nesortate.

Algoritmul este reluat prin recursie pentru partiţia stângă (cu limitele între 0 şi j ), apoi pentru
partiţia dreaptă (cu limitele între i şi n-1 ). Recursia pentru partea stângă se opreşte atunci
când j atinge limita stângă (devine 0), iar recursia pentru partiţia dreaptă se opreşte când i
atinge limita dreaptă (devine n-1).

SUBALGORITM QuickSort (vect[ ], stg, drt) //la primul apel stg = 0 si drt = n - 1
ÎNCEPUT SUBALGORITM
i ← stg
j ← drt
DACĂ i < j ATUNCI
ÎNCEPUT
pivot=vect[(stg+drt)/2]
CÂT TIMP i <= j REPETĂ
//extinderea partiţiilor stânga şi dreapta până când i se încrucişează cu j
ÎNCEPUT
CÂT TIMP i<drt si vect[i]<pivot REPETĂ
i = i + 1
CÂT TIMP j<stg si vect[j] >pivot REPETĂ
j = j - 1
DACĂ i<=j ATUNCI
ÎNCEPUT //interschimbă elementele vect[i] şi vect[j]
aux ← vect[i]
vect[i] ← vect[j]
vect[j] ← aux
i ← i+1
j ← j-1
SFÂRŞIT
SFÂRŞIT
DACĂ j>stg ATUNCI // part. stângă extinsa la max, apel qiuckSort pentru ea
CHEAMĂ QuickSort(vect, stg, j)
DACĂ i<drt ATUNCI //par. dreaptă extinsa la max, apel qiuckSort pentru ea
CHEAMĂ QuickSort(vect, i, drt)
SFÂRŞIT
SFÂRŞIT SUBALGORITM

124
CAPITOLUL 6 Funcţii

 Metoda InsertSort (metoda inserţiei)


Metoda identifică cel mai mic element al vectorului şi îl schimbă cu primul element. Se reia
procedura pentru vectorul iniţial, fără primul element şi se caută minimul în noul vector, etc.

SUBALGORITM InsertSort (vect[ ], nr_elem)


ÎNCEPUT SUBALGORITM
CÂT TIMP i< nr_elem REPETĂ
ÎNCEPUT
pozMin ← cautMinim(vect,i,nr_elem) //se apelează alg. cautMinim
aux ← vect[i]
vect[i] ← vect[pozMin]
vect[pozMin] ← aux
i ← i+1
SFÂRŞIT
SFÂRŞIT SUBALGORITM

Funcţia cautMin(vect[ ], indexIni, nr_elem) caută elementul minim al unui


vector, începând de la poziţia indexIni şi returnează poziţia minimului găsit.

Mod de implementare (Se va completa programul cu instrucţiunile care obţin şi afişează


timpului necesar ordonării prin fiecare metodă. Se vor compara rezultatele pentru un vector de
10, 30, 50, 100 elemente):

#include <stdlib.h>
#include <stdio.h>
#include <time.h>
#define TRUE 1
#define FALSE 0
void gener(double v[], int n)
//functia de generare aleatoare a elementelor vectorului v, cu n elemente
{for (int i=0; i<n; i++)
v[i]=1.0*rand()/100000;
}
void afis(double v[], int n)
//functia de afisare a vectorului
{for (int i=0; i<n; i++)
printf("%10.2f",v[i]);
printf("\n");
}
void copie_vect(double v1[], double v[], int n)
//functie de "duplicare "a unui vector; copie vectorul v in vectorul v1
{for (int i=0; i<n; i++)
v1[i]=v[i];
}
void bubbleSort(double v[], int n)
{int gata; gata=FALSE;
while (!gata){
gata=TRUE;
for (int i=0; i<n-1; i++)
if (v[i]>=v[i+1]){
double aux=v[i];
v[i]=v[i+1];
v[i+1]=aux;
// printf("Interschimbare element %d cu %d",i,i+1);
// afis(v,n);
gata=FALSE;}
}}

125
CAPITOLUL 6 Funcţii

int cautMin(double v[], int indexIni, int n)


// cauta elementul minim, incepând de la pozitia indexIni, inclusiv
{ double min=v[indexIni];
int pozMin=indexIni;
for (int i=indexIni; i<n; i++)
if (v[i]<=min){
min=v[i]; pozMin=i;
}
return pozMin;
}
void insertSort(double v[], int n)
{ int i;
for (i=0; i<n; i++){
int poz=cautMin(v, i, n);
double aux=v[i];
v[i]=v[poz];
v[poz]=aux;
}
}

void quickSort(double v[], int stg, int drt)


{int i,j; i=stg; j=drt; double pivot, aux;
if (i<j){
pivot=v[(stg+drt)/2];
while (i<=j){ //extindere partitie st si dr pana i se incrucis cu j
while (i<drt && v[i]<pivot) i++;
while (j>stg && v[j]>pivot) j--;
if (i<=j){
aux=v[i];v[i]=v[j];v[j]=aux; //interschimbare elemente
i++; j--;
}
}
if (j>stg) quickSort(v, stg, j);
if (i<drt) quickSort(v, i, drt);
}
}
void main()
{
clock_t ti,tf; int n; //n = nr elemente vector
printf("Nr componente vector:"); scanf("%d", &n);
double v[200], v1[200], v2[200], v3[200];
gener(v, n);
copie_vect(v1,v,n);
printf("\nInainte de ordonare: v1="); afis(v1, n); ti=clock();
bubbleSort(v1,n); tf=clock(); printf("\nDupa ord.:v1=");afis(v1, n);
printf("%10.7f", dif_b);
printf("\n\n****** INSERT SORT ******\n");
copie_vect(v2,v,n);
printf("\nInainte de ordonare INSERT: v2="); afis(v2, n);
insertSort(v2,n); printf("\nDupa ord. INSERT: v2=");afis(v2, n);
int st=0; int dr=n-1; copie_vect(v3, v, n);
printf("\n\n****** QUICK SORT ******\n");
printf("\nInainte ordonare QUICK: v3="); afis(v3, n);
quickSort(v3, st, dr); printf("\nDupa ordonare QUICK: v3=");
afis(v3, n);
}

126
CAPITOLUL 6 Funcţii

Exerciţiul 4: Problema turnurilor din Hanoi, inspirată dintr-o veche legendă: Se consideră
trei tije verticale (A, B şi C), fixate pe o placă. Pe una dintre tije (A) sunt aranjate discuri (cu
orificiu în centru), în ordinea descrescătoare a diametrelor. Scopul jocului este de a muta
turnul de discuri de pe tija iniţială (A) pe tija B, folosind tija C ca tijă de manevră. La fiecare
mutare se deplasează un singur disc, şi în nici o etapă nu este admis ca un disc mai mare să fie
aşezat peste un disc mai mic.

Notăm cele n discuri în ordinea descrescătoare a diametrelor (discul 1 în vârful turnului,


discul n - la baza turnului). Pentru a muta n discuri de pe tija A pe B, folosind C, se mută mai
întâi cele n-1 discuri de pe A pe B, folosind C; după mutarea discurilor de deasupra, poate fi
mutat discul de la baza turnului (discul n), de pe A pe B. Se aduc apoi deasupra acestuia (pe
B) toate discurile de pe C (cele n-1), folosind tija A (rămasă liberă). Această secvenţă se
repetă pentru un număr de discuri n>1. Deci rezolvarea problemei pentru n discuri s-a redus la
rezolvarea aceleeaşi probleme, pentru n-1 discuri. Rolul tijelor se schimbă în etapele
procesului de deplasare a discurilor, de aceea parametrii funcţiei hanoi specifică rolul
fiecărei tije.

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>
#define ERR 1
void hanoi(int n, char A, char B, char C)
{/* n-nr. discurilor
A-tija sursa
B-tija destinatie
C-tija de manevra */
if (n==1){
printf("Se muta discul %d de pe tija %c pe tija %c\n", n, A, B);
getch(); return;}

/* n>1 problema ptr n-1 discuri


A-tija sursa
C-tija destinatie
B-tija de manevra */

hanoi(n-1, A, C, B);
/* mutarea discului n de pe A pe B */
printf("Se muta discul %d de pe tija %c pe tija %c\n", n, A, B);
getch();
/* n>1 problema ptr n-1 discuri
C-tija sursa
B-tija destinatie
A-tija de manevra */
hanoi(n-1, C, B, A);
}

void main()
{int nr; clrscr();printf("Nr discuri=");
if (scanf("%d", &nr)!=1 || nr<=0){
//validarea numarului intreg citit (nr. discuri)
printf("Date intrare invalide!\n"); exit(ERR);}
else hanoi(nr, 'A', 'B', 'C');
}

127
CAPITOLUL 6 Funcţii

6.11. POINTERI CĂTRE FUNCŢII


Aşa cum s-a evidenţiat în capitolul 5, exista trei categorii de variabilele pointer:
 Pointeri cu tip;
 Pointeri generici (void);
 Pointeri către funcţii.

Pointerii către funcţii sunt variabile pointer care conţin adresa de început a codului executabil
al unei funcţii. Pointerii către funcţii permit:
 Transferul ca parametru al adresei unei funcţii (exerciţiul 2);
 Apelul unei funcţii cu ajutorul unui pointer către aceasta (exerciţiul 1).

Declaraţia unui pointer către funcţie are următoarea formă:


<tip> (*<nume_point>)(<lista_declar_param_formali>);
unde:
nume_point este un pointer de tipul “funcţie cu rezultatul tipul_valorii_întoarse”. În
declaraţia anterioară trebuie remarcat rolul parantezelor, pentru a putea face distincţie între
declaraţia unei funcţii care întoarce un pointer şi declaraţia unui pointer de funcţie:
tip_val_intoarse * nume_point (lista_declar_param_formali);
tip_val_intoarse (* nume_point)(lista_declar_param_formali);

Exemplu:
int f(double u, int v); //prototipul funcţiei f
int (*pf)(double, int); //declararea pointerului pf,către funcţia f
int i, j; double d;
pf=f; //atribuie adresa codului executabil al funcţiei f pointerului pf
j=*pf(d, i); //apelul funcţiei f, folosind pointerul către funcţie, pf

Exerciţiul 1: Să se implementeze exemplul următor, care ilustrează modul de utilizare a


pointerilor către funcţii.
#include <iostream.h>
#include <stdio.h>
void afis(float);
void afis1(float);
void afis_float(float);
void (*point_fc)(float); //declararea pointerului către funcţie point_fct
void main()
{ float pi = 3.14159; float dublu_pi = 2.0 * pi;
afis(pi); // Aceasta este functia afis.
point_fc = afis; point_fc(pi); // Aceasta este functia afis.
point_fc = afis1; point_fc(dublu_pi); // Data de afisat este 6.283180
point_fc(13.0); // Data de afisat este 13.000000
point_fc = afis_float; point_fc(pi); // Functia afis_float 3.141590
afis_float(pi); // Functia afis_float 3.141590
}
void afis(float data_de_ignorat)
{ printf("Aceasta este functia afis.\n"); }
void afis1(float lista_data)
{ printf("Data de afisat este %f\n", lista_data);}
void afis_float(float date_de_afis)
{ printf("Functia afis_float %f\n", date_de_afis);}

128
CAPITOLUL 6 Funcţii

Exerciţiul 2: Să se implementeze un program care calculează o funcţie a cărei valoare este


integrala altei funcţii. Pentru calculul integralei se va folosi metoda trapezelor.
f(x)
Relaţia pentru calculul integralei prin metoda
b
trapezelor pentru ∫ f ( x)dx
a
este:
n −1 a x1 x 2 x 3 . . . . x n −2 x n−1 b
I = (f(a)+f(b))/2 + ∑ f ( a + k * h)
k =1 h

| x|
Figura 6.9. Calculul integralei prin metoda
b
0 .2 + e 2 trapezelor
Să se calculeze
a
∫1+0 . 3 + ln(1 + x 4
)
dx,

cu o eroare mai mică decât eps (valoarea erorii introdusă de la tastatură).

#include <conio.h>
#include <math.h>
#include <iostream.h>

double functie(double x)
{return sqrt(0.1+exp(0.5*fabs(x)))/(1+sqrt(0.3+log(1+pow(x,4))));
}

double intrap(double a, double b, long int n, double (*f)(double))


{double h,s=0; long k;
if (a>=b)
return 0;
if (n<=0)
n=1;
h=(b-a)/n;
for (k=1; k<n; k++)
s+=f(a+k*h);
return ((f(a)+f(b))/2+s)*h;
}

void main()
{long int j; double p,q;
double eps, d2;double dif;
cout<<"Marg. inf:";cin>>p;
cout<<"Marg. sup:";cin>>q;
cout<<"Eroare:";cin>>eps; j=1;
double d1=intrap(p, q, j, functie);
do{ j*=2;
if (j>MAXLONG || j<0)
break;
d2=intrap(p, q, j, functie);
dif=fabs(d1-d2); d1=d2;
cout<<"Nr.intervale "<<j<<" Val.integralei "<<d2<<'\n';
}while (dif>eps);
cout<<"\n\n-----------------------------------------------\n";
cout<<"Val. integralei: "<<d2<<" cu eroare de:"<<eps<<'\n';
}

129
CAPITOLUL 6 Funcţii

6.12. ÎNTREBĂRI ŞI PROBLEME

ÎNTREBĂRI

1. Asemănări între transferul parametrilor 20. Ce sunt variabilele referinţă?


unei funcţii prin pointeri şi prin referinţă. 21. Cine determină timpul de viaţă şi
2. Caracteristicile modului de transfer a domeniul de vizibilitate ale unei
parametrilor unei funcţii prin pointeri. variabile?
3. Caracteristicile variabilelor globale. 22. Comparaţie între declararea şi definirea
4. Caracteristicile variabilelor locale. funcţiilor.
5. Care este diferenţa între antetul unei 23. Diferenţe între modurile de transfer a
funcţii şi prototipul acesteia? parametrilor prin valoare şi prin referinţă.
6. Care sunt modurile de alocare a 24. Din apelul funcţiei printf se poate omite
memoriei? specificatorul de format?
7. Care sunt modurile de transfer a 25. Din ce este formată o funcţie?
parametrilor unei funcţii? 26. În ce zonă de memorie se rezervă spaţiu
8. Care sunt operatorii din C++ care permit pentru variabilele globale?
alocarea/dealocarea dinamică a memoriei? 27. O funcţie poate fi declarată în corpul altei
9. Ce clase de memorare cunoasteţi? funcţii?
10. Ce este domeniul de vizibilitate a unei 28. O funcţie poate fi definită în corpul unei
variabile? alte funcţii?
11. Ce este prototipul unei funcţii? 29. Parametrii formali ai unei funcţii sunt
12. Ce este timpul de viaţă a unei variabile? variabile locale sau globale?
13. Ce loc ocupă declaraţiile variabilelor 30. Transferul parametrilor prin valoare.
locale în corpul unei funcţii? 31. Ce rol au parametrii formali ai unei
14. Ce reprezintă antetul unei funcţii? funcţii?
15. Ce rol are declararea funcţiilor? 32. Ce reprezintă supraîncărcarea unei
16. Ce se indică în specificatorul de format al funcţii?
funcţiei printf ? 33. Prin ce se deosebesc variabilele cu clasa
17. Ce sunt funcţiile cu număr variabil de de memorare register faţă de cale cu clasa
parametri? Exemple. de memorare auto?
18. Ce sunt funcţiile cu parametri impliciţi? 34. Diferenţe între modurile de transfer a
19. Ce sunt pointerii către funcţii? parametrilor unei funcţii prin pointeri şi
prin referinţă.

PROBLEME

1. Să se implementeze programele cu exemplele prezentate.

2. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.

3. Să se modularizeze programele din capitolul 4 (3.a.-3.g., 4.a.-4.i, 5.a.-5.h.), prin


implementarea unor funcţii (funcţii pentru: citirea elementelor unui vector, afişarea
vectorului, calculul sumei a doi vectori, calculul produsului scalar a doi vectori, aflarea
elementului minim din vector, citire a unei matrici, afişare a matricii, calculul transpusei

130
CAPITOLUL 6 Funcţii

unei matrici, calculul sumei a două matrici, calculul produsului a două matrici, calculul
produsului elementelor din triunghiul haşurat, etc.).

4. Să se rescrie programele care rezolvă exerciţiile din capitolul 3, folosind funcţii (pentru
calculul factorialului, aflarea celui mai mare divizor comun, ordonarea lexicografică a
caracterelor, etc). Utilizaţi funcţiile de intrare/ieşire printf şi scanf.

5. Să se scrie un program care citeşte câte două numere, până la întâlnirea perechii de
numere 0, 0 şi afişează, de fiecare dată, cel mai mare divizor comun al acestora, folosind o
funcţie care îl calculează.

6. Se introduce de la tastatura un număr întreg. Să se afişeze toţi divizorii numărului


introdus. Se va folosi o funcţie de calcul a celui mai mare divizor comun a 2 numere.

7. Secvenţele următoare sunt corecte din punct de vedere sintactic? Dacă nu, identificaţi
sursele erorilor.
 void a(int x, y) {cout<<"x="<<x<<" y="<<y<<'\n'; }
void main( ) { int b=9; a(6, 7); }
 void main( ) {int x=8; double y=f(x); cout<<"y="<<y<<'\n';}
int f(int z) {return z+z*z;}

8. Scrieţi o funcţie găseşte_cifra care returnează valoarea cifrei aflate pe poziţia k în


cadrul numărului n, începând de la dreapta (n şi k vor fi argumentele funcţiei).

9. Implementaţi propriile versiuni ale funcţiile de lucru cu şiruri de caractere.

10. Să se calculeze valoarea funcţiei g, cu o eroare EPS (a, b, EPS citite de la tastatură):
b b
g(x)= ∫ ( x + x + 1) *ln x + a dx +
2
∫ x * arctg (b (b + x)) dx
a a

11. Implementaţi funcţii iterative şi recursive pentru calculul valorilor polinoamelor Hermite
H n (y), ştiind că: H 0 (y)=1, H 1 (y)=2y, H n (x)=2yH n −1 (y)-2H n − 2 (y) dacă n>1.
Comparaţi timpul de execuţie al celor două funcţii.

12. Să se scrie un program care generează toate numerele palindrom, mai mici decât o valoare
dată, LIM. Un număr palindrom are cifrele simetrice egale (prima cu ultima, a doua cu
penultima, etc). Se va folosi o funcţie care testează dacă un număr este palindrom.

13. Fie matricea C (NXN), N<=10, ale cărei elemente sunt date de relaţia:
j
j! + ∑ sin(kx) , dacă i<j
k =0

C i, j = x , dacă i=j
i
, unde x ∈ [0,1], x introdus de la tastatură

i! + i ∑ cos(kx) , dacă i>j


k =0
a) Să se implementeze următoarele funcţii: de calcul a elementelor matricii; de afişare a
matricii; de calcul şi de afişare a procentului elementelor negative de pe coloanele
impare (de indice 1, 3, etc).
b) Să se calculeze şi să se afişeze matricea B, unde: B = C - C 2 + C 3 - C 4 + C 5 .

131
CAPITOLUL 6 Funcţii

11. Să se creeze o bibliotecă de funcţii pentru lucrul cu matrici, care să conţină funcţiile
utilizate frecvent (citirea elementelor, afisarea matricii, adunare a două matrici, etc). Să se
folosească această bibliotecă.

12. Să se creeze o bibliotecă de funcţii pentru lucrul cu vectori, care să conţină funcţiile
utilizate frecvent. Să se folosească această bibliotecă.

13. Să se calculeze cel mai mare divizor comun a două numere, folosind într-o funcţie
recursivă relaţia de recurenţă: cmmdc(a, b) = cmmdc(b, a%b).

14. Folosind o funcţie recursivă, să se inverseze un şir de caractere terminat cu blanc.

15. Să se scrie un program care determină cel mai mare divizor comun şi cel mai mic multiplu
comun a n numere naturale, nenule. Se va utiliza calculul recurent.

16. Să se calculeze S = C 0n + C 1n + C 2n + C 3n + . . . + C nn , unde n este un număr natural,


introdus de la tastatură. Se va folosi o funcţie pentru calculul C kn .

17. Să se calculeze S = A 0n + A 1n + A 2n + A 3n + . . . + A nn , unde n este un număr natural,


introdus de la tastatură. Se va folosi o funcţie pentru calculul A kn .

18. Să se calculeze S = 1! + 2! + 3! + . . . + n!, unde n este un număr natural, introdus de la


tastatură. Se va folosi o funcţie pentru calculul factorialului.

19. Fie n natural, citit de la tastatură (n<100). Să se determine toate tripletele de numere (x, y,
z) mai mici decât n, care sunt numere pitagorice (îndeplinesc relaţia x 2 + y 2 = z 2 ).
Numerele fiecărui triplet vor fi afişate în ordine crescătoare, pe câte o linie a ecranului.

20. Să se calculeze valorile următoarelor expresii (n natural, citit de la tastatura), folosind o


funcţie care calculează termenul general.
E(n)=1*(1+2)*(1+2+3)* . . . *(1+2+3+. . . +n)
E(n)=1*2 - 2*4 + 3*6 - 4*8 + . . . +(-1) n *n*2*n

132
CAPITOLUL 1 Noţiuni introductive

1. NOŢIUNI INTRODUCTIVE

1.1. Calculatorul, un sistem automat 1.4. Teoria rezolvării problemelor


de prelucrare a datelor cu ajutorul calculatorului
1.2. Algoritmi 1.5. Etapele rezolvării unei probleme
1.3. Limbaje de programare

1.1. CALCULATORUL, UN SISTEM AUTOMAT DE PRELUCRARE A


DATELOR
Calculatorul (mai precis, calculatorul numeric programabil) reprezintă un sistem electronic
(ansamblu de dispozitive şi circuite diverse) complex, care preia (citeşte) datele iniţiale ale
unei probleme, pe baza unui program efectuează diverse operaţii (prelucrări) asupra acestora
şi furnizează (scrie, afişează) rezultatele obţinute (figura 1.1.).

Date de intrare Date de ieşire


(datele iniţiale ale PROGRAM (şir de acţiuni, prelucrări, algoritm) (rezultatele obţinute)
problemei)

Figura 1.1. Calculatorul - sistem automat de prelucrare a datelor

Principalele avantaje ale utilizării calculatorului constau în:


 viteza mare de efectuare a operaţiilor;
 capacitatea extinsă de prelucrare şi memorare (înregistrare) a informaţiei.

În orice sistem de calcul vom găsi două părţi distincte şi la fel de importante: hardware-ul şi
software-ul.
 Hardware-ul este reprezentat prin totalitatea echipamentelor şi dispozitivelor fizice;
 Software-ul este reprezentat prin totalitatea programelor care ajută utilizatorul în
rezolvarea problemelor sale (figura 1.2.).

Software-ul are două componente principale:


 Sistemul de operare (de exploatare) care coordonează întreaga activitate a
echipamentului de calcul; acesta “este activat” la pornirea calculatorului şi asigură:
 Gestiunea echitabilă şi eficientă a resurselor din cadrul sistemului de calcul;
 Realizarea interfeţei cu utilizatorul;
 Furnizarea suportului pentru dezvoltarea şi execuţia aplicaţiilor.
Exemple de sisteme de operare: RSX11, CP/M, MS-DOS, LINUX, WINDOWS NT, UNIX.
 Sistemul de aplicaţii (de programe), care poate include: medii de programare, editoare
de texte, compilatoare, programe aplicative din diverse domenii (economic, ştiinţific,
financiar, divertisment).

9
CAPITOLUL 1 Noţiuni introductive

SISTEM OPERARE

HARDWARE UTILIZATOR

SOFTWARE DE
APLICAŢIE SOFTWARE

Figura 1.2. Sistemul de calcul - sistem hardware-software

1.1.1. UNITĂŢILE FUNCŢIONALE ALE UNUI SISTEM DE CALCUL

Componentele unui sistem de calcul pot fi grupate în unităţi cu funcţii complexe, bine
precizate, numite unităţi funcţionale. Modelul din figura 1.3. face o prezentare simplificată a
structurii unui calculator, uşurând înţelegerea unor noţiuni şi concepte de bază privind
funcţionarea şi utilizarea acestuia. Denumirea fiecărei unităţi indică funcţia ei, iar săgeţile -
modul de transfer al informaţiei.

Unitate de intrare Memorie internă Unitate de ieşire


(flux de intrare - istream în (flux de ieşire - ostream în
C++) C++)
Unitate centrală

Memorie externă

Figura 1.3. Unităţile funcţionale ale unui sistem de calcul


Înainte de a prezenta unităţile funcţionale ale sistemului de calcul, trebuie să subliniem faptul
că, într-un calculator, toată informaţia (numere, cuvinte, texte, desene, imagini, sunete, etc.)
este reprezentată sub formă numerică. Programele sunt codificate tot sub formă numerică.
Vom utiliza în continuare termenii de citire pentru operaţia de introducere (de intrare) de la
tastatură a datelor iniţiale ale unei probleme, şi scriere pentru operaţia de afişare (de ieşire) a
rezultatelor obţinute. În cazul în care utilizatorul doreşte să rezolve o problemă cu ajutorul
calculatorului, informaţia de intrare (furnizată calculatorului de către utilizator) va consta din
datele iniţiale ale problemei de rezolvat şi dintr-un program (numit program sursă). În
programul sursă utilizatorul implementează (traduce) într-un limbaj de programare un
algoritm (acţiunile executate asupra datelor de intrare pentru a obţine rezultatele). Informaţia
de intrare, aflată iniţial într-o formă externă, accesibilă omului (numere, text, grafică), va fi
transformată de către calculator - în vederea memorării şi prelucrării - într-o formă internă,
binară.

Unitatea de intrare (cu funcţia de citire) realizează această conversie a informaţiei din
format extern în cel intern. Din punct de vedere logic, fluxul (informaţia) de intrare este un şir
de caractere, din exterior către memoria calculatorului. Din punct de vedere fizic, unitatea de
intrare standard este, uzual, tastatura calculatorului. Tot ca unităţi de intrare, pot fi enumerate:
mouse-ul, joystick-ul, scanner-ul (pentru introducerea informaţiilor grafice).

10
CAPITOLUL 1 Noţiuni introductive

Unitatea de ieşire (cu funcţia de scriere, afişare) realizează conversia inversă, din formatul
intern în cel extern. Din punct de vedere fizic, unitatea de ieşire standard este monitorul
calculatorului. Tot ca unităţi de ieşire într-un sistem de calcul, putem întâlni: imprimanta,
plotter-ul, etc.

Informaţia este înregistrată în memorie.


Memoria internă (memoria RAM - Random Acces Memory) se prezintă ca o succesiune de
octeţi (octet sau byte sau locaţie de memorie). Un octet reprezintă un grup de 8 biţi. Bit-ul
(binary unit) reprezintă unitatea elementară de informaţie şi poate avea una din valorile: 0 sau
1. Numărul de ordine al unui octet în memorie se poate specifica printr-un cod, numit adresă.
Ordinea în care sunt adresate locaţiile de memorie nu este impusă, memoria fiind un
dispozitiv cu acces aleator la informaţie.
Capacitatea unei memorii este dată de numărul de locaţii pe care aceasta le conţine şi se
măsoară în multiplii de 1024 (2 10 ), cum sunt kilobytes, megabytes, gigabytes sau terabytes.
De exemplu, 1Kb=1024bytes, 1 Mb=1024Kb;.
În memorie se înregistrează două categorii de informaţii:
 Date - informaţii de prelucrat;
 Programe - conţin descrierea (implementarea într-un limbaj de programare) a
acţiunilor care vor fi executate asupra datelor, în vederea prelucrării acestora.
În memoria internă este păstrată doar informaţia prelucrată la un moment dat. Memoria
internă are capacitate redusă; accesul la informaţia din memoria internă este extrem de rapid,
iar datele nu sunt păstrate după terminarea prelucrării (au un caracter temporar).

Unitatea centrală prelucrează datele din memoria internă (extrage din memoria internă,
secvenţial, instrucţiunile programului, le decodifică şi le execută, efectuează operaţii
aritmetice şi logice asupra datelor) şi coordonează activitatea tuturor componentelor fizice ale
unui sistem de calcul (transmite comenzi celorlalte unităţi funcţionale). Ea înglobează:
 Microprocesorul - circuit integrat complex cu următoarele componente de bază:
 Unitatea de execuţie (realizează operaţii logice şi aritmetice);
 Unitatea de interfaţă a magistralei (transferă datele la/de la microprocesor).
 Coprocesorul matematic – circuit integrat destinat realizării cu viteză sporită a
operaţiilor cu numere reale.

Memoria externă este reprezentată, fizic, prin unităţile de discuri (discuri dure-hard disk,
discuri flexibile-floppy disk, discuri de pe care informaţia poate fi doar citită-CDROM,
DVDROM, etc) sau benzi magnetice. Spre deosebire de memoria internă, memoria externă
are capacitate mult mai mare, iar informaţia înregistrată în memoria externă are caracter
permanent, în dezavantajul timpului de acces la aceasta.

1.1.2. DATE, ALGORITMI ŞI PROGRAME

Datele sunt reprezentări simbolice (numere, cuvinte, texte, imagini, sunete) care vor fi
transformate în format intern, binar (şiruri de biţi), înregistrate în memoria calculatorului şi
supuse unor prelucrări. Datele, în sine, nu au semnificaţie, însă atunci când sunt interpretate
de către un anumit sistem de prelucrare, ele devin informaţie.

Algoritmul este conceptul fundamental al informaticii. Într-o definiţie aproximativă


algoritmul este un set de paşi care defineşte modul în care poate fi dusă la îndeplinire o
anumită sarcină. Reprezentarea (descrierea) unui algoritm nu se poate face în absenţa unui
limbaj comun celor care vor să îl înţeleagă. Pentru ca algoritmii să poată fi reprezentaţi astfel

11
CAPITOLUL 1 Noţiuni introductive

încât să fie înţeleşi de către oameni, se folosesc diferite limbaje artificiale, cum sunt
pseudocodul şi schema logică.

După descoperirea algoritmului, pasul următor este reprezentarea acestuia într-o formă în care
să poată fi comunicat unei maşini de calcul. Reprezentarea algoritmilor destinaţi
calculatoarelor se face prin programe, scrise în limbaje de programare (limbaje artificiale,
riguros formalizate). Programul este un ansamblu de instrucţiuni, pe care calculatorul le
execută pentru a rezolva o anumită problemă. Programul conţine atât informaţii despre datele
care vor fi prelucrate (date de intrare, de ieşire, auxiliare), cât şi despre algoritmul aplicat în
prelucrarea acestora: Program = Date + Algoritm.

Orice echipament de calcul poate fi considerat o maşină algoritmică, capabilă să stocheze


datele, dar să le şi prelucreze, conform unui algoritm. Pentru aceasta, maşina trebuie să
dispună de mecanisme care să permită efectuarea operaţiilor asupra datelor, dar şi
coordonarea secvenţelor de operaţii. În realitate, programatorul nu scrie programul pentru
calculatorul real, ci pentru un calculator abstract - un model care elimină detaliile, păstrând
numai elementele necesare limbajului de programare folosit. Schema calculatorului abstract
trebuie să ţină seama atât de calculatorul real modelat, cât şi de limbajul de programare
utilizat. În general, un calculator abstract are un set de instrucţiuni, un set de regiştri şi un
model de memorie.

Un model abstract al unei unităţi centrale (CPU, microprocesor) este prezentat în figura 1.4..

Unitatea de control
Registrii procesorului sunt, asemeni locaţiilor
de memorie, dispozitive în care se memorează
numere binare de lungime fixă, specifică
Contorul programului (PC) procesorului respectiv. Într-un registru poate fi
încărcat un număr întreg de octeţi (1, 2, 4).
Registru instrucţiune (RI) Unitatea aritmetică şi logică efectuează
operaţiile de calcul (adunare, scădere, înmulţire,
Indicatori împărţire, etc.).
Unitatea de control îşi realizează sarcinile
ALU repetând aşa-numitul ciclu al maşinii:
(Unitatea aritmetică şi logică) repetă
extrage următoarea instrucţiune din
Regiştrii de memorare memorie (pe baza adresei aflate în PC).
Regiştrii date Regiştrii adrese decodifică instrucţiunea (şirul de biţi) din
registrul de instrucţiuni, RI (analizează
codul operaţiei şi adresa operandului).
execută instrucţiunea (efectuarea operaţiei
cerute de instrucţiunea aflată în RI).
până la execuţia instrucţiunii “halt”, de
Fig. 1.4. Componentele procesorului oprire.
abstract

Instrucţiunile dintr-un program sunt codificate intern tot prin numere binare, care vor fi
înregistrate în memorie, formate din cel puţin două părţi: codul operaţiei şi adresa
operandului. Ca operaţii, se pot exemplifica: încărcarea (transferul unui operand din memorie
într-un registru); memorarea (înregistrarea la o anumită adresă din memorie a conţinutului
unui registru); operaţii de calcul - aritmetice sau logice - efectuate între operanzii din registre
sau între un operand dintr-un registru şi unul din memorie, etc.

12
CAPITOLUL 1 Noţiuni introductive

Una din primele descrieri a unui calculator programabil - cu o foarte mare influenţă asupra
evoluţiei ulterioare a calculatoarelor - a fost “maşina von Neumann”, formată din unitatea
aritmetică şi logică, unitatea de control, unitatea de intrare/ieşire şi unitatea de memorie.
Caracteristica principală a maşinii von Neuman este aceea că, funcţionarea ei este un proces
secvenţial: la un moment dat se execută o singură instrucţiune, iar execuţia unei instrucţiuni
poate începe numai după încheierea execuţiei instrucţiunii precedente. Deşi, odată cu evoluţia
calculatoarelor, au apărut abateri de la acest model (introducerea accesului direct la memorie
al unităţilor de intrare/ieşire, apariţia calculatoarelor multiprocesor, etc.), majoritatea
limbajelor de programare sunt realizate pentru calculatoare abstracte de tip von Neumann.

1.2. ALGORITMI
Algoritmul este conceptul fundamental al informaticii. Intuitiv, un exemplu de algoritm poate
fi cel de interpretare a unei bucăţi muzicale (descris prin partitură). Pentru ca o maşină de
calcul să poată rezolva o anumită problemă, programatorul trebuie mai întâi să stabilească un
algoritm care să conducă la efectuarea sarcinii respective.

Exemplu:
Algoritmul lui Euclid pentru determinarea celui mai mare divizor comun (cmmdc) a 2
numere întregi pozitive.
Date de intrare: cele 2 numere întregi.
Date de ieşire: cel mai mare divizor comun al numerelor (cmmdc).
1. Se notează cu A şi B- cea mai mare, respectiv cea mai mică, dintre datele de intrare.
2. Se împarte A la B şi se notează cu R restul împărţirii.
3. a. Dacă R diferit de 0, se atribuie lui A valoarea lui B şi lui B valoarea lui R. Se
revine la pasul 2.
b. Dacă R este 0, atunci cmmdc este B.

1.2.1. DEFINIŢII ŞI CARACTERISTICI

Descoperirea unui algoritm care să rezolve o problemă echivalează în esenţă cu descoperirea


unei soluţii a problemei. Căutarea unor algoritmi pentru rezolvarea unor probleme din ce în ce
mai complexe a avut ca urmare apariţia unor întrebări legate de limitele proceselor
algoritmice:
 Ce probleme pot fi rezolvate prin intermediul proceselor algoritmice?
 Care sunt modalităţile de descoperire a algoritmilor?
 Cum pot fi îmbunătăţite tehnicile de reprezentare şi comunicare a algoritmilor?
 Cum pot fi aplicate cunoştinţele dobândite în vederea obţinerii unor maşini algoritmice
mai performante?
 Cum pot fi analizate şi comparate caracteristicile diverşilor algoritmi?

Definiţie:
Algoritmul este un set ordonat de paşi executabili, descrişi fără echivoc, care definesc un
proces finit.

Proprietăţile fundamentale ale algoritmilor:


 Caracterul finit: orice algoritm bine proiectat se termină într-un număr finit de paşi;
 Caracterul unic şi universal: orice algoritm trebuie să rezolve toate problemele dintr-o
clasă de probleme, să poată fi aplicat oricărui set de date de intrare dintr-o anumită
mulţime de astfel de seturi de date avută în vedere.

13
CAPITOLUL 1 Noţiuni introductive

 Caracter realizabil: orice algoritm trebuie să poată fi codificat în limbajul de programare


pentru care a fost conceput;
 Caracterul discret: fiecare acţiune a algoritmului (numită şi pas al algoritmului) se
execută la un moment dat de timp;
 Caracterul determinist: ordinea acţiunilor în execuţie este determinată în mod unic de
rezultatele obţinute la fiecare moment de timp; prin aplicarea aceluiaşi algoritm asupra
aceloraşi date, trebuie să se obţină acelaşi rezultat.
Nerespectarea acestor caracteristici generale conduce la obţinerea de algoritmi neperformanţi,
posibil infiniţi sau nerealizabili.

1.2.2. REPREZENTAREA ALGORITMILOR

Reprezentarea (descrierea) unui algoritm se poate face doar printr-un limbaj comun celor care
vor să îl înţeleagă. Pentru creşterea rigurozităţii în modul de reprezentare a algoritmilor, au
fost introduse diferite limbaje artificiale, bazate pe o mulţime bine definită de primitive
(blocuri elementare pe care se bazează reprezentarea). Fiecare primitivă se caracterizează prin
sintaxă (reprezentarea simbolică a primitivei) şi semantică (semnificaţia primitivei). De
exemplu, în limbajul natural (în limba română), primitiva aer este, din punct de vedere
sintactic, un cuvânt format din trei simboluri (litere); din punct de vedere semantic, este o
substanţă gazoasă care înconjoară globul pământesc.
Cele mai răspândite limbaje artificiale (destinate oamenilor) de reprezentare a algoritmilor
sunt:
 schema logică;
 pseudocodul.

1.2.2.1. Reprezentarea algoritmilor prin scheme logice


Primitivele utilizate în schemele logice sunt simboluri grafice, cu funcţiuni (reprezentând
procese de calcul) bine precizate. Aceste simboluri sunt unite prin arce orientate care indică
ordinea de execuţie a acţiunilor.

Categoriile de simboluri utilizate în schemele logice:

 Simboluri de început şi sfârşit


Simbolurile START şi STOP desemnează
START STOP începutul, respectiv sfârşitul unui algoritm
(program sau subprogram). Prezenţa lor
este obligatorie.

 Simbolul paralelogram

Semnifică procese (operaţii) de


CITEŞTE a, b AFIŞEAZĂ a, b intrare/ieşire (citirea datelor de
intrare sau scrierea, afişarea
rezultatelor).
 Simbolul dreptunghi

Semnifică calcul şi/sau atribuire


a ←34 (modificarea valorii unei date).

14
CAPITOLUL 1 Noţiuni introductive

 Simbolul romb
Simbolul romb este utilizat în situaţiile care
necesită luarea unei decizii (figura 1.5.).
NU Condiţie DA Se testează îndeplinirea condiţiei din
îndeplinită? blocul de decizie. Dacă această condiţie
este îndeplinită, se execută ACŢIUNE1.
Dacă nu, se execută ACŢIUNE2. La un
ACŢIUNE2 ACŢIUNE1
moment dat, se execută sau ACŢIUNE1,
sau ACŢIUNE2.

Figura 1.5. Structura de decizie

Cu ajutorul acestor simboluri grafice se poate reprezenta orice algoritm. Repetarea unei
secvenţe se realizează prin combinarea simbolurilor de decizie şi de atribuire. Structurile
repetitive obţinute pot fi: cu test iniţial sau cu test final.
 Structură de control repetitivă, cu test iniţial
Se evaluează condiţia de test (figura 1.6.).
Dacă aceasta este îndeplinită, se execută
ACŢIUNE1. Se revine apoi şi se testează
iar condiţia. Dacă este îndeplinită, se
NU DA
execută (se repetă) ACŢIUNE1, ş.a.m.d.
Condiţie Abia în momentul în care condiţia nu mai
îndeplinită?
este îndeplinită, se execută ACŢIUNE2.
Astfel, cât timp condiţia este îndeplinită,
ACŢIUNE2 ACŢIUNE1 se repetă ACŢIUNE1. În cazul în care, la
prima testare a condiţiei, aceasta nu este
îndeplinită, se execută ACŢIUNE2.
Astfel, este posibil ca ACŢIUNE1 să nu
fie executată niciodată.
Figura 1.6. Structură repetitivă cu test iniţial

În situaţiile în care se ştie de la început de câte ori se va repeta o anumită acţiune, se foloseşte
tot o structură de control repetitivă cu test iniţial. Se utilizează un contor (numeric) pentru a
ţine o evidenţă a numărului de execuţii ale acţiunii. La fiecare execuţie a acţiunii, contorul
este incrementat.
contor ← valoare_iniţială
Se atribuie contorului valoarea iniţială
(figura 1.7.). Cât timp condiţia
NU
val_contor ←
DA (valoarea contorului este mai mică sau
val_finală egală cu valoarea finală) este îndeplinită,
se repetă:
 ACŢIUNE
ACŢIUNE
 incrementare contor (se adună 1 la
valoarea anterioară a contorului).
val_contor ← val_contor + 1

Figura 1.7. Structură repetitivă cu test iniţial,


cu număr cunoscut de paşi

15
CAPITOLUL 1 Noţiuni introductive

 Structură de control repetitivă, cu test final:


Se execută mai întâi ACŢIUNE1. Se
testează apoi condiţia (figura 1.8.). Se
ACŢIUNE1 repetă ACŢIUNE1 cât timp condiţia
este îndeplinită.
În acest caz, corpul ciclului (ACŢIUNE1)
DA
Condiţie este executat cel puţin o dată.
îndeplinită

NU
ACŢIUNE2

Figura 1.8. Structură repetitivă cu test final

1.2.2.2. Reprezentarea algoritmilor prin pseudocod

Pseudocodul este inspirat din limbajele de programare, nefiind însă atât de formalizat ca
acestea; fiind o reprezentare textuală, bazată pe un vocabular restrâns, reprezintă o punte de
legătură între limbajul natural şi limbajele de programare. Nu există un standard pentru
regulile lexicale. La fel ca şi schema logică, limbajul pseudocod permite comunicarea între
oameni, şi nu comunicarea om-maşină (precum limbajele de programare). Pseudocodul
utilizează o serie de cuvinte cheie (scrise cu majuscule subliniate) cu următoarele semnificaţii:

Sfârşit algoritm: SFÂRŞIT


Început algoritm: ÎNCEPUT
Citire (introducere) date: CITEŞTE lista_valori
Scriere (afişare) date: SCRIE lista_valori
Atribuire: <-
Structura de decizie (alternativă): DACĂ condiţie
ATUNCI acţiune1
ALTFEL acţiune2
Structuri repetitive cu test iniţial: CÂT TIMP condiţie
REPETĂ acţiune
PENTRU contor=val_iniţ LA val_fin [PAS]
REPETĂ acţiune;
Structuri repetitive cu test final:
REPETĂ acţiune CÂT TIMP condiţie
sau:
REPETĂ acţiune PÂNĂ CÂND condiţie

Pe lângă cuvintele cheie, în reprezentarea algoritmilor în pseudocod pot apare şi propoziţii


nestandard, a căror detaliere va fi realizată ulterior.
În cazul în care se realizează un algoritm modularizat, pot apare cuvintele cheie:
SUBALGORITM nume (lista_intrări)
CHEAMĂ nume (lista_valori_efective_de_intrare)

Reprezentarea algoritmilor prin schemă logică oferă avantajul clarităţii şi expresivităţii


sporite, în dezavantajul spaţiului mare necesar reprezentării. Reprezentarea prin pseudocod
este mai puţin expresivă, însă de întindere mică, fiind mai apropiată de limbajele de
programare.

16
CAPITOLUL 1 Noţiuni introductive

Aşa cum se observă, operaţiile folosite în descrierea unui algoritm sunt:


 Operaţii de intrare/ieşire, care permit comunicarea între viitorul program şi utilizator;
 Operaţii de calcul şi atribuire;
 Operaţii de control, care exprimă raţionamentul uman.

Exemple:
Se vor reprezenta în continuare algoritmii de rezolvare pentru câteva probleme simple (pentru
primele 2 probleme se exemplifică şi implementarea algoritmilor în limbajul C++).

1. Se citesc 2 valori numerice reale, care reprezintă dimensiunile (lungimea şi lăţimea unui
dreptunghi). Să se calculeze şi să se afişeze aria dreptunghiului.

ALGORITM aflare_arie_drept
ÎNCEPUT
START CITEŞTE L,l
aria <- L*l
AFIŞEAZĂ aria
SFÂRŞIT
CITEŞTE L, l

aria <- L * l Implementare: #include <iostream.h>


void main( )
{ double L, l;
cout<<"Lungime="; cin>>L;
AFIŞEAZĂ aria cout<<"Laţime="; cin>>l;
double aria = L * l;
cout << "Aria="<< aria;
}
STOP

2. Se citesc 2 valori reale. Să se afişeze valoarea maximului dintre cele 2 numere.

ALGORITM max_2_nr ALGORITM max_2_nr


Sau: ÎNCEPUT
ÎNCEPUT
CITEŞTE a, b CITEŞTE a, b
DACĂ a >= b DACĂ a >= b
ATUNCI max<-a ATUNCI AFIŞEAZĂ a
ALTFEL max<-b ALTFEL AFIŞEAZĂ b
AFIŞEAZĂ max SFÂRŞIT
SFÂRŞIT

Implementare în limbajul C++:


#include <iostream.h> #include <iostream.h>
void main( ) void main( )
{ float a, b, max; { float a, b;
cout<<"a="; cin>>a; cout<<"a=";cin>>a;
cout<<"b="; cin>>b; cout<<"b="; cin>>b;
if (a >= b) if (a >= b)
max = a; cout<<"Maximul este:"<<a;
else max = b; else
cout<<"Maximul este:"<<max; cout<<"Maximul este:"<<b;
} }

17
CAPITOLUL 1 Noţiuni introductive

3. Să se citească câte 2 numere întregi, până la întâlnirea perechii de numere 0, 0. Pentru


fiecare pereche de numere citite, să se afişeze maximul.

Algoritm care utilizează structură repetitivă cu test iniţial:


ALGORITM max_perechi1 ALGORITM max_perechi2
ÎNCEPUT ÎNCEPUT
CITEŞTE a,b a <- 3
CÂT TIMP(a#0sau b#0)REPETĂ CÂT TIMP (a#0 sau b#0) REPETĂ
ÎNCEPUT ÎNCEPUT
DACA (a>=b) CITEŞTE a, b
ATUNCI AFIŞEAZĂ a DACĂ (a>=b)
ALTFEL AFIŞEAZĂ b ATUNCI AFIŞEAZĂ a
CITEŞTE a,b ALTFEL AFIŞEAZĂ b
SFÂRŞIT SFÂRŞIT
SFÂRŞIT SFÂRŞIT

Algoritm care utilizează structură repetitivă cu test final:


ALGORITM max_perechi3
ÎNCEPUT
REPETĂ
ÎNCEPUT
CITEŞTE a,b
DACĂ (a>=b)
ATUNCI AFIŞEAZĂ a
ALTFEL AFIŞEAZĂ b
SFÂRŞIT
CÂT TIMP (a#0 sau b#0)
SFÂRŞIT

1.3. LIMBAJE DE PROGRAMARE

Algoritmul de rezolvare a unei probleme trebuie transcris (pentru a putea fi înţeles de către
calculator) din forma conceptuală într-un set clar de instrucţiuni, reprezentate într-un mod
lipsit de ambiguitate. În acest domeniu, studiile bazate pe cunoştinţele privitoare la gramatică
şi limbaj au condus la o mare varietate de scheme de reprezentare a algoritmilor (numite
limbaje de programare), bazate pe diverse abordări ale procesului de programare (numite
paradigme de programare).

Definiţie:
Limbajele de programare sunt limbaje artificiale, care permit o descriere - riguros
formalizată - a datelor şi a algoritmului, într-un program, care să fie înţeles de către
calculator.

1.3.1. Scurt istoric

Limbajele de programare au cunoscut o lungă evoluţie, determinată de scopul ca un program


scris într-un anumit limbaj să poată fi înţeles cât mai uşor de către om. Principalele etape ale
evoluţiei sunt marcate de dezvoltarea următoarelor limbaje de programare:

Limbaje din generaţia întâi: Limbajele maşină (cod maşină), în care datele şi instrucţiunile
erau exprimate sub o formă binară, specifică doar maşinii pe care se execută programul.

18
CAPITOLUL 1 Noţiuni introductive

Limbaje din generaţia a doua: Limbajele de asamblare, în care se folosesc mnemonice


pentru instrucţiunile limbajului maşină (de exemplu, pentru operaţia de încărcare într-un
registru, nu se mai foloseşte codul binar al acesteia, ci mnemonicul LD) şi nume descriptive
(numite adesea identificatori) pentru operanzi (nume care înlocuiesc adresele de memorie ale
operanzilor). Programul scris în limbaj de asamblare este convertit, automat, în cod maşină,
de către programul numit asamblor. Dezavantajele limbajelor de asamblare sunt, în principal,
dependenţa de o anumită maşină şi nivelul scăzut al primitivelor folosite de către
programator.

Limbaje din generaţia a treia, sau limbajele de nivel înalt sunt limbaje de programare
apropiate de limbajele umane naturale (cu primitive de nivel înalt), puternic formalizate.
Exemple de astfel de limbaje: Basic (limbaj interpretat), FORTRAN, Pascal, C, C++ (limbaje
compilate), etc.
Programele scrise într-un limbaj de nivel înalt sunt, independente de maşină (nu chiar 100%),
deci portabile (pot fi transferate pe diferite platforme).
În cazul limbajelor compilate, programul sursă, exprimat cu ajutorul primitivelor de nivel
înalt, este compilat, translatat în limbaj maşină (de către compilator), specific calculatorului
pe care se va executa. Fiecare instrucţiune din programul în limbaj de nivel înalt este
înlocuită, de regulă, de către compilator, prin mai multe instrucţiuni în cod maşină. În timpul
execuţiei, în memoria calculatorului se găseşte programul binar rezultat după compilare; acest
program poate fi executat direct de către procesorul calculatorului respectiv, deoarece
foloseşte setul de instrucţiuni specific acestuia.

În cazul limbajelor interpretate, în timpul execuţiei programului, în memoria calculatorului se


găseşte chiar programul sursă, împreună cu un program binar numit interpretor. Acesta
parcurge instrucţiunile programului sursă şi le interpretează, adică le traduce în instrucţiuni
binare, aparţinând setului de instrucţiuni ale procesorului, şi le transmite procesorului spre
execuţie.

1.3.2. Limbajele C şi C++

Limbajele C şi C++ sunt limbaje de programare de nivel înalt.

Limbajul C a apărut în anii 1970 şi a fost creat de Dennis Ritchie în laboratoarele AT&T
Bell. Limbajul C face parte din familia de limbaje concepute pe principiile programării
structurate, la care ideea centrală este “structurează pentru a stăpâni o aplicaţie”. Proiectat
iniţial pentru dezvoltarea sistemelor de operare şi a compilatoarelor, popularitatea limbajului a
crescut rapid datorită eleganţei şi a multiplelor posibilităţi oferite programatorului (puterea şi
flexibilitatea unui limbaj de asamblare); ca urmare, au apărut numeroase alte implementări.
De aceea, în anii ’80 se impune necesitatea standardizării acestui limbaj. În perioada 1983-
1990, un comitet desemnat de ANSI (American National Standards Institute) a elaborat un
compilator ANSI C, care permite scrierea unor programe care pot fi portate fără modificări,
pe orice sistem.

Limbajul C++ apare la începutul anilor ’80 şi îl are ca autor pe Bjarne Stroustrup. El este o
variantă îmbunătăţită a limbajului C (un superset al limbajului C), mai riguroasă şi mai
puternică, completată cu construcţiile necesare aplicării principiilor programării orientate pe
obiecte (POO). Limbajul C++ păstrează toate elementele limbajului C, beneficiind de
eficienţa şi flexibilitatea acestuia. Incompatibilităţile între limbajele C şi C++ sunt minore, de
aceea, modulele C pot fi încorporate în proiecte C++ cu un efort minim.

19
CAPITOLUL 1 Noţiuni introductive

1.3.3. Convenţii folosite în prezentarea sintaxei

Orice formă sintactică generală a unei construcţii dintr-un limbaj de programare poate avea
următoarele componente: componente obligatorii şi componente opţionale; componente care
apar în instrucţiune o singură dată sau care se pot repeta; componente (numite simboluri
terminale, sau cuvinte cheie) a căror formă este invariabilă şi componente (numite simboluri
neterminale) care se vor înlocui la scrierea programului prin alte componente, conform unor
reguli.

La prezentarea sintaxei limbajelor C/C++, se vor folosi următoarele convenţii:


Simbolurile terminale sunt scrise cu caractere normale, îngroşate, şi vor apare în
program exact ca în forma generală;
Simbolurile neterminale apar în forma generală, ca <nume_simbol> şi vor fi înlocuite la
scrierea programului cu alte simboluri.
Simbolurile opţionale apar în forma generală între paranteze [ ].
Dacă două sau mai multe simboluri sunt separate prin caracterul |, se va alege doar unul
dintre ele.

1.4. TEORIA REZOLVĂRII PROBLEMELOR CU AJUTORUL


CALCULATORULUI
Creşterea complexităţii problemelor supuse rezolvării automate (cu ajutorul calculatorului) a
determinat ca activitatea de programare să devină, de fapt, un complex de activităţi organizate
pe etape. Pentru fiecare etapă au fost definite metodele formale de dezvoltare.

Pentru rezolvarea unei probleme trebuie parcurse următoarele etape:


 Analiza problemei (înţelegerea problemei şi specificarea cerinţelor acesteia). Se stabileşte
ce trebuie să facă aplicaţia, şi nu cum; se stabilesc datele de intrare (identificarea mediului
iniţial) şi obiectivele (identificarea mediului final, a rezultatelor);
 Proiectarea (conceperea metodei de rezolvare a problemei, printr-un algoritm);
 Implementarea (codificarea algoritmului ales într-un limbaj de programare);
 Testarea aplicaţiei obţinute (verificarea corectitudinii programului);
 Exploatarea şi întreţinerea (mentenanţa, constând în modificarea aplicaţiei la cererea
beneficiarului sau în urma unor deficienţe constatate pe parcursul utilizării aplicaţiei).

Etapele descrise anterior alcătuiesc ciclul de viaţă al unui produs software şi constituie
obiectul de studiu al disciplinei numite ingineria sistemelor de programe (software
engineering).
Teoreticienii ingineriei programării consideră că în rezolvarea unei probleme se poate alege
una din următoarele trei abordări:
 Rezolvarea orientată pe algoritm (pe acţiune), în care organizarea datelor este neesenţială;
 Rezolvarea orientată pe date, acţiunile fiind determinate doar de organizarea datelor;
 Rezolvarea orientată obiect, care combină tendinţele primelor două abordări.

Abordarea aleasă determină modelarea problemei de rezolvat.


Dintre metodele de proiectare orientate pe algoritm amintim: metoda programării
structurate şi metoda rafinării succesive. Ambele au ca punct de plecare metoda de
proiectare top-down, considerată ca fiind o metodă clasică de formalizare a procesului de
dezvoltare a unui produs software.
20
CAPITOLUL 1 Noţiuni introductive

La baza metodei top-down stă descompunerea funcţională a problemei P, adica găsirea unui
număr de subprobleme P 1 , P 2 , ... P n , cu următoarele proprietăţi:
 Fiecare subproblemă P i (1 ≤ i ≤ n) poate fi rezolvată independent. Dacă nu constituie o
problemă elementară, poate fi, la rândul ei, descompusă;
 Fiecare subproblemă P i este mai simplă decât problema P;
 Soluţia problemei P se obţine prin reuniunea soluţiilor subproblemelor P i ;
 Procesul de descompunere se opreşte în momentul în care toate subproblemele P i
obţinute sunt elementare, deci pot fi implementate;

Comunicarea între aceste subprobleme se realizează prin intermediul parametrilor.


Implementarea metodei top-down într-un limbaj de programare se face cu ajutorul modulelor
de program (funcţii sau proceduri în limbajul Pascal, funcţii în limbajele C, C++).

P Descompunerea funcţională a unui


P program P constă în identificarea
funcţiilor (task-urilor, sarcinilor)
P1 P3 principale ale programului (P 1 , P 2 ,
P2
P 3 ), fiecare dintre aceste funcţii
reprezentând un subprogram
(figura 1.9.). Problemele de pe
P4 P5 acelaşi nivel i sunt independente
unele faţă de altele.

Figura 1.9. Descompunerea funcţională

1.5. ETAPELE REZOLVĂRII UNEI PROBLEME

Să detaliem în continuare etapa de implementare. După analiza problemei şi stabilirea


algoritmului, acesta trebuie tradus (implementat) într-un limbaj de programare.
 Srierea (editarea) programului sursă - Programele sursă sunt fişiere text care conţin
instrucţiuni (cu sintactica şi semantica proprii limbajului utilizat). Fişierul sursă este creat
cu ajutorul unui editor de texte şi va fi salvat pe disc (programele sursă C primesc, de
obicei, extensia .c, iar cele C++, extensia .cpp). Pentru a putea fi executat, programul
sursă trebuie compilat şi linkeditat.
 Compilarea - Procesul de compilare este realizat cu ajutorul compilatorului, care
translatează codul sursă în cod obiect (cod maşină), pentru ca programul să poată fi înţeles
de calculator. În cazul limbajului C, în prima fază a compilării este invocat preprocesorul.
Acesta recunoaşte şi analizează mai întâi o serie de instrucţiuni speciale, numite directive
preprocesor. Verifică apoi codul sursă pentru a constata dacă acesta respectă sintaxa
limbajului. Dacă există erori, acestea sunt semnalate utilizatorului. Utilizatorul trebuie să
corecteze erorile (modificând programul sursă). Abia apoi codul sursă este translatat în
cod de asamblare, iar în final, în cod maşină, binar, propriu calculatorului. Acest cod binar
este numit cod obiect şi de obicei este memorat într-un alt fişier, numit fişier obiect.
Fişierul obiect va avea, de obicei, acelaşi nume cu fişierul sursă şi extensia .obj.
 Linkeditarea (editarea de legături) - După ce programul sursă a fost translatat în program
obiect, el este va fi supus operaţiei de linkeditare. Scopul fazei de linkeditare este acela de
a obţine o formă finală a programului, în vederea execuţiei acestuia. Linkeditorul “leagă”

21
CAPITOLUL 1 Noţiuni introductive

modulele obiect, rezolvă referinţele către funcţiile externe şi rutinele din biblioteci şi
produce cod executabil, memorat într-un fişier executabil (extensia .exe).
 Execuţia - Lansarea în execuţie constă în încărcarea programului executabil în memorie şi
startarea execuţiei sale. Corectitudinea sintactică a unui program nu o implică şi pe aceea
privitoare la aspectul îndeplinirii cu succes a sarcinii pentru care a fost conceput (aşa cum
un text scris în limba română, de exemplu, poate fi corect gramatical, dar să exprime
concepţii greşite). Sarcina ca programul să rezolve corect problema, revine, în întregime,
programatorului (calculatorul nu este decât o “unealtă” în mâna omului; nu calculatorul
greşeşte, ci programatorul!).

Cod (Preprocesor) Cod obiect Linkeditor Cod


sursă Compilator executabil

Figura 1.10. Etapele necesare obţinerii fişierului executabil


Observaţii:
1. Mediile de programare integrate (BORLANDC, TURBOC) înglobează editorul,
compilatorul, linkeditorul şi depanatorul (utilizat în situaţiile în care apar erori la
execuţie). Dacă nu foloseşte un mediu integrat, programatorul va apela în mod explicit (în
linie de comandă) un editor de texte, compilatorul, linkeditorul. Lansarea în execuţie se va
face tot din linie de comandă;
2. Extensiile specificate anterior pentru fişierele sursă, obiect şi executabile sunt cele
utilizate în mediile integrate BORLANDC şi TURBOC. De exemplu, în GNUC++,
extensiile sunt .c, .cc sau .cpp (fişierul sursă), .o (obiect) şi .e (executabil).

1.6. ÎNTREBĂRI ŞI PROBLEME


Întrebări
1. Enumeraţi unităţile funcţionale ale unui 7. Care sunt modalităţile de reprezentare a
sistem de calcul. algoritmilor?
2. Care este diferenţa dintre bit şi byte? 8. Ce sunt limbajele de programare de nivel
3. Ce este un algoritm? înalt?
4. Care sunt deosebirile între algoritm şi 9. Ce legături există între limbajele C şi C++?
program? 10. Care sunt diferenţele între programele de
5. Care sunt proprietăţile fundamentale ale aplicaţie şi sistemul de operare?
algoritmilor? 11. Care sunt diferenţele dintre memoriile
6. Ce sunt limbajele de programare? internă şi externă dintr-un calculator?

Probleme
1. Reprezentaţi algoritmul lui Euclid (pentru calculul celui mai mare divizor comun a 2
numere întregi) prin schemă logică şi prin pseudocod.
2. Proiectaţi un algoritm care să rezolve o ecuaţie de gradul I (de forma ax + b = 0), unde a,b
sunt numere reale. Discuţie după coeficienţi.
3. Proiectaţi un algoritm care să rezolve o ecuaţie de gradul II (de forma ax 2 + bx + c = 0),
unde a,b,c sunt numere reale. Discuţie după coeficienţi.
4. Proiectaţi un algoritm care să testeze dacă un număr întreg dat este număr prim.
5. Proiectaţi un algoritm care să afişeze toţi divizorii unui număr întreg citit de la tastatură.
6. Proiectaţi un algoritm care să afişeze toţi divizorii primi ai unui număr întreg.
7. Proiectaţi un algoritm care calculează factorialul unui număr natural dat (0!=1).

22
CAPITOLUL 2 Date, operatori şi expresii

2. DATE, OPERATORI ŞI EXPRESII

2.1. Programe în limbajul C/C++ 2.4. Date în limbajul C/C++


2.2. Preprocesorul 2.5. Operatori şi expresii
2.3. Elemente de bază ale limbajului 2.6. Conversii ale tipului operanzilor

2.1. PROGRAME ÎN LIMBAJUL C/C++


Un program scris în limbajul C (sau C++) este compus din unul sau mai multe fişiere sursă.
Un fişier sursă este un fişier text care conţine codul sursă (în limbajul C) al unui program.
Fiecare fişier sursă conţine una sau mai multe funcţii şi eventual, referinţe către unul sau mai
multe fişiere header (figura 2.1.).

Funcţia principală a unui program este numită main. Execuţia programului începe cu
execuţia acestei funcţii, care poate apela, la rândul ei, alte funcţii. Toate funcţiile folosite în
program trebuie descrise în fişierele sursă (cele scrise de către programator), în fişiere header
(funcţiile predefinite, existente în limbaj), sau în biblioteci de funcţii.

Un fişier header este un fişier aflat în sistem sau creat de către programator, care conţine
declaraţii şi definiţii de funcţii şi variabile.
Program Fişiere header

Fişier sursă

Funcţii main Biblioteci C++

Funcţii din bibliotecă

Figura 2.1. Structura unui program în limbajul C


Acţiunile din fiecare funcţie sunt codificate prin instrucţiuni (figura 2.2.a.). Există mai multe
tipuri de instrucţiuni, care vor fi discutate în capitolul următor. O instrucţiune este orice
expresie validă (de obicei, o asignare sau un apel de funcţie), urmată de simbolul ;. În figura
2.2.b. este dat un exemplu de instrucţiune simplă. Uneori, ca instrucţiune poate apare
instrucţiunea nulă (doar ;), sau instrucţiunea compusă (privită ca o succesiune de instrucţiuni
simple, încadrate între acoladele delimitatoare {}).
23
CAPITOLUL 2 Date, operatori şi expresii

O expresie este o structură corectă sintactic, formată din operanzi şi operatori (figura 2.2.c.).
FUNCŢII INSTRUCŢIUNI EXPRESII

Instrucţiunea1 Operanzi
Instrucţiunea2 Expresie;
Instrucţiunea3
.
.
.
.
Operatori
2.2.a. 2.2.b. 2.2.c
Figura 2.2. Funcţie, instrucţiune, expresie

Pentru a înţelege mai bine noţiunile prezentate, să considerăm un exemplu foarte simplu:
programul afişează pe ecran un mesaj (mesajul Primul meu program). Informaţia de prelucrat
(de intrare) este chiar mesajul (o constantă şir), iar prelucrarea ei constă în afişarea pe ecran.

Exemplul 2.1.:
#include <iostream.h> // linia 1
void main() // linia 2 - antetul funcţiei main
{ /* linia 3 - începutul corpului funcţiei, a unei intrucţiuni
compuse (linia 4)*/
cout<<”Primul meu program in limbajul C++\n”; // linia 5
} // linia6-sfârşitul corpului funcţiei

Prima linie este o directivă preprocesor (indicată de simbolul #) care determină includerea în
fişierul sursă a fişierului header cu numele iostream.h. Acest header permite realizarea
afişării pe monitor.
Programul conţine doar o funcţie, funcţia principală, main, al cărui antet (linia 2) indică:
- tipul valorii returnate de funcţie (void, ceea ce înseamnă că funcţia nu returnează nici o
valoare);
- numele funcţiei (main)
- lista declaraţiilor argumentelor primite de funcţie, încadrată de cele 2 paranteze rotunde.
Funcţiile comunică între ele prin argumente. Aceste argumente reprezintă datele de intrare ale
funcţiei. În cazul nostru, nu avem nici un argument în acea listă, deci puteam să scriem antetul
funcţiei şi astfel:
void main(void)
Ceea ce urmează după simbolul //, până la sfărşitul liniei, este un comentariu, care va fi
ignorat de către compilator. Comentariul poate conţine un text explicativ, informaţii
lămuritoare la anumite aspecte ale problemei sau observaţii. Dacă vrem să folosim un
comentariu care cuprinde mai multe linii, vom delimita începutul acestuia prin simbolurile
/*, iar sfârşitul - prin */ (vezi liniile 3, 4). Introducerea comentariilor în programele sursă
uşurează înţelegerea acestora. În general, se recomandă introducerea unor comentarii după
antetul unei funcţiei, pentru a preciza prelucrările efectuate în funcţie, anumite limite impuse
datelor de intrare, etc.

Începutul şi sfârşitul corpului funcţiei main sunt indicate de cele două acoalade { (linia3),
respectiv }(linia 6).

24
CAPITOLUL 2 Date, operatori şi expresii

Corpul funcţiei (linia 5) este format dintr-o singură instrucţiune, care implementează o
operaţie de scriere. Cuvântul cout este un cuvânt predefinit al limbajului C++ - console
output - care desemnează dispozitivul logic de ieşire; simbolul << este operatorul de transfer
al informaţiei. Folosite astfel, se deschide un canal de comunicaţie a datelor către dispozitivul
de ieşire, în cazul acesta, monitorul. După operator se specifică informaţiile care vor fi afişate
(în acest exemplu, un şir de caractere constant). Faptul că este un şir constant de caractere
este indicat de ghilimelele care îl încadrează. Pe ecran va fi afişat fiecare caracter din acest
şir, cu excepţia grupului \n. Deşi grupul este format din două caractere, acesta va fi
interpretat ca un singur caracter - numit caracter escape - care determină poziţionarea
cursorului la începutul următoarei linii a ecranului. O secvenţă escape (cum este \n)
furnizează un mecanism general şi extensibil pentru reprezentarea caracterelor invizibile sau
greu de obţinut. La sfârşitul instrucţiunii care implementează operaţia de scriere, apare ; .

2.2. PREPROCESORUL
Aşa cum s-a menţionat în capitolul 1.5., în faza de compilare a fişierului sursă este invocat
mai întâi preprocesorul. Acesta tratează directivele speciale - numite directive preprocesor -
pe care le găseşte în fişierul sursă. Directivele preprocesor sunt identificate prin simbolul #,
care trebuie să fie primul caracter, diferit de spaţiu, dintr-o linie. Directivele preprocesor sunt
utilizate la includerea fişierelor header, la definirea numelor constantelor simbolice, la
definirea macro-urilor, sau la realizarea altor funcţii (de exemplu, compilarea condiţionată),
aşa cum ilustrează exemplele următoare:

 Includerea fişierelor header în codul sursă:


Exemplul 2.2.:
#include <stdio.h>
Când procesorul întâlneşte această directivă preprocesor (identificabilă datorită
simbolului #), localizează fişierul header indicat (parantezele unghiulare < > indică faptul
că este vorba de un fişier header sistem).
Exemplul 2.3.:
#include "headerul_meu.h"
Numele fişierului header inclus între ghilimele, indică faptul că headerul_meu.h este
un fişier header creat de utilizator. Preprocesorul va căuta să localizeze acest fişier în
directorul curent de lucru al utilizatorului. În cazul în care fişierul header nu se află în
directorul curent, se va indica şi calea către acesta (vezi exemplul 3).
Exemplul 2.4.:
#include "c:\\bc\\head\\headerul_meu.h"
În acest exemplu, pentru interpretarea corectă a caracterului backslash \, a fost necesară
“dublarea” acestuia, din motive pe care le vom prezenta în paragraful 2.4.

 Asignarea de nume simbolice constantelor:


Exemplul 2.5.:
#define TRUE 1
#define FALSE 0

Tratarea acestor directive preprocesor are ca efect asignarea (atribuirea) valorii întregi 1
numelui (constantei simbolice) TRUE, şi a valorii 0 numelui simbolic FALSE. Ca urmare,
înaintea compilării propriu-zise, în programul sursă, apariţiile numelor TRUE şi FALSE
vor fi înlocuite cu valorile 1, respectiv 0.

25
CAPITOLUL 2 Date, operatori şi expresii

 Macrodefiniţii:
Directiva #define este folosită şi în macrodefiniţii. Macrodefiniţiile permit folosirea
unor nume simbolice pentru expresiile indicate în directivă.
Exemplul 2.6.:
#define NEGATIV(x) -(x)
Între numele macrodefiniţiei şi paranteza stângă ( NEGATIV(…) ) nu sunt permise spaţii
albe. La întalnirea - în programul sursă - a macrodefiniţiei NEGATIV, preprocesorul
subtituie argumentul acesteia cu expresia indicată (negativarea argumentului).
Macrodefiniţia din exemplu poate fi folosită în programul sursă astfel: NEGATIV(a+b).
Când preprocesorul întâlneşte numele expresiei, subtituie literalii din paranteză, a+b, cu
argumentul din macrodefiniţie, x, obţinându-se -(a+b).
Dacă macrodefiniţia ar fi fost de forma:
#define NEGATIV(x) -x
NEGATIV(a+b) ar fi fost tratată ca -a+b.

2.3. ELEMENTE DE BAZĂ ALE LIMBAJULUI

2.3.1. VOCABULARUL

În scrierea programelor în limbajul C/C++ pot fi folosite doar anumite simboluri care
alcătuiesc alfabetul limbajului. Acesta cuprinde:
 Literele mari sau mici de la A la Z (a-z);
 Caracterul de subliniere ( _ underscore), folosit, de obicei, ca element de legătură între
cuvintele compuse;
 Cifrele zecimale (0-9);
 Simboluri speciale:
 Caractere care reprezintă:
 operatori (Exemple: +, *, !=);
 delimitatori (Exemple: blank (spaţiu), tab \t, newline \n, cu rolul de a separa
cuvintele limbajului);
 Grupuri de caractere (perechi de caractere).

Grupurile de caractere, numire adesea separatori, pot fi:


 ( ) - Încadrează lista de argumente ale unei funcţii sau sunt folosite în expresii
pentru schimbarea ordinii de efectuare a operaţiilor (în ultimul caz, fiind operator);
 { } - Încadrează instrucţiunile compuse;
 // - Indică începutul unui comentariu care se poate întinde până la sfârşitul liniei;
 /* */ - Indică începutul şi sfârşitul unui comentariu pe mai multe linii;
 " " - Încadrează o constantă şir (un şir de caractere);
 ' ' - Încadrează o constantă caracter (caracter imprimabil sau secvenţă escape).

2.3.2. UNITĂŢILE LEXICALE

Unităţile lexicale (cuvintele) limbajului C/C++ reprezintă grupuri de caractere, cu o


semnificaţie de sine stătătoare, putând fi:
 Identificatori (simboluri neterminale);
 Cuvinte cheie ale limbajului (simboluri terminale);

26
CAPITOLUL 2 Date, operatori şi expresii

Identificatorii reprezintă numele unor date (constante sau variabile), sau ale unor funcţii.
Identificatorul este format dintr-un şir de litere, cifre sau caracterul de subliniere (underscore),
trebuie să înceapă cu o literă sau cu caracterul de subliniere şi să fie sugestiv.

Exemplul 2.7.: viteza, greutate_netă, Viteza, Viteza1, GreutateNetă


Identificatorii pot conţine litere mici sau mari, dar limbajul C++ este senzitiv la majuscule şi
minuscule (case-sensitive). Astfel, identificatorii viteza şi Viteza sunt diferiţi.
Nu pot fi folosiţi ca identificatori cuvintele cheie. Identificatorii pot fi standard (ca de
exemplu numele unor funcţii predefinite: scanf, clrscr, etc.), sau aleşi de utilizator.

Cuvintele cheie sunt cuvinte ale limbajului, împrumutate, de obicei, din limba engleză, cărora
programatorul nu le poate da o altă utilizare. Cuvintele cheie se scriu cu litere mici şi pot
reprezenta:
 Tipuri de date (Exemple: int, char, double);
 Clase de memorare (Exemple: extern, static, register);
 Instrucţiuni (Exemple: if, for, while);
 Operatori (Exemplu: sizeof).
Sensul cuvintelor cheie va fi explicat pe măsură ce vor fi prezentate construcţiile în care
acestea apar.

2.4. DATE ÎN LIMBAJELE C/C++


Aşa cum s-a văzut în capitolul 1, un program realizează o prelucrare de informaţie. Termenul
de prelucrare trebuie să fie considerat într-un sens foarte general (de exemplu, în programul
prezentat în paragraful 2.1., prelucrarea se referea la un text şi consta în afişarea lui). În
program datele apar fie sub forma unor constante (valori cunoscute anticipat, care nu se
modifică), fie sub formă de variabile. Constantele şi variabilele sunt obiectele informaţionale
de bază manipulate într-un program.

Fiecare categorie de date este caracterizată de atributele:


 Nume;
 Valoare;
 Tip;
 Clasă de memorare.
De primele trei tipuri de atribute ne vom ocupa în continuare, urmând ca de atributul clasă de
memorare să ne ocupăm în paragraful 6.7.

Numele unei date


Numele unei date este un identificator şi, ca urmare, trebuie să respecte regulile specifice
identificatorilor. Deasemenea, numărul de caractere componente ale unui identificator este
nelimitat, însă, implicit, numai primele 32 de caractere sunt luate în considerare. Aceasta
înseamnă că doi identificatori care au primele 32 de caractere identice, diferenţiindu-se prin
caracterul 33, vor fi consideraţi identici.

2.4.1. TIPURI DE DATE

Tipul unei date constă într-o mulţime de valori pentru care s-a adoptat un anumit mod de
reprezentare în memoria calculatorului şi o mulţime de operatori care pot fi aplicaţi acestor
valori. Tipul unei date determină lungimea zonei de memorie ocupată de acea dată. În general,

27
CAPITOLUL 2 Date, operatori şi expresii

lungimea zonei de memorare este dependentă de calculatorul pe care s-a implementat


compilatorul. Tabelul 2.1. prezintă lungimea zonei de memorie ocupată de fiecare tip de dată
pentru compilatoarele sub MS-DOS şi UNIX/LINUX.

Tipurile de bază sunt:


 char un singur octet (1 byte = 8 biţi), capabil să conţină codul unui caracter
(un număr) din setul local de caractere;
 int număr întreg, reflectă în mod tipic mărimea naturală din calculatorul utilizat;
 float număr real, în virgulă mobilă, simplă precizie;
 double număr real, în virgulă mobilă, dublă precizie.

În completare există un număr de calificatori, care se pot aplica tipurilor de bază char, int,
float sau double: short, long, signed şi unsigned. Prin alăturarea acestor
calificatori tipurilor de bază, se obţin tipurile derivate de date. Short şi long se referă la
mărimea diferită a întregilor, iar datele de tip unsigned int sunt întotdeauna pozitive. S-a
intenţionat ca short şi long să furnizeze diferite lungimi de întregi, int reflectând
mărimea cea mai “naturală” pentru un anumit calculator. Fiecare compilator este liber să
interpreteze short şi long în mod adecvat propriului hardware; în nici un caz, însă, short
nu este mai lung decât long. Toţi aceşti calificatori pot aplicaţi tipului int. Calificatorii
signed (cel implicit) şi unsigned se aplică şi tipului char. Calificatorul long se aplică
şi tipului double. Dacă într-o declaraţie se omite tipul de bază, implicit, acesta va fi int.

Să considerăm, de exmplu, tipul int, folosit pentru date întregi (pozitive sau negative).
Evident că mulţimea valorilor pentru acest tip va fi, de fapt, o submulţime finită de numere
întregi. Dacă pentru memorarea unei date de tip int se folosesc 2 octeţi de memorie, atunci
1
valoarea maximă pentru aceasta va fi × 2 16 - 1, deci 2 15 - 1 (32767), iar valoarea minimă va
2
1
fi - × 2 16 , deci -2 15 (-32768). Încercarea de a calcula o expresie de tip int a cărei valoare
2
se situează în afara acestui domeniu va conduce la o eroare de execuţie.
Mulţimea valorilor pentru o dată de tip unsigned int (întreg fără semn) va fi formată din
numerele întregi situate în intervalul [0, 2 16 - 1].

În header-ul <values.h> sunt definite constantele simbolice (cum ar fi: MAXINT,


MAXSHORT, MAXLONG, MINDOUBLE, MINFLOAT, etc.) care au ca valori limitele inferioară
şi superioară ale intervalului de valori pentru tipurile de date enumerate. (de exemplu,
MAXINT reprezintă valoarea întregului maxim care se poate memora).

Fără a detalia foarte mult modul de reprezentare a datelor reale (de tip float sau double),
vom sublinia faptul că, pentru acestea, este importantă şi precizia de reprezentare. Deoarece
calculatorul poate reprezenta doar o submulţime finită de valori reale, în anumite cazuri, pot
apare erori importante.
Numerele reale pot fi scrise sub forma: N = mantisa × baza exponent
unde: baza reprezintă baza sistemului de numeraţie; mantisa (coeficientul) este un
număr fracţionar normalizat (în faţa virgulei se află 0, iar prima cifră de după virgulă este
diferită de zero); exponentul este un număr întreg. Deoarece forma internă de reprezentare
este binară, baza=2. În memorie vor fi reprezentate doar mantisa şi exponentul. Numărul de
cifre de după virgulă determină precizia de exprimare a numărului. Cu alte cuvinte, pe un
calculator cu o precizie de 6 cifre semnificative, două valori reale care diferă la a 7-a cifră

28
CAPITOLUL 2 Date, operatori şi expresii

zecimală, vor avea aceeaşi reprezentare. Pentru datele de tip float, precizia de reprezentare
este 6; pentru cele de tip double, precizia este 14, iar pentru cele de tip long double, precizia
este 20.

Tabelul 2.1.
Tip Lungimea zonei Descriere
de memorare (în
biţi)
MS- UNIX
DOS LINUX
char 8 8 Valoarea unui singur caracter; poate fi întâlnit în
expresii cu extensie de semn
unsigned 8 8 Aceeaşi ca la char, fără extensie de semn
char
signed char 8 8 Aceeaşi ca la char, cu extensie de semn obligatorie
int 16 32 Valoare întreagă
long 32 64 Valoare întreagă cu precizie mare
(long int)
long long 32 64 Valoare întreagă cu precizie mare
int
short int 16 32 Valoare întreagă cu precizie mică
unsigned int 16 32 Valoare întreagă, fără semn
unsigned 32 64 Valoare întreagă, fără semn
long int
float 32 32 Valoare numerică cu zecimale, simplă precizie (6 )
double 64 64 Valoare numerică cu zecimale, dublă precizie (10 )
long double 80 128 Valoare numerică cu zecimale, dublă precizie

Lungimea zonei de memorie ocupate de o dată de un anumit tip (pe câţi octeţi este memorată
data) poate fi aflată cu ajutorul operatorului sizeof.
Exemplul 2.8.:
cout<<"Un int este memorat pe "<<sizeof(int)<<"octeti.\n";
Instrucţiunea are ca efect afişarea pe monitor a mesajului: Un int este memorat pe 2 octeţi.

2.4.2. CONSTANTE

O constantă este un literal (o formă externă de reprezentare a unei valori în fişierul sursă)
numeric, caracter sau şir de caractere. Numele şi valoarea unei constante sunt identice.
Valoarea unei constante nu poate fi schimbată în timpul execuţiei programului în care a fost
utilizată. Tipul şi valoarea ei sunt determinate în mod automat, de către compilator, pe baza
caracterelor care compun literalul.

2.4.2.1. Constante numerice întregi

Constantele întregi sunt literali numerici (compuşi din cifre), fără punct zecimal.

 Constante întregi în baza 10, 8 sau 16


 Constante întregi în baza 10
Exemplul 2.9.:
45
-78 // constante întregi decimale (în baza 10), tip int

29
CAPITOLUL 2 Date, operatori şi expresii

 Constante întregi octale - Dacă în faţa numărului apare cifra zero (0), acea constantă
este de tip int, în baza opt (constantă octală).
Exemplul 2.10.:
056
077 // constante întregi octale, tip int
 Constante întregi hexagesimale - Dacă în faţa numărului apar caracterele zero (0) şi x
(sau X), acea constantă este de tipul int, în baza 16 (constantă hexagesimală).
Reamintim cifrele folosite în baza de numeraţie 16, sunt: 0-9, A (sau a) cu valoare
10, B (sau b) cu valoare 11, C (sau c) cu valoare 12, D (sau d) cu valoare 13, E (sau e)
cu valoare 14, F (sau f) cu valoare 15.
Exemplul 2.11.:
0x45
0x3A
0Xbc // constante întregi hexagesimale, tip int
 Constante întregi, de tipuri derivate
 Dacă secvenţa de cifre este urmată de L sau l, tipul constantei este long int.
Exemplul 2.12.:
145677L
897655l // tip decimal long int
 Dacă secvenţa de cifre este urmată de U sau u, tipul constantei este unsigned int.
Exemplul 2.13.:
65555u
 Dacă secvenţa de cifre este urmată de U (u) şi L (l), tipul este unsigned long int.
Exemplul 2.14: 7899UL //tip decimal unsigned long int

2.4.2.2. Constante numerice reale

 Dacă o constantă numerică conţine punctul zecimal, ea este de tipul double.


Exemplul 2.15.:
3.1459 //tip double
 Dacă numărul este urmat de F sau f, constante este de tip float.
 Dacă numărul este urmat de L sau l, este de tip long double.
Exemplul 2.16.:
0.45f //tip float
9.788L //tip long double
 Constante reale în format ştiinţific
Numărul poate fi urmat de caracterul e sau E şi de un număr întreg, cu sau fără semn. În
acest caz, constanta este în notaţie ştiinţifică. În această formă externă de reprezentare,
numărul din faţa literei E reprezintă mantisa, iar numărul întreg care urmează caracterului
E reprezintă exponentul. În forma externă de reprezentare, baza de numeraţie este 10, deci
exp onent
valoarea constantei va fi dată de mantisa × 10 .
Exemplul 2.17.: 1.5e-2 //tip double, în notaţie ştiinţifică, valoare 1.5 × 10 − 2

Exerciţiul 2.1.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
#include <values.h>
#define PI 3.14359
void main()
{ cout<<"Tipul int memorat pe: "<<sizeof(int)<<" octeti\n";
cout<<"Tipul int memorat pe: "<<sizeof(23)<<" octeti\n";
//23-const. decimală int
30
CAPITOLUL 2 Date, operatori şi expresii

cout<<"Int maxim="<<MAXINT<<’\n’;
//const. simbolice MAXINT, MAXLONG, etc. - definite in <values.h>
cout<<"Const. octala 077 are val decimala:"<<077<<’\n';
cout<<"Const. hexagesimala d3 are val decimala:"<<0xd3<<’\n’;
cout<<"Tipul unsigned int memorat pe:";
cout<<sizeof(unsigned int)<<" octeti\n";
cout<<"Tipul unsigned int memorat pe: ";
cout<<sizeof(23U)<<" octeti\n";
cout<<"Tipul unsigned int memorat pe: ";
cout<<sizeof(23u)<<" octeti\n";
cout<<"Tipul long int memorat pe: ";
cout<<sizeof(long int)<<" octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23L)<<" octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23l)<<" octeti\n";
//23L sau 23l-const. decimala long int
cout<<"Long int maxim="<<MAXLONG<<’\n’;
cout<<"Tipul unsigned long memorat pe:";
cout<<sizeof(unsigned long int)<<" octeti\n";
cout<<"Tip unsigned long mem. pe: "<<sizeof(23UL)<<" octeti\n";
cout<<"Tip unsigned long mem. pe: "<<sizeof(23ul)<<" octeti\n";
//23UL sau 23ul-const. decimala unsigned long int
cout<<"Tipul long long int memorat pe: ";
cout<<sizeof(long long int)<<" octeti\n"; long long int d;
cout<<"Tip long long int mem. pe: "<<sizeof(d)<<" octeti\n";
cout<<"Tip short int mem.pe: "<<sizeof(short int)<<" octeti\n";
cout<<"Short int maxim="<<MAXSHORT<<’\n’;
cout<<"Tipul float memorat pe: "<<sizeof(float)<<" octeti\n";
cout<<"Tipul float memorat pe: "<<sizeof(23.7f)<<" octeti\n";
//23.7f-const. decimala float
cout<<"Float maxim="<<MAXFLOAT<<’\n’;
cout<<"Float minim="<<MINFLOAT<<’\n’;
cout<<"Tipul double memorat pe: "<<sizeof(double)<<" octeti\n";
cout<<"Tipul double memorat pe: "<<sizeof(23.7)<<" octeti\n";
//23.7-const. decimala double
cout<<"Const. decim. doubla in not st.:"<<23.7e-5<<’\n’;
cout<<”Const. PI este:”<<PI<<’\n’;
cout<<”Constanta PI este memorata pe:”<<sizeof(PI)<<”octeti\n”:
cout<<"Double maxim="<<MAXDOUBLE<<’\n’;
cout<<"Double minim="<<MINDOUBLE<<’\n’;
cout<<"Tip long double mem.pe:"<<sizeof(long double)<<" oct\n";
cout<<"Tip long double mem. pe: "<<sizeof(23.7L)<<" octeti\n";
//23.7L-const. decimala long double
cout<<"Cifra A din HEXA are val.:"<<0xA<<"\n";
cout<<"Cifra B din HEXA are val.:"<<0XB<<"\n";
cout<<"Cifra C din HEXA are val.:"<<0xc<<"\n";
cout<<" Cifra D din HEXA are val.:"<<0xD<<"\n";
cout<<" Cifra E din HEXA are val.:"<<0XE<<"\n";
cout<<" Cifra F din HEXA are val.:"<<0xf<<"\n";
cout<<"Val. const. hexa 0x7ac1e este: "<<0x7ac1e<<'\n';
cout<<"Val. const. octale 171 este: "<<0171<<'\n';
cout<<"O const. octala se mem. pe "<<sizeof(011)<<" octeti\n";
cout<<"O const.oct.long mem.pe";cout<<sizeof(011L)<<" oct\n";}

31
CAPITOLUL 2 Date, operatori şi expresii

2.4.2.3. Constante caracter

Caracterele sunt simboluri care reprezintă litere, cifre, semne de punctuaţie, etc. Constantele
caracter sunt încadrate între apostroafe.
Exemplul 2.18.:
'a' //tip char

Caracterele sunt reprezentate intern printr-un număr întreg, fără semn, memorat pe 1 octet.
Valoarea numărului este aşa-numitul cod ASCII (American Standard Code for Information
Interchange) al caracterului pe care îl reprezintă. Codul ASCII are următoarele proprietăţi:
 Fiecărui caracter îi corespunde o valoare întreagă distinctă (ordinală);
 Valorile ordinale ale literelor mari sunt ordonate şi consecutive ('A' are codul ASCII
65, 'B' - codul 66, 'C' - codul 67, etc.);
 Valorile ordinale ale literelor mici sunt ordonate şi consecutive ('a' are codul ASCII
97, 'b' - codul 98, 'c' - codul 99, etc.);
 Valorile ordinale ale cifrelor sunt ordonate şi consecutive ('0' are codul ASCII 48, '1' -
codul 49, '2' - codul 50, etc.).

 Constante caracter corespunzătoare caracterelor imprimabile


O constantă caracter corespunzătoare unui caracter imprimabil se reprezintă prin
caracterul respectiv inclus între apostroafe.
Exemplul 2.19.:
Constantă caracter Valoare
‘A’ 65
‘a’ 97
‘0’ 48
‘*’ 42
Excepţii de la regula de mai sus le constituie caracterele imprimabile apostrof (') şi
backslash (\). Caracterul backslash se reprezintă prin '\\'. Caracterul apostrof se
reprezintă prin '\''.

 Constante caracter corespunzătoare caracterelor neimprimabile


Pentru caracterele neimprimabile, se folosesc secvenţe escape. O secvenţă escape
furnizează un mecanism general şi extensibil pentru reprezentarea caracterelor invizibile
sau greu de obţinut (tabelul 2.2. sunt prezintă câteva caractere escape utilizate frecvent).

Tabelul 2.2.
Constantă Valoare Denumire Utilizare
caracter Cod ASCII caracter
‘\n’ 10 LF rând nou (Line Feed)
‘\t’ 9 HT tabulator orizontal
‘\r’ 13 CR poziţionează cursorul în coloana 1 din rândul curent
‘\f’ 12 FF salt de pagină la imprimantă (Form Feed)
‘\a’ 7 BEL activare sunet

O constantă caracter pentru o secvenţă escape poate apare însă, şi sub o formă în care se
indică codul ASCII, în octal, al caracterului dorit:
’\ddd’ unde d este o cifră octală.

32
CAPITOLUL 2 Date, operatori şi expresii

Exemplul 2.20.:
’\11’ (pentru ’\t’)
reprezintă constanta caracter backspace, cu codul 9 în baza 10, deci codul 11 în baza 8.
’\15’ (pentru ’\r’)
reprezintă constanta caracter CR, cu codul 13 în baza 10, deci codul 11 în baza 8.

Exerciţiul 2.2.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main(void)
{
cout<<"Un caracter este memorat pe "<<sizeof(char)<<" octet\n";
cout<<"Caracterul escape \\n este memorat pe ";
cout<<sizeof('\n')<<" octet\n";
cout<<"Car. escape '\\n\' e mem. pe "<<sizeof('\n')<<" oct.\n";
cout<<"Caracterul '9' e memorat pe "<<sizeof('9')<<" octet\n";
cout<<'B';cout<<' ';cout<<'c';cout<<'\t';
cout<<'\t';cout<<'9';cout<<'\b';cout<<'\a';
cout<<'L';cout<<'\v';cout<<'L';
cout<<'\'';cout<<'\t';cout<<'\"';cout<<'\\';cout<<'\n';
cout<<'\a';cout<<'\7';
}

2.4.2.4. Constante şir de caractere

Constanta şir este o succesiune de zero sau mai multe caractere, încadrate de ghilimele. În
componenţa unui şir de caractere, poate intra orice caracter, deci şi caracterele escape.
Lungimea unui şir este practic nelimitată. Dacă se doreşte continuarea unui şir pe rândul
următor, se foloseşte caracterul backslash.

Caracterele componente ale unui şir sunt memorate într-o zonă continuă de memorie (la
adrese succesive). Pentru fiecare caracter se memorează codul ASCII al acestuia. După
ultimul caracter al şirului, compilatorul plasează automat caracterul NULL ('\0'), caracter
care reprezintă marcatorul sfârşitului de şir. Numărul de octeţi pe care este memorat un şir va
fi, deci, mai mare cu 1 decât numărul caracterelor componente ale şirului.

Exemplul 2.2.:
”Acesta este un şir de caractere” //constantă şir memorată pe 32 octeţi
”Şir de caractere continuat\”
pe rândul următor!” //constantă şir memorată pe 45 octeţi
”Şir \t cu secvenţe escape\n” //constantă şir memorată pe 26 octeţi
’\n’ //constantă caracter memorată pe un octet
”\n” //const şir memorată pe 2 oct. (codul caracterului escape şi terminatorul de şir)
”a\a4” /*Şir memorat pe 4 octeţi:
Pe primul octet: codul ASCII al caracterului a
Pe al doilea octet: codul ASCII al caracterului escape \a
Pe al treilea octet: codul ASCII al caracterului 4
Pe al patrulea octet: terminatorul de şir NULL, cod ASCII 0*/
”\\ASCII\\” /*Şir memorat pe 8 octeţi:
Pe primul octet: codul ASCII al caracterului backslah
Pe al doilea octet: codul ASCII al caracterului A
Pe al treilea octet: codul ASCII al caracterului S
Pe al patrulea octet: codul ASCII al caracterului C

33
CAPITOLUL 2 Date, operatori şi expresii

Pe al 6-lea octet: codul ASCII al caracterului I


Pe al 7-lea octet: codul ASCII al caracterului I
Pe al 8-lea octet: codul ASCII al caracterului backslah
Pe al 9-ea octet: terminatorul de şir NULL, de cod ASCII 0 */
”1\175a” /*Şir memorat pe 4 octeţi:
Primul octet: Codul ASCII al caracterul 1
Al 2-lea octet: codul ASCII 125 (175 in octal) al car. }
Al 3-lea octet: codul ASCII al caracterului a
Al 4-lea octet: codul ASCII 0 pentru terminatorul şirului */

Exerciţiul 2.3.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{cout<<"Şirul \"Ab9d\" e mem. pe:"<<sizeof("Ab9d")<<" oct\n";
cout<<"Şir \"Abcd\\t\" mem. pe:"<<sizeof("Abcd\t")<<" oct.\n";
cout<<"Şirul \"\n\" este mem. pe "<<sizeof("\n")<<" octeţi\n";
cout<<"Şirul \"\\n\" este mem. pe "<<sizeof("\n")<<" octeţi\n";
cout<<"Şir\"ABCDE\" se mem. pe "<<sizeof("ABCDE")<<" oct.\n";}

2.4.3. VARIABILE

Spre deosebire de constante, variabilele sunt date (obiecte informaţionale) ale căror valori se
pot modifica în timpul execuţiei programului. Şi variabilele sunt caracterizate de atributele
nume, tip, valoare şi clasă de memorare. Variabilele sunt nume simbolice utilizate pentru
memorarea valorilor introduse pentru datele de intrare sau a rezultatelor. Dacă la o constantă
ne puteam referi folosind caracterele componente, la o variabilă ne vom referi prin numele ei.
Numele unei variabile ne permite accesul la zona de memorie rezervată variabilei, deci
accesul la valoarea sa (afişarea sau modificarea acesteia). Numele unei variabile este un
identificator ales de programator. Ca urmare, trebuie respectate regulile enumerate în
secţiunea identificatori.

Dacă o dată nu are legături cu alte date (de exemplu, relaţia de ordine), vom spune că este o
dată izolată. O dată izolată este o variabilă simplă. Dacă datele se grupează într-un anumit
mod (în tablouri - vectori, matrici - sau structuri), variabilele sunt compuse (structurate).

În cazul constantelor, în funcţie de componenţa literalului, compilatorul stabilea, automat,


tipul constantei. În cazul variabilelor este necesară specificarea tipului fiecăreia, la declararea
acesteia. Toate variabilele care vor fi folosite în program, trebuie declarate înainte de utilizare.

2.4.3.1. Declararea variabilelor

Modul general de declarare a variabilelor este:


<tip_variabile> <listă_nume_variabile>;

Se specifică tipul variabilei(lor) şi o listă formată din unul sau mai mulţi identificatori ai
variabilelor de tipul respectiv.

Într-un program scris în limbajul C++, declaraţiile de variabile pot apare în orice loc în
programul sursă. La declararea variabilelor, se rezervă în memorie un număr de octeţi
corespunzător tipului variabilei, urmând ca ulterior, în acea zonă de memorie, să fie depusă
(memorată, înregistrată) o anumită valoare.

34
CAPITOLUL 2 Date, operatori şi expresii

Exemplul 2.22.:
int i, j;
/*declararea var. simple i, j, tip int. Se rezervă pentru i şi j câte 16 biţi (2octeţi)*/
char c; /* declararea variabilei simple c, de tip char. Se rezervă un octet. */
float lungime; /* declararea variabilei simple lungime; se rezervă 4 octeţi */

2.4.3.2. Iniţializarea variabilelor în declaraţii

În momentul declarării unei variabile, acesteia i se asigna, atribui o anumită valoare. În acest
caz, în memorie se rezervă numărul de locaţii corespunzător tipului variabilei respective, iar
valoarea va fi depusă (memorată) în acele locaţii.
Forma unei declaraţii de variabile cu atribuire este:
<tip_var> <nume_var1>=<expr1>[,<nume_var2>=<expr2>, …];
Se evaluează expresia1, iar rezultatul acesteia este asignat variabilei specificate prin
nume_var1. Analog se procedează, când este cazul, pentru toate variabilele care apar în
declaraţia cu iniţializare.

Exemplul 2.23.:
char backslash=’\\’; //declararea şi iniţializarea variabilei simple backslash
int a=7*9+2;
/* declararea variabilei simple a, de tip int şi iniţializarea ei cu valoarea 65*/
float radiani, pi=3.14;
/*declararea variabilei radiani; declararea şi iniţializarea var. pi cu valoarea 3.14*/
short int z=3; //declararea şi iniţializarea variabilei simple z
char d=’\011’;
char LinieNoua=’\n’;
double x=9.8, y=0;
//declararea variabilelor simple x şi y şi iniţializarea lor cu valorile 9.8, respectiv 0

Compilatorul C++ furnizează mecanisme care permit programatorului să influenţeze codul


generat la compilare, prin aşa-numiţii calificatori. Aceştia sunt:
 const;
 volatile.

Calificatorul const asociat unei variabile, nu va permite modificarea ulterioară a valorii


acesteia, prin program (printr-o atribuire). Calificatorul volatile (cel implicit) are efect
invers calificatorului const. Dacă după calificator nu este specificat tipul datei, acesta este
considerat tipul implicit, adică int.

Exemplul 2.24.:
const float b=8.8;
volatile char terminator;terminator=’@’;terminator=’*’;//permis
b=4/5; //nepermisă modificarea valorii variabilei b
const w; volatile g; //w, g de tip int (implicit)

2.4.3.3. Operaţii de intrare/ieşire

Limbajele C/C++ nu posedă instrucţiuni de intrare/ieşire, deci de citire/scriere (ca limbajul


PASCAL, de exemplu). În limbajul C aceste operaţii se realizează cu ajutorul unor funcţii (de
exemplu, printf şi scanf), iar în limbajul C++ prin supraîncărcarea operatorilor (definirea
unor noi proprietăţi ale unor operatori existenţi, fără ca proprietăţile anterioare să dispară),

35
CAPITOLUL 2 Date, operatori şi expresii

mai precis a operatorilor >> şi << . Vom folosi în continuare abordarea limbajului C++, fiind,
în momentul de faţă, mai simplă. În limbajul C++ sunt predefinite următoarele dispozitive
logice de intrare/ieşire:
cin - console input - dispozitivul de intrare (tastatura);
cout - console output - dispozitivul de ieşire (monitorul).
Aşa cum se va vedea în capitolul 9, cin şi cout sunt, de fapt, obiecte (predefinite).
Transferul informaţiei se realizează cu operatorul >> pentru intrare şi operatorul << pentru
ieşire. Utilizarea dispozitivelor de intrare/ieşire cu operatorii corespunzători determină
deschiderea unui canal de comunicaţie a datelor către dispozitivul respectiv. După operator se
specifică informaţiile care vor fi citite sau afişate.

Exemplul 2.25.:
cout << var; /* afişează valoarea variabilei var pe monitor*/
cin >> var; /* citeşte valoarea variabilei var de la tasatatură */

Sunt posibile operaţii multiple, de tipul:

Exemplul 2.26.:
cout << var1 << var2 << var3;
cin >> var1 >> var2 >> var3;
În acest caz, se efectuează succesiv, de la stânga la dreapta, scrierea, respectiv citirea valorilor
variabilelor var1, var2 şi var3.

Operatorul >> se numeşte operator extractor (extrage valori din fluxul datelor de intrare,
conform tipului acestora), iar operatorul << se numeşte operator insertor (inserează valori în
fluxul datelor de ieşire, conform tipului acestora). Tipurile de date citite de la tastatură pot fi
toate tipurile numerice, caracter sau şir de caractere. Tipurile de date transferate către ieşire
pot fi: toate tipurile numerice, caracter sau şir de caractere. Operanzii operatorului extractor
(>>) pot fi doar nume de variabile. Operanzii operatorului insertor (<<) pot fi nume de
variabile (se afişează valoarea variabilei), constante sau expresii. Utilizarea dispozitivelor şi
operatorilor de intrare/ieşire în C++ impune includerea fişierului header iostream.h.

Exemplul 2.27.:
char c;
cout<<"Astept un caracter:";//afişarea const. şir de caract., deci a mesajului
cin>>c; //citirea valorii variabilei c, de tip caracter
int a, b, e; double d;
cin>>a>>b>>e>>d; //citirea valorilor variabilelor a, b, e, d de tip int, int, int, double
cout<<"a="<<a<<"Valoarea expresiei a+b este:"<<a+b<<'\n';

2.5. OPERATORI ŞI EXPRESII


Datele (constante sau variabile) legate prin operatori (simboluri pentru operaţii), formează
expresii (figura 2.4). Operatorii care pot fi aplicaţi datelor (operanzilor) depind de tipul
operanzilor, datorită faptului că tipul unei date constă într-o mulţime de valori pentru care s-a
adoptat un anumit mod de reprezentare în memoria calculatorului şi o mulţime de operatori
care pot fi aplicaţi acestor valori. În funcţie de numărul operanzilor necesari, operatorii pot fi:
 unari (necesită un singur operand);
 binari (necesită doi operanzi);
 ternari (trei operanzi).

36
CAPITOLUL 2 Date, operatori şi expresii

O expresie este o combinaţie corectă din punct de vedere sintactic, formată din operanzi şi
operatori. Expresiile, ca şi operanzii, au tip şi valoare.

2.5.1. OPERATORI

 Operatorul unar adresă & (numit şi operator de referenţiere), aplicat unei variabile,
furnizează adresa la care este memorată aceasta. Poate fi aplicat datelor de orice tip.

Exemplul 2.28.:
int a; cout<<"Adr. la care este mem. variabila a este:"<<&a;

 Operatorul de atribuire (de asignare) este un operator binar care se aplică tuturor tipurilor
de variabile. Este folosit sub formele următoare:
<nume_variabilă> = <expresie>;
sau: <expresie1> = <expresie2>;
Se evaluează expresia din membrul drept, iar valoarea acesteia este atribuită variabilei din
membrul stâng. Dacă tipurile membrilor stâng şi drept diferă, se pot realiza anumite conversii,
prezentate în paragraful 2.7.

Exemplul 2.19.:
float x; int a,b; x=9.18;
a=b=10;
int s; s=a+20*5; //rezultat: s=110
s=x+2; //rezultat s=11, deoarece s este int.

Aşa cum se observă în linia a 2-a din exemplul precedent, operatorul de atribuire poate fi
utilizat de mai multe ori în aceeaşi expresie. Asociativitatea operatorului are loc de la dreapta
la stânga. Astfel, mai întâi b=10, apoi a=b.

Exerciţiul 2.4.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{float x,y=4.25; char car=’A’; int a,b,c;
cout<<”Val. lui y este:”<<y<<’\n’; //Afişare: Val. lui y este:4.25
x=y; cout<<”Val. lui x este:”<<x<<’\n’;//Afişare: Val. lui x este:4.25
a=x;
cout<<”Val.lui a este:”<<a<<’\n’; //Afişare:Val.lui a este:4 (a de tip int!!!)
c=b=a; cout<<”b=”<<b<<”\tc=”<<c<<’\n’; //Afişare: b=4 c=4
cout<<”Introduceţi val. lui c:”; cin>>c; // citire val. pentru c
cout<<”Val. lui c este:”<<c<<’\n’; } //Val. lui c este: val. citită anterior

Operatorul poate fi aplicat tipurilor de date întregi, reale, caracter, şi chiar şiruri de caractere,
aşa cum vom vedea în capitolele următoare (exemplu: char şir[10]=”a5dfgthklj”).

 Operatori aritmetici unari:


Operator Semnificaţie Exemple
- Minus unar -a
++ Operator de incrementare a++ sau ++a
(adună 1 la valoarea operandului)
-- Operator de decrementare a-- sau --a
(scade 1 din valoarea operandului)

37
CAPITOLUL 2 Date, operatori şi expresii

 Operatorul - unar schimbă semnul operandului (numeric sau caracter).

Exemplul 2.30.:
int a,b; cout<<”a=”<<-a<<’\n’; b=-a;
cout<<”b=”<<b<<’\n’;

 Operatorii de incrementare (++) şi de decrementare (--) pot fi aplicaţi datelor


numerice sau caracter. Ambii operatori pot fi folosiţi în formă prefixată, înaintea
operandului, (++a, respectiv --a) sau postfixată, după operand (a++, respectiv
a--). Utilizarea acestor operatori în expresii, în formă prefixată sau postfixată,
determină evaluarea acestora în moduri diferite, astfel:

y = ++x este echivalent cu: x = x+1; y = x;


y = x++ este echivalent cu: y = x; x = x+1;
y = --x este echivalent cu: x = x-1; y = x;
y = x-- este echivalent cu: y = x; x = x-1;

Exerciţiul 2.5.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{ int a=9; cout<<”a++=”<<a++<<’\n’; //Afişare: a++=9
cout<<”a=”<<a<<’\n’; //Afişare: a=10
a=9; //Revenire în situaţia anterioară
cout<<”++a=”<<++a<<’\n’; //Afişare: ++a=10
cout<<”a=”<<a<<’\n’; //Afişare: a=10
a=9; cout<<”a--=”<<a--<<’\n’; //Afişare: a--=9
cout<<”a=”<<a<<’\n’; //Afişare: a=8
a=9; //Revenire în situaţia anterioară
cout<<”--a=”<<--a<<’\n’; //Afişare: --a=8
cout<<”a=”<<a<<’\n’; //Afişare: a=8
int z,x=3; z=x++-2;
cout<<”z=”<<z<<’\n’; //Afişare: z=1
cout<<"x=”<<x<<’\n’; //Afişare: x=4
x=3; z=++x-2; cout<<”z=”<<z<<’\n’; //Afişare: z=2
cout<<"x=”<<x<<’\n’; //Afişare: x=4
}

 Operatori aritmetici binari simpli:


Operator Semnificaţie Exemple
+ Adunarea celor doi operanzi a+b
- Scăderea celor doi operanzi a-b
* Înmulţirea celor doi operanzi a*b
/ Împărţirea celor doi operanzi a/b
% Operatorul modulo (operatorul rest) a%b
(furnizează restul împărţirii operatorului stâng la operatorul drept).

Operatorul modulo se aplică numai operanzilor întregi (de tip int sau char). Ceilalţi operatori
aritmetici binari pot fi aplicaţi datelor întregi sau reale.
Dacă într-o expresie apar 2 operanzi întregi şi un operator binar aritmetic, rezultatul expresiei
va fi tot un număr întreg. De exemplu, la evaluarea expresiei 9/2, ambii operanzi fiind întregi,
rezultatul furnizat este numărul întreg 4.
38
CAPITOLUL 2 Date, operatori şi expresii

Operatorii prezentaţi respectă o serie de reguli de precedenţă (prioritate) şi asociativitate, care


determină precis modul în care va fi evaluată expresia în care aceştia apar. În tabelul 2.3 sunt
prezentaţi operatorii anteriori, în ordinea descrescătoare a priorităţii. Precedenţa operatorilor
poate fi schimbată cu ajutorul parantezelor.

Tabelul 2.3.
Clasă de operatori Operatori Asociativitate
Unari & - (unar) ++ -- de la stânga la dreapta
Multiplicativi * / % de la stânga la dreapta
Aditivi + - de la stânga la dreapta
Atribuire = de la dreapta la stânga

Exerciţiul 2.6.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei


acestuia.
#include <iostream.h>
void main()
{ int rezult, a=20,b=2,c=25,d=4; rezult=a-b;
cout<<”a-b=”<<rezult<<’\n’; // Afişare: a-b=18
rezult=a+b; cout<<”a+b=”<<rezult<<’\n’;// Afişare: a+b=22
rezult=a*b;cout<<”c*b=”<<rezult<<’\n’; // Afişare: c*b=50
rezult=a/d; cout<<”a/d=”<<rezult<<’\n’;// Afişare: a/d=5
rezult=c%b; cout<<”c%b=”<<rezult<<’\n’;// Afişare: c%b=1
rezult=c/b*d; cout<<”c/b*d=”<<rezult<<’\n’; // Afişare: c/b*d=48
rezult= -b+a; cout<<”-b+a=”<<rezult<<’\n’; // Afişare: -b+a=18
rezult= -(b+a); cout<<”-(b+a)=”<<rezult<<’\n’;// Afişare: -(b+a)=-22
rezult=b+c*d;cout<<”b+c*d=”<<rezult<<’\n’; // Afişare: b+c*d=102
rezult=(b+c)*d;cout<<”(b+c)*d=”<<rezult<<’\n’; //(b+c)*d=108
a = b = c = 20; cout<<"c="<<c<<"b="<<b<<"a="<<a<<'\n';
// Atribuire multiplă c=20 b=c a=b c=20 b=20 a=20
a = b = c = 12*13/4; cout<<"c="<<c<<"b="<<b<<"a="<<a<<'\n'; }
// Atribuire multiplă c=36 b=c a=b

 Operatori aritmetici binari compuşi


Operator Semnificaţie Exemple
+= a=a+b a+=b
-= a=a-b a-=b
*= a=a*b a*=b
/= a=a/b a/=b
%= a=a%b a%=b

Aceşti operatori se obţin prin combinarea operatorilor aritmetici binari cu operatorul de


atribuire şi sunt folosiţi sub forma următoare:
<expresie1> <operator> = <expresie2>;
Rezultatul obţinut este acelaşi cu rezultatul obţinut prin:
<expresie1> = <expresie1> <operator> <expresie2>;
Toţi aceşti operatorii modifică valoarea operandului stâng prin adunarea, scăderea, înmulţirea
sau împărţirea acestuia prin valoarea operandului drept.
Construcţia x+=1 generează acelaşi rezultat ca expresia x=x+1.
Observaţiile referitoare la operatorii aritmetici binari sunt valabile şi pentru operatorii
aritmetici binari compuşi. Operatorii aritmetici binari compuşi au aceeaşi prioritate şi
asociativitate ca şi operatorul de atribuire.
39
CAPITOLUL 2 Date, operatori şi expresii

Exerciţiul 2.7.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{ int a,b; float c=9.3; a=3; b=8;
cout<<”a=”<<a<<’\n’; //Afişare a=3
a+=b; cout<<”a=”<<a<<’\n’; //Afişare a=11
a=3; b=8;a-=b; cout<<”a=”<<a<<’\n’; //Afişare a=-5
a=3; b=8;a*=b; cout<<”a=”<<a<<’\n’; //Afişare a=24
a=3; b=8;a/=b; cout<<”a=”<<a<<’\n’; //Afişare a=0
a=3; b=8;a%=b; cout<<”a=”<<a<<’\n’; } //Afisare a=3

 Operatori relaţionali binari


Operator Semnificaţie Exemple
== Egal cu a==b
!= Diferit de a!=b
< Mai mic decât a<b
<= Mai mic sau egal cu a<=b
> Mai mare decât a>b
>= Mai mare sau egal cu a>=b

Primii doi operatori mai sunt numiţi operatori de egalitate. Operatorii relaţionali compară
valorile celor doi operanzi, fără a le modifica. Rezultatul unei expresii în care apare un
operator relaţional binar este întreg şi are valoarea zero (0) dacă relaţia este falsă, sau valoarea
unu (1) (sau diferită de 0 în cazul compilatoarelor sub UNIX), dacă relaţia este adevărată.
Aceşti operatorii pot fi aplicaţi datelor de tip întreg, real sau caracter.

Observaţie: Deosebirea dintre operatorii == (relaţional, de egalitate) şi = (de atribuire) constă


în faptul că primul nu modifică valoarea nici unuia dintre operanzii săi, pe când cel de-al
doilea modifică valoarea operandului stâng (vezi exerciţiul 2.8.).

Exerciţiul 2.8.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{ int a=1, b=20, lim=100; int rezult; rezult=a<b;
cout<<”a<b=”<<rezult<<’\n’;
// Afişare: a<b=1 (sau o altă valoare diferită de zero pentru alte compilatoare)
rezult=a<=b;
//operatorul realţional <= are prioritate mai mare decât cel de atribuire
cout<<”a<=b=”<<rezult<<’\n’;
// Afisare: a<b=1 (sau o alta valoare diferită de zero pentru alte compilatoare)
rezult=a>b; cout<<”a>b=”<<rezult<<’\n’; // Afişare: a<b=0
rezult=a+10>=lim; cout<<”a+10>=lim=”<<rezult<<’\n’;
/* Op. + are prioritate mai mare decât operatorul >= . Afişare: a+10>=lim=0 */
rezult=a+(10>=lim); cout<<”a+(10>=lim)=”<<rezult<<’\n’;
/*Schimbarea priorităţii op. prin folosirea parantezelor; Afişare: a+(10>=lim)=1 */
rezult=a==b;
cout<<”a==b=”<<rezult<<’\n’; // Afişare: a==b=0
cout<<”a=”<<a<<’\n’; // Afişare: a=1
cout<<”b=”<<b<<’\n’; // Afişare: b=20
rezult=a=b; cout<<”a=b=”<<rezult<<’\n’; // Afişare: a=b=20
cout<<”a=”<<a<<’\n’; // Afişare: a=20

40
CAPITOLUL 2 Date, operatori şi expresii

cout<<”b=”<<b<<’\n’; // Afişare: b=20


rezult=5>b>10;cout<<”b=”<<b<<’\n’; // Afişare: b=20
cout<<”5>b>10=”<<rezult<<’\n’;} //Echiv. cu (5>b)>10Afişare: 5>b>10=0

 Operatori logici pe cuvânt


Operator Semnificaţie Exemple
! Not (negaţie logică) !(a==b)
&& And (conjuncţie, şi logic) (a>b)&&(b>c)
|| Or (disjuncţie, sau logic) (a>b)||(b>c)

Aceşti operatori (primul unar, ceilalţi binari) pot fi aplicaţi datelor numerice sau caracter.
Evaluarea expresiilor în care intervin operatorii logici pe cuvânt se face conform tabelului 2.4.

Tabelul 2.4.
x y !x x&&y x||y
1 (adevărat) 1 (adevărat) 0 (fals) 1 (adevărat) 1 (adevărat)
1 (adevărat) 0 (fals) 0 (fals) 0 (fals) 1 (adevărat)
0 (fals) 1 (adevărat) 1 (adevărat) 0 (fals) 1 (adevărat)
0 (fals) 0 (fals) 1 (adevărat ) 0 (fals) 0 (fals)

Expresia !<expresie> are valoarea 0 (fals) dacă expresia-operand are o valoare diferită de
zero şi valoarea unu (adevărat) dacă expresia-operand are valoarea zero.
Expresia <expresie1>||<expresie2> are valoarea diferită de 0 dacă FIE expresie1, FIE
expresie2 au valori diferite de zero.
Expresia <expresie1>&&<expresie2> are valoarea diferită de 0 dacă AMBELE
expresii-operand ( expresie1 şi expresie2) au valori diferite de zero.

Exerciţiul 2.9.: Să se scrie următorul program şi să se urmărească rezultatele execuţiei.


#include <iostream.h>
void main()
{ int a=0, b=10, c=100, d=200; int rezult; rezult=a&&b;
cout<<”a&&b=”<<rezult<<’\n’; //Afişare a&&b=0
rezult=a||b;cout<<”a||b=”<<rezult<<’\n’;// a||b=1(sau val. nenulă)
rezult=!a;cout<<”!a=”<<rezult<<’\n’; // !a=1 (sau valoare nenulă)
rezult=!b; cout<<”!b=”<<rezult<<’\n’; //Afişare !b=0
rezult=(a>b) || (b>c);cout<<”(a>b) || (b>c)=”<<rezult<<’\n’;
//Afişare (a>b) || (b>c) =1 (sau valoare nenulă)
rezult=!(c<d);cout<<”!(c<d)=”<<rezult<<’\n’;//Afişare !(c>d)=0
rezult=(a-b)&&1;cout<<”(a-b)&&1=”<<rezult<<’\n’;
//Afişare (a-b)&&1 =1 (sau valoare nenulă)
rezult=d||b&&a;cout<<”d||b&&a=”<<rezult<<’\n’;//Afişare d||b&&a =1
}// În evaluarea expresiilor, s-au aplicat priorităţile operatorilor

Exerciţiul 2.10.: Să se scrie un program care citeşte un număr real şi afişează 1 dacă numărul
citit aparţine unui interval ale cărui limite sunt introduse de la tastatură, sau 0 în caz contrar.
#include <iostream.h>
void main()
{ double lmin, lmax, nr;cout<<"Numar=";cin>>nr;
cout<<”Limita inferioară a intervalului:”; cin>>lmin;
cout<<”Limita superioară a intervalului:”; cin>>lmax;
cout<<(nr>=lmin && nr<=lmax); }

41
CAPITOLUL 2 Date, operatori şi expresii

 Operatori logici pe bit (simpli sau compuşi)


Operator Semnificaţie Exemple
~ Negaţie (cod complementar faţă de unu) ~a
& AND (Conjuncţie, şi logic pe bit a&0377
| OR (Disjuncţie, sau logic pe bit) a|0377
^ XOR (Sau exclusiv logic pe bit) a^b
<< Deplasare stânga cu un număr indicat de poziţii 0377<<2
>> Deplasare dreapta cu un număr indicat de poziţii 0377>>2

Aceşti operatori nu se aplică numerelor reale, ci numai datelor de tip întreg sau caracter.
Primul operator este unar, ceilalţi binari. Operatorii acţionează la nivel de bit, conform
tabelelului 2.5.

Tabelul 2.5.
x y x&y x|y x^y ~x
1 1 1 1 0 0
1 0 0 1 1 0
0 1 0 1 1 1
0 0 0 0 0 1

Operatorul ~ are aceeaşi prioritate ca operatorii aritmetici unari. El furnizează complementul


faţă de unu al unui întreg, adică va schimba fiecare bit de pe 1 în zero şi invers.
Operatorii de deplasare pe bit (<< şi >>) efectuează deplasarea la stânga sau la dreapta a
operandului stâng, cu numărul de biţi indicaţi de operandul drept. Astfel, x<<2 deplasează
biţii din x la stânga, cu două poziţii, introducând zero pe poziţiile rămase vacante.
Operatorul binar ^ îşi găseşte o utilizare tipică în expresii ca: x&^077, care maschează
ultimii 6 biţi ai lui x pe zero.
Operatorul & este adesea utilizat în expresii ca x&0177, unde setează toţi biţii pe zero, cu
excepţia celor de ordin inferior din x.
Operatorul | este utilizat în expresii ca: x&MASK , unde setează pe unu biţii care în x şi masca
MASK sunt setaţi pe unu.
Operatorii logici pe bit & şi | sunt diferiţi de operatorii logici && şi || (pe cuvânt).

Exemplul 2.31.:
int a=3; //Reprezentare internă a lui a (pe 2 octeţi): 0000000000000011
int b=5; //Reprezentare internă a lui b (pe 2 octeţi): 0000000000000101
int rez=~a; cout<<"~"<<a<<'='<<rez<<'\n'; //~3= -4
//Complementul faţă de unu este: 1111111111111100 (în octal: 0177777774 (!a= - 4)
rez=a & b; cout<<a<<'&'<<b<<'='<<rez<<'\n'; //3&5=1
//a&b=0000000000000001 =1
rez=a^b; cout<<a<<'^'<<b<<'='<<rez; // 3^5= 6
//a ^b = 0000000000000110
rez=a|b; cout<<a<<'|'<<b<<'='<<rez; //3|5= 7
//a | b = 0000000000000111
rez=a<<2; cout<<a<<"<<"<<3<<'='<<rez; //3<<2=16=2*2 3
//a<<2= 0000000001100000
rez=5>>2; cout<<b<<">>"<<2<<'='<<rez; //5>>2=1=5/2 2
//b>>2= 0000000000000001

42
CAPITOLUL 2 Date, operatori şi expresii

Deplasarea la stânga a unei date cu n poziţii este echivalentă cu înmulţirea valorii acesteia cu
2 n . Deplasarea la dreapta a unei date fără semn cu n poziţii este echivalentă cu împărţirea
valorii acesteia cu 2 n .
Combinând operatorii logici pe bit cu operatorul de atribuire, se obţin operatorii:
&=, ^=, |=, <<=, >>=.

 Operatorul condiţional
Este un operator ternar (necesită 3 operanzi), utilizat în construcţii de forma:
<expresie1>?<expresie2>:<expresie3>
Se evaluează expresia1. Dacă aceasta are o valoare diferită de zero, atunci tipul şi valoarea
întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei2. Altfel (dacă expresie1 are
valoarea zero), tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei3.
Deci operatorul condiţional este folosit pentru a atribui întregii expresii tipul şi valoarea
expresiei2 sau a expresiei3, în funcţie de o anumită condiţie. Acest lucru este echivalent cu:
Dacă expresie1 diferită de zero
Atunci evaluează expresie2
Altfel evaluează expresie3

Exemplul 2.32.:
int semn =(x<0)?-1:1 //dacă x<0, atunci semn=-1, altfel semn=1.

 Operatorul virgulă
Este utilizat în construcţii de forma:
<expresie1>, <expresie2> [, <expresie3>, . . . ]
Operatorul virgulă forţează evaluarea unei expresii de la stânga la dreapta; tipul şi valoarea
întregii expresii este dată de tipul şi valoarea ultimei expresii. Operatorul virgulă este folosit
în cadrul instrucţiunii for. Operatorul virgulă are cea mai mică prioritate.

Exemplul 2.33.:
int x, c, y;
cout<<”Astept val. ptr. y:”; cin>>y;
x=(c=y, c<=5);/* c va primi valoarea lui y (citită); se verifică dacă c este mai mic
sau egal cu 5. Daca nu, x=0; daca da, x=1 sau x=valoare diferită de zero)*/
x++, y--; //întâi este incrementat x, apoi este decrementat y

 Operatorul sizeof()
Este un operator unar, care furnizează numărul de octeţi pe care este memorată o dată
de un anumit tip. Operandul este un tip sau o dată (constantă sau variabilă).

Exemplul 2.34.:
cout<<sizeof(int);// afişează nr. de octeţi pe care este memorat un întreg (2)
int a=8; cout<<sizeof(a)<<sizeof(20)<<'\n';
//afişează nr. de oct. pe care este memorată var. întreagă a, respectiv const. întreagă 9
cout<<sizeof(”ab6*”);//afişează 5, nr. oct. pe care este mem. const. şir ”ab6*”

 Operatorul (tip)
Este un operator unar care apare în construcţiile numite ”cast” şi converteşte tipul
operandului său la tipul specificat între paranteze.
Exemplul 2.35.:
int a=9; cout<<(float)a/2; // conv. operandul a (de tip int) în float; afiş. 4.5

43
CAPITOLUL 2 Date, operatori şi expresii

În afara operatorilor prezentaţi, există şi alţi operatori, enumeraţi în continuare. Despre aceşti
operatori vom discuta în capitolele viitoare, când cunoştinţele acumulate vor permite acest
lucru.

 Operatorul unar *
Este operator unar, numit şi operator de deferenţiere. Se aplică unei expresii de tip
pointer şi este folosit pentru a accesa conţinutul unei zone de memorie spre care
pointează operatorul. Operatorii & (adresă, de referenţiere) şi * sunt complementari.

Exemplul 2.36.: Expresia *a este înlocuită cu valoarea de la adresa conţinută în variabila


pointer a.

 Operatorii paranteză ( )
Parantezele rotunde ( ) se utilizează în expresii, pentru schimbarea ordinii de
efectuare a operaţiilor, sau la apelul funcţiilor. La apelul funcţiilor, parantezele
rotunde încadrează lista parametrilor efectivi. Din acest motiv, parantezele rotunde
sunt numite şi operatori de apel de funcţie.

Exemplul 2.37.:
double sum(double a, double b);
/*declar. funcţiei sum, care are 2 arg. reale(double) şi returnează o val. de tip double */
void main()
{
. . .
double a=sum(89.9,56.6);//apelul funcţiei sum, cu param. efectivi 89.9 şi 56.6
int s0=6; double s1=(s0+9)/a; //folosirea parantezelor în expresii
. . .
}

Tabelul 2.6.
Nr. Clasă de operatori Operatori Asociativitate
1. Primari () [] . -> :: de la stânga la dreapta
2. Unari ! ~ ++ -- sizeof (tip) de la dreapta la stânga
-(unar) *(deferenţiere) &(referenţiere)
3. Multiplicativi * / % de la stânga la dreapta
4. Aditivi + - de la stânga la dreapta
5. Deplasare pe bit << >> de la stânga la dreapta
6. Relaţionali < <= > >= de la stânga la dreapta
7. De egalitate == != de la stânga la dreapta
8. Operatori logici & (ŞI logic pe bit) de la stânga la dreapta
9. ^ (XOR pe bit) de la stânga la dreapta
10. | (SAU logic pe bit) de la stânga la dreapta
11. && de la stânga la dreapta
12. || de la stânga la dreapta
13. Condiţional ?: de la dreapta la stânga
14. De atribuire, aritm. = += -= *= %= de la dreapta la stânga
compuşi, logici pe &= ^= |= <<= >>=
bit compuşi
15. Virgulă , de la stânga la dreapta

44
CAPITOLUL 2 Date, operatori şi expresii

 Operatorii de indexare [ ]
Operatorii de indexare sunt parantezele pătrate [ ]. Acestea încadrează expresii
întregi care reprezintă indici într-un tablou (vector, matrice, etc.).

 Operatorii de acces la membri structurilor


Operatorii ::, ., ->, .* şi ->* permit accesul la componentele unei structuri (a unei
date compuse, cu mai multe elemente). Ei vor fi studiaţi în capitolul 7.

În tabelul 2.6. sunt prezentaţi toţi operatorii, grupaţi pe categorii, cu priorităţile lor şi regulile
de asociativitate. Operatorii dintr-o categorie au aceeaşi prioritate.

2.5.2. EXPRESII

Prin combinarea operanzilor şi a operatorilor se obţin expresii. Tipul unei expresii este dat de
tipul rezultatului obţinut în urma evaluării acesteia. La evaluarea unei expresii se aplică
regulile de prioritate şi asociativitate a operatorilor care apar în expresie. Ordinea de aplicare a
operatorilor poate fi schimbată prin folosirea parantezelor. La alcătuirea expresiilor, este
indicată evitarea expresiilor în care acelaşi operand apare de mai multe ori.

2.6. CONVERSII ALE TIPULUI OPERANZILOR


La evaluarea expresiilor, în anumite situaţii, se realizează conversii ale tipului operanzilor.
Aceste conversiile pot fi:
 Automate;
 Cerute de evaluarea expresiilor;
 Cerute de programator (prin construcţiile cast), explicite.

 Conversiile automate sunt realizate de către compilator, de fiecare dată când într-o
expresie apar operanzi de tipul char sau short int:
char, short int -> int

 Conversiile cerute de evaluarea expresiilor sunt efectuate în cazurile în care în expresii


apar operanzi de tipuri diferite. Înaintea aplicării operatorilor, se realizează conversia
unuia sau a ambilor operanzi:
 Dacă un operand este de tip long int, celălalt (de tip int sau char) este convertit la
acelaşi tip; tipul expresiei este long int.
 Dacă un operand este de tipul double, celălalt (de tip int, char sau float) este
convertit la acelaşi tip; tipul expresiei este double.
 Dacă un operand este de tipul float, celălalt (de tip int sau char) este convertit la
acelaşi tip; tipul expresiei este float.

 Conversiile explicite (cerute de programator) se realizează cu ajutorul construcţiilor cast.

Exemplul 2.37.:
int x=3; float y; y=(float)x/2;
Înainte de a se efectua împărţirea celor 2 operanzi, operandul x (întreg) este convertit în
număr real simplă precizie (float). După atribuire, valoarea lui y va fi 1.5. Dacă nu ar fi fost
folosit operatorul de conversie în expresia y=x / 2, operanzii x şi 2 fiind întregi, rezultatul
împărţirii este întreg, deci y ar fi avut valoarea 1.

45
CAPITOLUL 2 Date, operatori şi expresii

Exemplul 2.38.:
int a,b,c; char x,y,z; float n1; a = b = c = -27;
x = y = z = 'A'; n1=3.6792; a = y; /* a = 65 (codul caracterului A) */
x = b; n1 = b; a = n1; /* x = -27 n1= -27.00 a = 3 */

2.7. ÎNTREBĂRI ŞI PROBLEME

ÎNTREBĂRI

1. Ce reprezintă datele şi care sunt atributele 25. Operatorul de referenţiere.


lor? 26. Operatori relaţionali binari.
2. Care sunt diferenţele între constante şi 27. Ce sunt literalii?
variabile? 28. Diferenţe între operatorii logici pe bit şi
3. Cine determină tipul unei constante? operatorii logici pe cuvânt.
4. Ce sunt identificatorii? 29. Cum explicaţi că operatorii aplicabili
5. Ce sunt directivele preprocesor? datelor întregi se pot folosi şi pentru
6. Ce reprezintă variabilele? datele de tip caracter?
7. Ce sunt constantele? 30. Care sunt modalităţile de realizare a
8. Enumeraţi tipurile simple de variabile. operaţiilor de intrare/ieşire în limbajul C?
9. Câte tipuri de directive preprocesor Dar în C++?
cunoasteţi? Exemple. 31. Care este tipul rezultatului unei operaţii
10. Care este modalitatea de a interzice de atribuire?
modificarea valorii unei variabile? 32. Cum sunt reprezentate intern datele de tip
11. Ce loc ocupă declararea varibilelor în char?
cadrul unui program sursă scris în 33. Cum se memorează un o dată şir de
limbajul C++? caractere?
12. Ce tipuri de variabile se utilizează pentru 34. Ce semnifică parantezele unghiulare < >
datele numerice? care încadrează numele unui fişier
13. Care este diferenţa între constantele header?
35.2e-1 şi 3.52 ? Dar între "\t" şi '\t'? 35. Ce conţin fişierele header?
14. Ce tip are constanta 6.44 ? 36. Care sunt calificatorii folosiţi alături de
15. Diferenţa dintre operatorii = şi = =. tipurile de bază pentru obţinerea tipurilor
16. Ce reprezintă caracterele "escape"? derivate de date?
17. Constante întregi. 37. De către cine este dat tipul unei expresii?
18. Ce tipuri de conversii cunoaşteţi? 38. Operatorul virgulă
19. Care sunt conversiile realizate în mod 39. Constante şir de caractere.
automat, de către compilator, la evaluarea 40. Ce operatori ternari cunoasteţi?
unei expresii? 41. Care dintre următorii operatori pot fi
20. Ce este “volatile”? aplicaţi datelor numerice reale? & (de
21. Constante reale. referenţiere), %, +, -, *, /, <<, | ?
22. Ce sunt operatorii? 42. Care dintre identificatorii următori sunt
23. Care din următoarele tipuri desemnează incorecţi? acceleraţie gravitaţională,
date întregi, fără semn: int, short int, char, acceleraţie, acceleraţie_gravitaţională,
signed int, unsigned int, long int? Acceleraţie_gravitaţională, 9acceleraţie
24. Operatori aritmetici binari compuşi. 43. Constante caracter.

46
CAPITOLUL 2 Date, operatori şi expresii

PROBLEME

1. Să se scrie declaraţiile necesare pentru definirea constantelor simbolice: pi, g (acceleraţia


gravitaţională), unghi_drept, dimensiune_MAX.

2. Care va fi rezultatul afişat pe ecran în urma execuţiei următoarelor secvenţe:


 double a=9/2; cout<<a*5<<’\n’;
 double a=9.7, b=5.6; cout<<(a+6<b)<<’\n’;
 double a=9/4; cout<<a*6<<’\n’;
 double x=3;int y=++x+5;cout<<y<<’\n’;
 int a=7; cout<<(!a)<<’\n’;
 int a=10.5; cout<<a++<<’\n’; cout<<a<<’\n’;
 int a=7; cout<<++a<<’\n’; cout<<a<<’\n’;
 int a=10; cout<<a++<<’\n’; cout<<a<<’\n’;
 double a=7/2; cout<<a<<’\n’;
 int x=3; int y=x++-2; cout<<y<<’\n’;
 int x=3; int y=++x+5; cout<<y<<’\n’;
 double a=5.6, b=7.45; cout<<(a>b)<<’\n’;

3. Să se verifice corectitudinea următoarelor secvenţe. Pentru cele incorecte, explicaţi sursa


erorilor. Pentru cele corecte, specificaţi rezultatul.
 double a=9.7, b=5.2; int c=(a+6<b)++; cout<<c<<’\n’;
 double a=7/5; double c=a*5++; cout<<c<<’\n’;
 double a=9.7, b=5.6; int c=(a%6<b)++; cout<<c<<’\n’;
 double a=5.6, b=7.45; cout<<++(a+5>b)<<’\n’;
 double a=9.8; double b=9.7; cout<<a%b<<’\n’;
 int a=9; cout<<&(a+8)<<'\n';
 int I=8; cout<<(I+10)++<<'\n';
 double a=8.7; A=(a+8)/56; cout<<A<<'\n';
 int x=3/5; int y=x++; char x='J'; cout<<"y="<<y<<'\n';
 char a='X';const int b=89; b+=8; cout<<"b="<<b<<" a="<<a<<'\n';
 const x=34; int g=56; x+=h; cout<<"g="<<g<<"x="<<x<<'\n';
 double y=9.8; int a=(y<<7); cout<<"a="<<a<<"y="<<y<<'\n';
 int f=98789; f++; cout<<"f="<<f<<'\n';
 cout<<(5++-3)--<<'\n';
 cout<<('A'>'Z');
 int a=9; cout<<(a!=9)<<'\n'; cout<<(++a!=9); cout<<(a++!=9);
 int a=9; cout<<(a!=9)<<'\n'; cout<<(a++!=9); cout<<(++a!=9);
 int a=9; cout<<(a++-2*5);
 cout<<(sizeof('A')<=1)<<'\n';
 cout<<(int)'A';
 double x; int y=8.5; x=y%3; cout<<"x="<<x<<" y="<<y<<'\n';
 double x; int y=8; x=y/3; cout<<"x="<<x<<" y="<<y<<'\n';
 double w=2.5; cout<<(!w); cout<<((!w)++); cout<<(!w+2)++;
 cout<<sizeof("ab9*")<<'\t'<<sizeof("a\nb");
 double x=3; double y=(x<7)?1:0; cout<<y<<"\n";
 int m=2, n=5, p=10; p=(m=n, n<20); cout<<"p="<<p<<'\n';
 int m=2, n=3, p=5; int q=m=n=p; cout<<q<<'\n';
 int x=3; double y=25.2, z; x=y; cout<<x<<'\n';
 double q=35, z=q/3; cout<<z<<'\n';
 int x=2; char backslash='\n'; cout<<"x="<<x<<" backslash=";
cout<<backslash<<'\n';

47
CAPITOLUL 2 Date, operatori şi expresii

4. Să se scrie un program care afişează următoarele mesaje (inclusiv ", ', \):
 Sirul "este dupa-amiaza" este memorat pe .... octeti.
 O marime intreaga este memorata pe ... octeti.
 O marime reala, in simpla precizie este memorata pe ... octeti!
 O marime reala, in dubla precizie este memorata pe ... bytes!
 Constanta caracter 'Q' memorata pe ... octeti!
 Sirul "a\n\n" este memorat pe ... octeti!
 Sirul "\n" este memorat pe ... biti!
 Caracterul '\' este memorat pe .... biti.

5. Să se evalueze expresiile, ştiind că:


int i=1;int j=2;int k=-7;double x=0;double y=2.3;
 -i - 5 * j >= k + 1
 3 < j < 5
 i + j + k == -2 * j
 x && i || j - 3

6. Care dintre următoarele declaraţii sunt incorecte, şi de ce?


 int lungime cerc, arie, 2latime;
 double greutate=9,34;
 long d=8.78; long double;

7. Ce operaţie logică şi ce mască trebuie să folosiţi pentru a converti codurile ASCII ale
literelor mici în litere mari? Dar pentru conversia inversă?

8. O deplasare la dreapta cu 3 biţi este echivalentă cu o rotaţie la stânga cu câţi biţi?

9. Să se seteze pe 1 toţi biţii dintr-un octet, cu excepţia bitului cel mai semnificativ.

10. Să se scrie un program care citeşte o valoare întreagă. Să se afişeze un mesaj care să
indice dacă numărul citit este par sau impar.

11. Să se citeasca două valori întregi. Să se calculeze şi să se afişeze restul împărţirii celor
două numere.

12. Se ştie că un an bisect este multiplu de 4, nu este multiplu de 100, dar este multiplu de
400. Să se scrie o expresie care are valoarea 1 dacă o valoare întreagă (introdusă de la
tastatură) reprezintă un an bisect, sau 0 în caz contrar.

48
CAPITOLUL 8 Fişiere

8. FIŞIERE

8.1. Caracteristicile generale ale 8.5. Intrări/ieşiri binare


fişierelor 8.6. Poziţionarea într-un fişier
8.2. Deschiderea unui fişier 8.7. Funcţii utilitare pentru lucrul cu
8.3. Închiderea unui fişier fişiere
8.4. Prelucrarea fişierelor text 8.8. Alte operaţii cu fişiere

8.1. CARACTERISTICILE GENERALE ALE FIŞIERELOR


Noţiunea de fişier desemnează o colecţie de informaţii memorată pe un suport permanent (de
obicei discuri magnetice), percepută ca un ansamblu, căreia i se asociază un nume (în vederea
conservării şi regăsirii ulterioare).

Caracteristicile unui fişier (sub sistem de operare MS-DOS) sunt :


 Dispozitivul logic de memorare (discul);
 Calea (în structura de directoare) unde este memorat fişierul;
 Numele şi extensia;
 Atributele care determină operaţiile care pot fi efectuate asupra fişierului (de exemplu: R-
read-only - citire; A-archive; H-hidden - nu se permite nici măcar vizualizarea; S-system -
fişiere sistem asupra cărora numai sistemul de operare poate realiza operaţii operaţii, etc.).

Lucrul cu fişiere în programare oferă următoarele avantaje:


 Prelucrarea de unei cantităţi mari de informaţie obţinută din diverse surse cum ar fi
execuţia prealabilă a unui alt program;
 Stocarea temporară pe suport permanent a informaţiei în timpul execuţiei unui program
pentru a evita supraîncărcarea memoriei de lucru;
 Prelucrarea aceleeaşi colecţii de informaţii prin mai multe programe.

În limbajul C, operaţiile asupra fişierelor se realizează cu ajutorul unor funcţii din biblioteca
standard (stdio.h). Transferurile de informaţie către/de la dipozitivele periferice (tastatură,
monitor, disc, imprimantă, etc.) se realizează prin intermediul unor dispozitive logice identice
numite stream-uri (fluxuri) şi prin intermediul sistemului de operare. Un flux de date este un
fişier sau un dispozitiv fizic tratat printr-un pointer la o structură de tip FILE (din header-ul
stdio.h). Când un program este executat, în mod automat, se deschid următoarele fluxuri de
date predefinite, dispozitive logice (în stdio.h):
 stdin (standard input device) - dispozitivul standard de intrare (tastatura) - ANSII C;
 stdout (standard output device) - dispozitivul standard de ieşire (monitorul) - ANSII C;
 stderr (standard error output device) - dispozitivul standard de eroare (de obicei un
fişier care conţine mesajele de eroare rezultate din execuţia unor funcţii) - ANSII C;
 stdaux (standard auxiliary device) - dispozitivul standard auxiliar (de obicei interfaţa
serială auxiliară) - specifice MS-DOS;
 stdprn (standard printer) - dispozitivul de imprimare - specifice MS-DOS.

147
CAPITOLUL 8 Fişiere

În abordarea limbajului C (impusă de stdio.h), toate elementele care pot comunica informaţii
cu un program sunt percepute - în mod unitar - ca fluxuri de date. Datele introduse de la
tastatură formează un fişier de intrare (fişierul standard de intrare). Datele afişate pe
monitor formează un fişier de ieşire (fişierul standard de ieşire). Sfârşitul oricărui fişier este
indicat printr-un marcaj de sfârşit de fişier (end of file). În cazul fişierului standard de
intrare, sfârşitul de fişier se generează prin Ctrl+Z (^Z) (sub MS-DOS) (sau Ctrl+D sub
Linux). Acest caracter poate fi detectat prin folosirea constantei simbolice EOF (definită în
fişierul stdio.h), care are valoarea -1. Această valoare nu rămane valabilă pentru fişierele
binare, care pot conţine pe o poziţie oarecare caracterul ’\x1A’.
De obicei, schimbul de informaţii dintre programe şi periferice se realizează folosind zone
tampon. O zonă tampon păstrează una sau mai multe înregistrări. Prin operaţia de citire,
înregistrarea curentă este transferată de pe suportul extern în zona tampon care îi corespunde,
programul având apoi acces la elementele înregistrării din zona tampon. În cazul operaţiei de
scriere, înregistrarea se construieşte în zona tampon, prin program, fiind apoi transferată pe
suportul extern al fişierului. În cazul monitoarelor, înregistrarea se compune din caracterele
unui rând. De obicei, o zonă tampon are lungimea multiplu de 512 octeţi. Orice fişier trebuie
deschis inainte de a fi prelucrat, iar la terminarea prelucrării lui, trebuie închis.

Fluxurile pot fi de tip text sau de tip binar. Fluxurile de tip text împart fişierele în linii
separate prin caracterul ’\n’ (newline=linie nouă), putând fi citite ca orice fişier text.
Fluxurile de tip binar transferă blocuri de octeţi (fără nici o structură), neputând fi citite
direct, ca fişierele text.

Prelucrarea fişierelor se poate face la două niveluri:


 Nivelul superior de prelucrare a fişierelor în care se utilizează funcţiile specializate în
prelucrarea fişierelor.
 Nivelul inferior de prelucrare a fişierelor în care se utilizează direct facilităţile oferite de
sistemul de operare, deoarece, în final, sarcina manipulării fişierelor revine sistemului de
operare. Pentru a avea acces la informaţiile despre fişierele cu care lucrează, sistemul de
operare foloseşte câte un descriptor (bloc de control) pentru fiecare fişier.

Ca urmare, există două abordări în privinţa lucrului cu fişiere:


 abordarea implementată în stdio.h, asociază referinţei la un fişier un stream (flux de
date), un pointer către o structură FILE.
 abordarea definită în header-ul io.h (input/output header) asociază referinţei la un fişier
un aşa-numit handle (în cele ce urmează acesta va fi tradus prin indicator de fişier) care
din punct de vedere al tipului de date este in;

Scopul lucrului cu fişiere este acela de a prelucra informaţia conţinută. Pentru a putea accesa
un fişier va trebui să-l asociem cu unul din cele două modalităţi de manipulare. Acest tip de
operaţie se mai numeşte deschidere de fişier. Înainte de a citi sau scrie într-un fişier
(neconectat automat programului), fişierul trebuie deschis cu ajutorul funcţiei fopen din
biblioteca standard. Funcţia primeşte ca argument numele extern al fişierului, negociază cu
sistemul de operare şi retunează un nume (identificator) intern care va fi utilizat ulterior la
prelucrarea fişireului. Acest identificator intern este un pointer la o structură care conţine
informaţii despre fişier (poziţia curentă în buffer, dacă se citeşte sau se scrie în fişier, etc.).
Utilizatorii nu trebuie să cunoască detaliile, singura declaraţie necesară fiind cea pentru
pointerul de fişier.

Exemplu: FILE *fp;

148
CAPITOLUL 8 Fişiere

Operaţiile care pot fi realizate asupra fişierelor sunt:


 deschiderea unui fişier;
 scrierea într-un fişier;
 citirea dintr-un fişier;
 poziţionarea într-un fişier;
 închiderea unui fişier.

8.2. DESCHIDEREA UNUI FIŞIER


 Funcţia fopen
Crează un flux de date între fişierul specificat prin numele extern (nume_fişier) şi
programul C. Parametrul mod specifică sensul fluxului de date şi modul de interpretare a
acestora. Funcţia returnează un pointer spre tipul FILE, iar în caz de eroare - pointerul
NULL (prototip în stdio.h).
FILE *fopen(const char *<nume_fişier>, const char *<mod>);
Parametrul mod este o constantă şir de caractere, care poate conţine caracterele cu
semnificaţiile:
 r : flux de date de intrare; deschidere pentru citire;
 w : flux de date de ieşire; deschidere pentru scriere (crează un fişier nou sau
suprascrie conţinutul anterior al fişierului existent);
 a : flux de date de ieşire cu scriere la sfârşitul fişierului, adăugare, sau crearea
fişierului în cazul în care acesta nu există;
 + : extinde un flux de intrare sau ieşire la unul de intrare/ieşire; operaţii de scriere şi
citire asupra unui fişier deschis în condiţiile r, w sau a.
 b : date binare;
 t : date text (modul implicit).

Exemple:
"r+" – deschidere pentru modificare (citire şi scriere);
"w+" – deschidere pentru modificare (citire şi scriere);
"rb" – citire binară;
"wb" – scriere binară;
"r+b" – citire/scriere binară.

 Funcţia freopen
Asociază un nou fişier unui flux de date deja existent, închizând legătura cu vechiul fişier
şi încercând să deschidă una nouă, cu fişierul specificat. Funcţia returnează pointerul
către fluxul de date specificat, sau NULL în caz de eşec (prototip în stdio.h).
FILE*freopen(const char*<fis>,const char*<mod>,FILE *<flux>);

 Funcţia open
Deschide fişierul specificat conform cu restricţiile de acces precizate în apel. Returnează
un întreg care este un indicator de fişier sau -1 (în caz de eşec) (prototip în io.h).
int open(const char *<fişier>,int <acces> [,int <mod>]);
Restricţiile de acces se precizează prin aplicarea operatorului | (disjuncţie logică la nivel
de bit) între anumite constante simbolice, definite în fcntl.h, cum sunt :

149
CAPITOLUL 8 Fişiere

O_RDONLY - citire;
O_WRONLY - scriere
O_RDWR - citire şi scriere
O_CREAT - creare
O_APPEND - adăugare la sfârşitul fişierului
O_TEXT - interpretare CR-LF
O_BINARY - nici o interpretare.,

Restricţiile de mod de creare se realizează cu ajutorul constantelor:


S_IREAD - permisiune de citire din fişier
S_IWRITE - permisiune de scriere din fişier, eventual legate prin operatorul “|”.

 Funcţia creat
Crează un fişier nou sau îl suprascrie în cazul în care deja există. Returnează indicatorul
de fişier sau -1 (în caz de eşec). Parametrul un_mod este obţinut în mod analog celui de la
funcţia de deschidere (prototip în io.h).
int creat(const char *<nume_fişier>, int <un_mod>);

 Funcţia creatnew
Crează un fişier nou, conform modului specificat. Returnează indicatorul fişierului nou
creat sau rezultat de eroare (-1), dacă fişierul deja există (prototip în io.h).
int creatnew(const char *<nume_fişier>, int <mod>);

După cum se observă, informaţia furnizată pentru deschiderea unui fişier este aceeaşi în
ambele abordări, diferenţa constând în tipul de date al entitaţii asociate fişierului.
Implementarea din io.h oferă un alt tip de control la nivelul comunicării cu echipamentele
periferice (furnizat de funcţia ioctrl), asupra căruia nu vom insista, deoarece desfăşurarea
acestui tip de control este mai greoaie, dar mai profundă.

8.3. ÎNCHIDEREA UNUI FIŞIER


 Funcţia fclose
int fclose(FILE *<flux>);
Funcţia închide un fişier deschis cu fopen şi eliberează memoria alocată (zona tampon
şi structura FILE). Returnează valoarea 0 la închiderea cu succes a fişierului şi -1 în caz
de eroare (prototip în stdio.h).

 Funcţia fcloseall
int fcloseall(void);
Închide toate fluxururile de date şi returnează numărul fluxurilor de date închise (prototip
în stdio.h).

 Funcţia close
int close(int <indicator>);
Închide un indicator de fişier şi returnează 0 (în caz de succes) sau -1 în caz de eroare
(prototip în io.h).

150
CAPITOLUL 8 Fişiere

8.4. PRELUCRAREA FIŞIERELOR TEXT


După deschiderea unui fişier, toate operaţiile asupra fişierului vor fi efectuate cu pointerul
său. Operaţiile de citire şi scriere într-un fişier text pot fi:
 intrări/ieşiri la nivel de caracter (de octet);
 intrări/ieşiri la nivel de cuvânt (2 octeţi);
 intrări/ieşiri de şiruri de caractere;
 intrări/ieşiri cu formatare.

Comunicarea de informaţie de la un fişier către un program este asigurată prin funcţii de citire
care transferă o cantitate de octeţi (unitatea de măsură în cazul nostru) din fişier într-o
variabilă-program pe care o vom numi buffer, ea însăşi având sensul unei înşiruiri de octeţi
prin declaraţia void *buf. Comunicarea de informaţie de la un program către un fişier este
asigurată prin funcţii de scriere care transferă o cantitate de octeţi dintr-o variabilă-program
de tip buffer în fişier.

Fişierele sunt percepute în limbajul C ca fiind, implicit, secvenţiale (informaţia este parcursă
succesiv, element cu element). Pentru aceasta, atât fluxurile de date cât şi indicatorii de fişier
au asociat un indicator de poziţie curentă în cadrul fişierului. Acesta este iniţializat la 0 în
momentul deschiderii, iar operaţiile de citire, respectiv scriere, se referă la succesiunea de
octeţi care începe cu poziţia curentă. Operarea asupra fiecărui octet din succesiune determină
incrementarea indicatorului de poziţie curentă.

8.4.1. PRELUCRAREA UNUI FIŞIER LA NIVEL DE CARACTER

Fişierele pot fi scrise şi citite caracter cu caracter folosind funcţiile fputc (pentru scriere) şi
fgetc (citire).
 Funcţia fputc
int fputc (int <c>, FILE *<flux>);
c – este codul ASCII al caracterului care se scrie în fişier;
flux – este pointerul spre tipul FILE a cărui valoare a fost returnată de funcţia fopen.
Funcţia putc returnează valoarea lui c (valoarea scrisă în caz de succes), sau –1 (EOF) în
caz de eroare sau sfârşit de fişier.

 Funcţia fgetc
int fgetc (FILE *<flux>);
Funcţia citeşte un caracter dintr-un fişier (pointerul spre tipul FILE transmis ca
argument) şi returnează caracterul citit sau EOF la sfârşit de fişier sau eroare.

Exerciţiu: Să se scrie un program care crează un fişier text în care se vor scrie caracterele
introduse de la tastatură (citite din fişierul standard de intrare), până la întâlnirea caracterului
^Z = Ctrl+Z.
#include <stdio.h>
#include <process.h>
void main()
{int c, i=0; FILE *pfcar;
char mesaj[]="\nIntrodu caractere urmate de Ctrl+Z (Ctrl+D sub\
Linux):\n";

151
CAPITOLUL 8 Fişiere

char eroare[]="\n Eroare deschidere fişier \n";


while(mesaj[i]) putchar(mesaj[i++]);
pfcar=fopen("f_car1.txt","w");
// crearea fişierului cu numele extern f_car1.txt
if(pfcar==NULL)
{i=0;
while(eroare[i])putc(eroare[i++],stdout);
exit(1);
}while((c=getchar())!=EOF) // sau: while ((c=getc(stdin)) != EOF)
putc(c,pfcar); // scrierea caracterului în fişier
fclose(pfcar); // închiderea fişierului
}

Exerciţiu: Să se scrie un program care citeşte un fişier text, caracter cu caracter, şi afişează
conţinutul acestuia.
#include <stdio.h>
#include <process.h>
void main()
{
int c, i=0;
FILE *pfcar;
char eroare[]="\n Eroare deschidere fişier \n";
pfcar=fopen("f_car1.txt","r");
//deschiderea fişierului numit f_car1.txt în citire
if(pfcar==NULL)
{
i=0;
while(eroare[i])putc(eroare[i++],stdout);
exit(1);
} while((c=getc(pfcar))!=EOF) //citire din fişier, la nivel de caracter
putc(c,stdout);
//scrierea caracterului citit în fişierul standard de ieşire (afişare pe monitor)
fclose(pfcar);
}

8.4.2. PRELUCRAREA UNUI FIŞIER LA NIVEL DE CUVÂNT

Funcţiile fputw şi fgetw (putword şi getword) sunt echivalente cu funcţiile fputc şi


fgetc, cu diferenţa că unitatea transferată nu este un octet (caracter), ci un cuvânt (un int).
int fgetw(FILE *<flux>);
int fputc (int <cuv>, FILE *<flux>);

Se recomandă utilizarea funcţiei feof pentru a testa întâlnirea sfârşitului de fişier.


Exemplu:
int tab[100]; FILE *pf;
// . . . deschidere fişier
while (!feof(pf)){
for (int i=0; i<100; i++){if (feof(pf)) break;
tab[i]=getw(pf);
//citire din fişier la nivel de cuvânt şi memorare în vectorul tab
// . . .
}
} printf("Sfarşit de fişier\n");
152
CAPITOLUL 8 Fişiere

8.4.3. PRELUCRAREA UNUI FIŞIER LA NIVEL DE ŞIR DE CARACTERE

Într-un fişier text, liniile sunt considerate ca linii de text separate de sfârşitul de linie ('\n'),
iar în memorie, ele devin şiruri de caractere terminate de caracterul nul ('\0'). Citirea unei
linii de text dintr-un fişier se realizează cu ajutorul funcţiei fgets, iar scrierea într-un fişier -
cu ajutorul funcţiei fputs.

Funcţia fgets este indentică cu funcţia gets, cu deosebirea că funcţia gets citeşte din
fişierul standard de intrare (stdin). Funcţia fputs este indentică cu funcţia puts, cu
deosebirea funcţia puts scrie în fişierul standard de ieşire (stdout).

 Funcţia fputs
int fputs(const char *<sir>, FILE *<flux>);
Funcţia scrie un şir de caractere într-un fişier şi primeşte ca argumente pointerul spre zona de
memorie (buffer-ul) care conţine şirul de caractere (sir) şi pointerul spre structura FILE.
Funcţia returnează ultimul caracter scris, în caz de succes, sau -1 în caz de eroare.

 Funcţia fgets
char *fgets(char *<sir>, int <dim>, FILE *<flux>);
Funcţia citeşte maximum dim-1 octeţi (caractere) din fişier, sau până la întâlnirea sfarşitului
de linie. Pointerul spre zona în care se face citirea caracterelor este sir. Terminatorul null
('\0') este plasat automat la sfârşitul şirului (buffer-lui de memorie). Funcţia returnează un
pointer către buffer-ul în care este memorat şirul de caractere, în caz de succes, sau pointerul
NULL în cazul eşecului.

Exerciţiul 1: Să se scrie un program care crează un fişier text în care se vor scrie şirurile de
caractere introduse de la tastatură.
#include <stdio.h>
void main()
{
int n=250; FILE *pfsir;
char mesaj[]="\nIntrodu siruri car.urmate de Ctrl+Z(Ctrl+D sub\
Linux):\n";
char sir[250],*psir; fputs(mesaj,stdout);
pfsir=fopen("f_sir.txt","w");//deschiderea fiş. f_şir.txt pentru scriere
psir=fgets(sir,n,stdin);// citirea şirurilor din fişierul standard de intrare
while(psir!=NULL)
{fputs(sir,pfsir); // scrierea în fişierul text
psir=fgets(sir,n,stdin);
}
fclose(pfsir);
}

Exerciţiul 2: Să se scrie un program care citeşte un fişier text, linie cu linie, şi afişează
conţinutul acestuia.
#include <stdio.h>
void main()
{int n=250; FILE *pfsir; char sir[250],*psir;
pfsir=fopen("f_sir.txt","r"); psir=fgets(sir,n,pfsir);
while(psir!=NULL)

153
CAPITOLUL 8 Fişiere

{ fputs(sir,stdout); //sau: puts(sir);


//afişarea (scrierea în fişierul standard de ieşire) şirului (liniei) citit din fişierul text
psir=fgets(sir,n,pfsir); //citirea unei linii de text din fişier
}
fclose(pfsir);}

Exerciţiul 3: Să se scrie un program care citeşte conţinutul unui fişier text (al cărui nume se
introduce de la tastatură) şi afişează câte litere mari, câte litere mici, câte cifre şi câte spaţii
albe conţine fişierul.
#include <stdio.h>
#include <ctype.h>
#include <stdio.h>
#include <process.h>
#include <string.h>
#include <conio.h>
void numarare(const char *);
void main()
{ FILE *fp; clrscr();
char linie[100], nume_fis[10], *c;
printf("Nume fisier:");
scanf("%s",nume_fis);
fp = fopen(nume_fis,"r"); //deschidere pentru citire
if (fp == NULL){
printf("Eroare deschidere fisier %s\n", nume_fis);
exit(1);}
int contor_lin=0;
do { c = fgets(linie,100,fp); /* citeste linie din fisier*/
if (c != NULL){
//printf("%s",linie); /* afisarea liniei citite */
contor_lin++;printf("Linia %d:%s\n", contor_lin, linie);
numarare(linie);}
} while (c != NULL);
fclose(fp); //inchidere fisier
}

void numarare(const char *lin)


{ int sp_albe=0, litere_mici=0, litere_mari=0, cifre=0;
for (int index = 0;index<strlen(lin);index++) {
if (isupper(lin[index])) litere_mari++;
if (islower(lin[index])) litere_mici++;
if (isdigit(lin[index])) cifre++;
if (isspace(lin[index])) sp_albe++;
}
printf("Lit. mari=%3d\nLit.
mici=%3d\n",litere_mari,litere_mici);
printf("Cifre=%3d\nSpatii albe=%3d\n",cifre,sp_albe);
getch();
}

Exerciţiul 4: Să se scrie un pprogram care care citeşte conţinutul unui fişier text (al cărui
nume se introduce de la tastatură) şi afişează conţinutul acestuia, transformând literele mari în
litere mici şi literele mici în litere mari.
#include <stdio.h>
#include <ctype.h>
#include <conio.h>

154
CAPITOLUL 8 Fişiere

void transformare(char *);


void main()
{FILE *fp;char linie[80], nume_fis[24];char *c;
printf("Nume fisier -> "); scanf("%s",nume_fis);
fp = fopen(nume_fis,"r");
do {
c = fgets(linie,80,fp); /* citire linie de text */
if (c != NULL)
transformare(linie);
} while (c != NULL);
fclose(fp);
}

void transformare (char *linie)


{
int index;
for (index = 0;linie[index] != 0;index++) {
if (isupper(linie[index])) /* litera mare */
linie[index] = tolower(linie[index]);
else {
if (islower(linie[index])) /* litera mica */
linie[index] = toupper(linie[index]);
}
}
printf("%s",linie);
}

8.4.4. INTRĂRI/IEŞIRI FORMATATE

Operaţiile de intrare/ieşire formatate permit citirea, respectiv scrierea într-un fişier text,
impunând un anumit format. Se utilizează funcţiile fscanf şi fprintf, similare funcţiilor
scanf şi printf (care permit citirea/scrierea formatată de la tastatură/monitor).

 Funcţia fscanf
int fscanf(FILE *<pf>, const char *<format>, . . .);

 Funcţia fprintf
int fprintf(FILE *<pf>, const char *<format>, . . .);
Funcţiile primesc ca parametri ficşi pointerul (pf ) spre tipul FILE (cu valoarea atribuită la
apelul funcţiei fopen), şi specificatorul de format (cu structură identică celui prezentat pentru
funcţiile printf şi scanf). Funcţiile returnează numărul câmpurilor citite/scrise în fişier, sau
-1 (EOF) în cazul detectării sfârşitului fişierului sau al unei erori.

8.5. INTRĂRI/IEŞIRI BINARE


Reamintim că fluxurile de tip binar transferă blocuri de octeţi (fără nici o structură), neputând
fi citite direct, ca fişierele text (vezi paragraful 8.1.). Comunicarea de informaţie dintre un
program şi un fişier este asigurată prin funcţii de citire/scriere care transferă un număr de
octeţi, prin intermediul unui buffer.

155
CAPITOLUL 8 Fişiere

Funcţiile de citire
 Funcţia fread
Citeşte date dintr-un flux, sub forma a n blocuri (entităţi), fiecare bloc având dimensiunea
dim, într-un buffer (buf). Returnează numărul de blocuri citite efectiv, sau -1 în caz de
eroare (prototip în stdio.h).
size_t fread(void *<buf>, size_t <dim>, size_t <n>, FILE
*<flux>);

 Funcţia read
Citeşte dintr-un fişier (precizat prin indicatorul său, indicator) un număr de n octeţi şi
îi memorează în bufferul buf. Funcţia returnează numărul de octeţi citiţi efectiv (pentru
fişierele deschise în mod text nu se numără simbolurile de sfirşit de linie), sau -1 în caz
de eroare (prototip în io.h).
int read(int <indicator>, void *<buf>, unsigned <n>);

Funcţiile de scriere
Fişierele organizate ca date binare pot fi prelucrate cu ajutorul funcţiilor fread şi fwrite.
În acest caz, se consideră că înregistrarea este o colecţie de date structurate numite articole.
La o citire se transferă într-o zonă specială, numită zona tampon, un număr de articole care
se presupune că au o lungime fixă.

 Funcţia fwrite
Scrie informaţia (preluată din buffer, buf este pointerul spre zona tampon care conţine
articolele citite) într-un flux de date, sub forma a n entităţi de dimensiune d. Returnează
numărul de entităţi scrise efectiv, sau -1 în caz de eroare (prototip în stdio.h).
size_t fwrite(const void *<buf>,size_t <d>,size_t <n>,FILE
*<flux>);

 Funcţia write
Scrie într-un fişier (desemnat prin indicatorul său, indicator) un număr de n octeţi
preluaţi dintr-un buffer (buf este pointerul spre acesta). Returnează numărul de octeţi
scrişi efectiv sau -1 în caz de eroare (prototip în io.h).
int write(int <indicator>, void *<buf>, unsigned <n>);

Exerciţu: Să se scrie un program care crează un fişier binar în care se vor introduce numere
reale, nenule.
#include <iostream.h>
#include <stdio.h>
int main()
{ FILE *f; double nr; int x;
if ((f=fopen("test_nrb.dat","wb"))==NULL)
//deschidere flux binar, scriere
{ cout<<"\nNu se poate deschide fiş. test_nrb.dat"<<'\n';
return 1;
}
cout<<"\nIntrod.nr(diferite de 0) terminate cu un 0:"<<'\n';
cin>>nr;
while(nr!=0)
{ x=fwrite(&nr, sizeof(nr), 1, f); //scriere în fişier
cin>>nr;
}
fclose(f); return 0;}
156
CAPITOLUL 8 Fişiere

Exemplu: Să se scrie un program ce citeşte dintr-un fişier binar numere reale, nenule.
#include <iostream.h>
#include <stdio.h>
int main()
{ FILE *f;double buf;
if ((f= fopen("test_nrb.dat", "rb")) == NULL)
{ cout<<"\nNu se poate deschide fiş. test_nrb.dat"<<'\n';
return 1; }
cout<<"\nNumerele nenule citite din fişier sunt:"<<'\n';
while((fread(&buf, sizeof(buf), 1, f))==1)
// funcţia sizeof(buf) care returneaza numarul de octeţi necesari variabilei buf.
cout<<buf<<" "; fclose(f); cout<<'\n'; return 0;}

8.6. POZIŢIONAREA ÎNTR-UN FIŞIER


Pe lângă mecanismul de poziţionare implicit (asigurat prin operaţiile de citire şi scriere) se pot
folosi şi operaţiile de poziţionare explicită.

 Funcţia fseek
int fseek(FILE *<pf>, long <deplasament>, int <referinţa>);
Funcţia deplasează capul de citire/scriere al discului, în vederea prelucrării înregistrărilor
fişierului într-o ordine oarecare. Funcţia setează poziţia curentă în fluxul de date la n
octeţi faţă de referinţă):
deplasament – defineşte numărul de octeţi peste care se va deplasa capul discului;
referinţa – poate avea una din valorile:
0 - începutul fişierului (SEEK_SET);
1 - poziţia curentă a capului (SEEK_CUR);
2 - sfârşitul fişierului (SEEK_END).
Funcţia returnează valoarea zero la poziţionarea corectă şi o valoare diferită de zero în
caz de eroare (prototip în stdio.h).

 Funcţia lseek
int lseek(int <indicator>, long <n>, int <referinta>);
Seteaza poziţia curentă de citire/scriere în fişier la n octeţi faţa de referinţă.
Returnează valoarea 0 în caz de succes şi diferită de zero în caz de eroare (io.h).

 Funcţia fgetpos
int fgetpos(FILE *<flux_date>, fpos_t *<poziţie>);
Determină poziţia curentă (pointer către o structură, fpos_t, care descrie această poziţie
în fluxul de date). Înscrie valoarea indicatorului în variabila indicată de poziţie.
Returnează 0 la determinarea cu succes a acestei poziţii sau valoare diferită de zero în caz
de eşec. Structura care descrie poziţia poate fi transmisă ca argument funcţiei fsetpos
(prototip în stdio.h).

 Funcţia fsetpos
int fsetpos(FILE *<flux_date>, const fpos_t *<poziţie>);
Setează poziţia curentă în fluxul de date (atribuie indicatorului valoarea variabilei
indicate poziţie), la o valoare obţinută printr apelul funcţiei fgetpos. Returnează
valoarea 0 în caz de succes, sau diferită de 0 în caz de eşec (prototip în stdio.h).

157
CAPITOLUL 8 Fişiere

Există funcţii pentru modificarea valorii indicatorului de poziţie şi de determinare a poziţiei


curente a acestuia.

 Funcţia ftell
long ftell(FILE *<pf>);
Indică poziţia curentă a capului de citire în fişier. Funcţia returnează o valoare de tip long
int care reprezintă poziţia curentă în fluxul de date (deplasamentul în octeţi a poziţiei
capului faţă de începutul fişierului) sau -1L în caz de eroare (prototip în stdio.h).

 Funcţia tell
long tell(int <indicator>);
Returnează poziţia curentă a capului de citire/scriere în fişier (exprimată în număr de
octeţi faţă de începutul fişierului), sau -1L în caz de eroare (prototip în io.h).

 Funcţia rewind
void rewind(FILE *<flux_date>);
Poziţionează indicatorul la începutul fluxului de date specificat ca argument (prototip în
stdio.h).

8.7. FUNCŢII UTILITARE PENTRU LUCRUL CU FIŞIERE


Funcţii de testare a sfârşitului de fişier
 Funcţia feof
int feof(FILE *<flux_date>);
Returnează o valoare diferită de zero în cazul întâlnirii sfârşitului de fişier sau 0 în
celelalte cazuri (prototip în stdio.h).

 Funcţia eof
int eof(int <indicator>);
Returnează valoarea 1 dacă poziţia curentă este sfârşitul de fişier, 0 dacă indicatorul este
poziţionat în altă parte, sau -1 în caz de eroare (prototip în io.h).

Funcţii de golire a fluxurilor de date


 Funcţia fflush
int fflush(FILE *<flux_date>);
Goleşte un fluxul de date specificat ca argument. Returnează 0 în caz de succes şi -1
(EOF) în caz de eroare (prototip în stdio.h).

 Funcţia flushall
int flushall(void);
Goleşte toate fluxurile de date existente, pentru cele de scriere efectuând şi scrierea în
fişiere. Returnează numărul de fluxuri asupra cărora s-a efectuat operaţia (stdio.h).

8.8. ALTE OPERAŢII CU FIŞIERE


Funcţii care permit operaţii ale sistemului de operare asupra fişierelor
 Funcţia remove
int remove(const char *<nume_fişier>);

158
CAPITOLUL 8 Fişiere

Şterge un fişier. Returnează valoarea 0 pentru operaţie reuşită şi -1 pentru operaţie eşuată
(prototip în stdio.h).

 Funcţia rename
int rename(const char *<nume_vechi>, const char *<nume_nou>);
Redenumeşte un fişier. Returnează 0 pentru operaţie reuşita şi -1 la eşec (stdio.h).

 Funcţia unlink
int unlink(const char *<nume_fişier>);
Şterge un fişier. Returnează 0 la operaţie reuşită şi -1 la eşec; dacă fişierul are permisiune
read-only, funcţia nu va reuşi operaţia (prototip în io.h, stdio.h).

Funcţii care permit manipularea aceluiaşi fişier prin două indicatoare de fişier
independente

 Funcţia dup
int dup(int <indicator>);
Duplică un indicator de fişier. Returnează noul indicator de fişier pentru operaţie reuşită
sau -1 în cazul eşecului (prototip în io.h).

 Funcţia dup2
int dup2(int <indicator_vechi>, int <indicator_nou>);
Duplică un indicator de fişier la valoarea unui indicator de fişier deja existent. Returnează
0 în caz de succes şi -1 în caz de eşec (prototip în io.h).

Funcţii pentru aflarea sau modificarea dimensiunii în octeţi a fişierelor

 Funcţia chsize
int chsize(int <indicator>, long <lungime>);
Modifică dimensiunea unui fişier, conform argumentului lungime. Returnează 0 pentru
operaţie reuşită sau -1 în caz de eşec (prototip în stdio.h).

 Funcţia filelength
long filelength(int <indicator>);
Returnează lungimea unui fişier (în octeţi) sau -1 în caz de eroare (prototip în io.h).

Funcţii de lucru cu fişiere temporare care oferă facilităţi de lucru cu fişiere temporare prin
generarea de nume unice de fişier în zona de lucru.

 Funcţia tmpfile
FILE *tmpfile(void);
Deschide un fişier temporar, ca flux de date, în mod binar (w+b). Returnează pointerul
către fişierul deschis în cazul operaţiei reuşite, sau NULL în caz de eşec (prototip în
stdio.h).

 Funcţia tmpnam
char *tmpnam(char *<sptr>);
Crează un nume unic pentru fişierul temporar (prototip în stdio.h).

 Funcţia creattemp
int creattemp(char *<cale>, int <attrib>);
159
CAPITOLUL 8 Fişiere

Crează un fişier unic ca nume, cu atributele specificate în argumentul attrib (prin


_fmode, O_TEXT sau O_BINARY), în directorul dat în argumentul cale. Returnează
indicatorul (handler-ul) către fişierul creat sau -1 (şi setarea errno) la eşec (io.h).

Exerciţiul 1: Să se creeze un fişier binar, care va conţine informaţiile despre angajaţii unei
întreprinderi: nume, marca, salariu. Să se afişeze apoi conţinutul fişierului.

#include<iostream.h>
#include <stdio.h>
#include <ctype.h>
typedef struct
{ char nume[20];int marca;double salariu;
}angajat;
union
{angajat a;char sbinar[sizeof(angajat)];}buffer;

int main()
{angajat a; FILE *pf; char cont;char *nume_fis;
cout<<"Nume fisier care va fi creat:"; cin>>nume_fis;
if ((pf= fopen(nume_fis, "wb")) == NULL)
{cout<<"\nEroare creare fiş."<<nume_fis<<"!\n";return 1; }
do
{cout<<"Marca : ";cin>>a.marca; cout<<"Nume : ";cin>>a.nume;
cout<<"Salariu :";cin>>a.salariu; buffer.a=a;
fwrite(buffer.sbinar,1,sizeof(angajat),pf);
cout<<"Continuati introducerea de date (d/n) ?"; cin>>cont;
} while(toupper(cont)!='N');
fclose(pf);
//citirea informatiilor
if ((pf= fopen(nume_fis, "rb")) == NULL)
{cout<<"\nEroare citire fişier "<<nume_fis<<"!\n";return 1;}
for(;;)
{fread(buffer.sbinar,1,sizeof(a),pf); a=buffer.a1;
if(feof(pf)) exit(1);
cout<<" Marca : "<<a.marca;cout<<" Numele : "<<a.nume<<'\n';
cout<<" Salariul : "<<a.salariu<<'\n';
}
fclose(pf);
}

Exerciţiul 2: Să se creeze un fişier binar, care va conţine informaţiile despre elevii prezenţi la
un concurs de admitere, cu două probe: nume, prenume, nota1, nota2, media (calculată pe
baza celor două note), numărul curent (completat automat) şi un câmp de observaţii
(completat automat, cu şirul de caractere promovat–dacă media este mai mare sau egală cu 5-
sau nepromovat-dacă media este sub 5). Să se afişeze apoi informaţiile din acest fişier.

#include<iostream.h>
#include <stdio.h>
#include <conio.h>
typedef struct
{ char num[10];
char pren[10];
int n1,n2,m,nrc;
char *obs;
}articol;

160
CAPITOLUL 8 Fişiere

union{
articol a;char sb[sizeof(articol)];
}buf;
articol tampon; FILE *pf; int n,i;
void main()
{clrscr();
pf=fopen("sitstud.dat","wb");
cout<<"Introduceti numarul de studenti:";cin>>n;
for(i=1;i<=n;i++) /* crearea fisierului */
{
tampon.nrc=i;
cout<<"Numele : ";cin>>tampon.num;
cout<<"Prenumele : ";cin>>tampon.pren;
cout<<"Prima nota a studentului "<<tampon.num<<" este : ";
cin>>tampon.n1;
cout<<"A doua nota a studentului "<<tampon.num<<" este : ";
cin>>tampon.n2;
tampon.m=(tampon.n1+tampon.n2)/2;
if(tampon.m>=5)
tampon.obs="promovat";
else tampon.obs="repetent";
buf.a=tampon;
fwrite(buf.sb,1,sizeof(articol),pf);
}
fclose(pf);

pf=fopen("sitstud.dat","rb");
while(!feof(pf)) /* citirea si afisarea informatiilor din fisier */
{
fread(buf.sb,1,sizeof(articol),pf);
if (feof(pf)) break;
tampon=buf.a;
tampon.nrc=i;
cout<<" Numele : ";cout<<tampon.num;
cout<<" Prenumele : ";cout<<tampon.pren<<endl;
cout<<" Prima nota a studentului "<<tampon.num<<" este : ";
cout<<tampon.n1<<endl;
cout<<" A doua nota a studentului "<<tampon.num<<" este : ";
cout<<tampon.n2<<endl;
cout<<" Media studentului este :"<<tampon.m<<endl;
cout<<"Observatii :"<<tampon.obs<<endl;
}
fclose(pf);
}

Exerciţiul 3: Aplicaţie pentru gestiunea materialelor dintr-un depozit. Aplicaţia va avea un


meniu principal şi va permite gestiunea următoarelor informaţii: codul materialului (va fi
chiar “numărul de ordine”), denumirea acestuia, unitatea de măsură, preţul unitar, cantitatea
contractată şi cea recepţionată (vectori cu 4 elemente). Memorarea datelor se va face într-un
fişier de date (un fişier binar cu structuri), numit “material.dat”.
Aplicaţia conţine funcţiile:
1. help() - informare privind opţiunile programului
2. Funcţii pentru fişierele binare, care să suplinească lipsa funcţiilor standard pentru
organizarea directă a fişierelor binare:
citireb() - citire în acces direct din fişier;

161
CAPITOLUL 8 Fişiere

scrieb() - scriere în acces direct în fişier;


citmat() - citirea de la terminal a informaţiilor despre un material;
afismat() - afişarea informaţiilor despre un material (apelată de list);
lungfisis() - determinarea lungimii fişierului existent;
crefis() - creare fişier.
3. Funcţii pentru adăugarea, modificarea, ştergerea şi listarea de materiale.

#include <process.h>
#include <iostream.h>
#include <stdio.h>
#include <ctype.h>
typedef struct material
{ int codm,stoc,cant_c[4],cant_r[4];
char den_mat[20],unit_mas[4];float preţ;};
material mat;FILE *pf;
void crefis(),adaug(),modif(),sterg(),list(),help();
void main()
{char opţiune;
do //afişarea unui meniu de opţiuni şi selecţia opţiunii
{ cout<<'\n'<<"Opţiunea Dvs. de lucru este"<<'\n';
cout<<"(c|a|m|s|l|e|h pentru help) : "; cin>>opţiune;
switch(opţiune)
{case 'c':case 'C':crefis();break;
case 'a':case 'A':adaug();break;
case 'm':case 'M':modif();break;
case 's':case 'S':şterg();break;
case 'l':case 'L':list();break;
case 'h':case 'H':help();break;
case 'e':case 'E': break;
default:help(); break; }
}while(toupper(opţiune)!='E'); }
void help() // afişare informaţii despre utilizarea meniului şi opţiunile acestuia
{cout<<"Opţiunile de lucru sunt :"<<'\n';
cout<<" C,c-creare fisier"<<'\n';
cout<<" A,a-adaugare"<<'\n';
cout<<" M,m-modificare"<<'\n';
cout<<" L,l-listare"<<'\n';
cout<<" S,s-ştergere"<<'\n';
cout<<" H,h-help"<<'\n';
cout<<" E,e-exit"<<'\n'; }
long int lungfis(FILE *f) // returnează lungimea fişierului
{long int posi,posf; posi=ftell(f); fseek(f,0,SEEK_END);
posf=ftell(f); fseek(f,posi,SEEK_SET); return posf; }
void scrieb(int nr,void *a,FILE *f) //scriere în fişierul binar
{long depl=(nr-1)*sizeof(material); fseek(f,depl,SEEK_SET);
if(fwrite(a,sizeof(material),1,f)!=1)
{cout<<"Eroare de scriere in fişier !"<<'\n';exit(1); }
}
void citireb(int nr,void *a,FILE *f) //citire din fişierul binar
{long depl=(nr-1)*sizeof(material); fseek(f,depl,SEEK_SET);
if(fread(a,sizeof(material),1,f)!=1)
{cout<<"Eroare de citire din fişier !"<<'\n'; exit(2); }
}
void afismat(material *a) //afişarea informaţiilor despre un anumit material
{ int i;

162
CAPITOLUL 8 Fişiere

if(a->codm)
{cout<<"Cod material : "<<a->codm<<'\n';
cout<<"Denumire material: "<<a->den_mat<<'\n';
cout<<"Cantitaţi contractate:"<<'\n';
for(i=0;i<4;i++)
cout<<"Contractat "<<i<<" : "<<a->cant_c[i]<<'\n';
cout<<"Cantitaţi recepţionate:"<<'\n';
for(i=0;i<4;i++)
cout<<"Receptionat "<<i<<" : "<<a->cant_r[i]<<'\n';
cout<<"Stoc : "<<a->stoc<<'\n';
cout<<"Unitate de masura: "<<a->unit_mas<<'\n';
cout<<"Preţ unitar : "<<a->preţ<<'\n'; }
else cout<<"Acest articol a fost şters !"<<'\n'; }
void citmat(material *a) //citirea informaţiilor despre un anumit material
{ int i;float temp;
cout<<"Introduceti codul materialului (0=End): ";cin>>a->codm;
if(a->codm==0) return;
cout<<"Introduceţi denumirea materialului : ";cin>>a->den_mat;
cout<<"Introduceţi unitatea de măsură : ";cin>>a->unit_mas;
cout<<"Introduceţi preţul : ";cin>>temp;a->preţ=temp;
cout<<"Introduceţi cantitaţile contractate : "<<'\n';
for(i=0;i<4;i++)
{cout<<"Contractat "<<i+1<<" : ";cin>>a->cant_c[i]; }
cout<<"Introduceţi cantitaţile recepţionate : "<<'\n';
for(i=0;i<4;i++)
{cout<<"Receptionat "<<i+1<<" : ";cin>>a->cant_r[i]; } }
void crefis() //deschidere fisier
{ if((pf=fopen("material.dat","r"))!=NULL)
cout<<"Fişierul exista deja !"<<'\n';
else pf=fopen("material.dat","w");
fclose(pf); }
void adaug() //adăugare de noi materiale
{int na; pf=fopen("material.dat","a");//deschidere pentru append
na=lungfis(pf)/sizeof(material);
do{citmat(&mat);
if(mat.codm) scrieb(++na,&mat,pf);
} while(mat.codm);
fclose(pf); }
void modif() //modificarea informaţiilor despre un material existent
{int na; char ch; pf=fopen("material.dat","r+");
do{cout<<"Numarul art. de modificat este (0=END): ";cin>>na;
if(na)
{citireb(na,&mat,pf);afismat(&mat);cout<<"Modif. art(D/N)? :";
do{ cin>>ch; ch=toupper(ch);
} while(ch!='D' && ch!='N');
if(ch=='D'){citmat(&mat);scrieb(na,&mat,pf); }
}
}while(na); fclose(pf); }
void sterg() //ştergerea din fişier a unui material
{ int n;long int na; pf=fopen("material.dat","r+");
mat.codm=0; na=lungfis(pf)/sizeof(material);
do
{do{cout<<"Numarul articolului de şters este (0=END): ";cin>>n;
if(n<0||n>na) cout<<"Articol eronat"<<'\n';
}while(!(n>=0 && n<=na));
if(n) scrieb(n,&mat,pf);

163
CAPITOLUL 8 Fişiere

}while(n); fclose(pf); }
void list() //afişare informaţii despre un anumit material
{ int na; pf=fopen("material.dat","r");
do{cout<<"Numarul articolului de listat este (0=END): ";cin>>na;
if(na){citireb(na,&mat,pf);afismat(&mat); cout<<'\n';}
}while(na); fclose(pf); }

8.9. ÎNTREBĂRI ŞI PROBLEME


1. Scrieţi un program de tipărire a conţinuturilor mai multor fişiere, ale căror nume se
transmit ca parametri către funcţia main. Tipărirea se face pe ecran (lungimea paginii =
22) sau la imprimantă (lungimea paginii = 61). Conţinutul fiecărui fişier va începe pe o
pagină nouă, cu un titlu care indică numele fişierului. Pentru fiecare fişier, paginile vor fi
numerotate (cu ajutorul unui contor de pagini).
2. Scrieţi un program care citeşte un fişier text. Pornind de la conţinutul acestuia, se va crea
un alt fişier, prin înlocuirea spaţiilor consecutive cu unul singur. Se vor afişa pe ecran
conţinutul fişierului de la care s-a pornit şi conţinutul fişierului obţinut.
3. Să se consulte conţinutul unui fişier şi să se afişeze următoarele informaţii statistice:
numărul de cuvinte din fişier, numărul de caractere, numărul de linii, numărul de date
numerice (nu cifre, numere!).
4. Scrieţi un program care să compare conţinutul a două fişiere, şi afişaţi primele linii care
diferă şi poziţia caracterelor diferite în aceste linii.
5. Scrieţi un program care citeşte conţinutul unui fişier sursă scris în limbajul C şi afişează în
ordine alfabetică fiecare grup al numelor de variabile care au primele n caractere identice
(n este citit de la tastatură).
6. Scrieţi un program care consultă un fişier text şi afişează o listă a tuturor cuvintelor din
fişier. Pentru fiecare cuvânt se vor afişa şi numerele liniilor în care apare cuvântul.
7. Scrieţi un program care citeşte un text introdus de la tastatură şi afişează cuvintele
distincte, în ordinea crescătoare a frecvenţei lor de apariţie. La afişare, fiecare cuvânt va fi
precedat de numărul de apariţii.
8. Scrieţi un program care citeşte un text introdus de la tastatură, ordonează alfabetic liniile
acestuia şi le afişează.
9. Scrieţi o aplicaţie pentru gestiunea informatiilor despre cărţile existente într-o bibliotecă.
Aplicaţia va avea un meniu principal care va permite:
10. Memorarea datelor într-un fişier (un fişier binar cu structuri), al cărui nume se introduce
de la tastatură. Fişierul va contine informaţiile: nume carte, autor, editura, anul apariţiei,
preţ. Pentru fiecare carte, se va genera o cotă (un număr unic care să constituie cheia de
căutare).
a) Adaugărea de noi cărţi;
b) Afişarea informaţiilor despre o anumită carte;
c) Căutarea titlurilor după un anumit autor;
d) Modificarea informaţiilor existente;
e) Lista alfabetică a tuturor autorilor;
f) Ştergerea unei cărţi din bibliotecă;
g) Ordonarea descrescătoare după anul apariţiei;
h) Numele celei mai vechi cărţi din bibliotecă;
i) Numele celei mai scumpe cărţi din bibliotecă;
j) Numele autorului cu cele mai multe cărţi;
k) Valoarea totală a cărţilor din bibliotecă.

164
PCLP CURS
AGENDA :
1. ALGORITMI
1.1 Definitie; Caracteristici
1.2 Date de intrare / iesire
1.3 Schema logica
1.4 Limbaj pseudocod si limbaj programare
2.EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
Program = Date + Algoritm
X
PCLP CURS 3
AGENDA :
1. TIPURI DE DATE
2. OPERATORI LOGICI
3. STRUCTURI ALGORITMICE
3.1 Structura lineara
3.2 Structura alternativa simpla (daca….altfel)
3.3 Structuri repetitive (cu pas initial si final, cu numar cunoscut si
necunoscut de pasi
4.EXEMPLE DE EXERCITII REZOLVATE
5. TEMA
1. TIPURI DE DATE

❑ Tipul de date REAL ( ex: 8,365; 245,56; -3578,456 )

❑ Tipul de date INTREG ( ex: - 45; 245; 3578; -185 )

❑ Tipul de date BOOLEAN ( poate avea valoarea TRUE sau FALSE )

❑ Tipul de date STRING ( sir de caractere, ex “Universitate”;


“Curs” ; “eroare” )
2. OPERATORI LOGICI

Valoare de Valoare de Operator Valoare de Valoare de Operator


adevar adevar Logic “SI” adevar adevar Logic
(AND) “SAU” (OR)
FALSE FALSE FALSE
FALSE FALSE FALSE
FALSE TRUE FALSE
FALSE TRUE TRUE
TRUE FALSE FALSE
TRUE FALSE TRUE
TRUE TRUE TRUE TRUE TRUE TRUE

Operatorul logic “SI” (AND) este acel Operatorul logic “SAU” (OR) este acel
operator care ia valoarea “TRUE” doar operator care ia valoarea “FALSE”
cand cele doua variabile au valoarea doar cand cele doua variabile au
“TRUE” Ex: Nr 5 este mai mare decat 0 valoarea “FALSE” Ex: Nr 5 este mai
SI mai mic decat 10. Valoare “TRUE” mare ca “0” SAU Nr 5 mai mare ca 10.
Valoare de adevar “TRUE”
2. OPERATORI LOGICI

A A B

Y
Y

Y= A si B Y= A sau B
3. STRUCTURI ALGORITMICE

➢ 3.1 Structura lineara – este asimilata oricarui algoritm in


ansamblul lui indiferent daca contine structuri alternative
si/sau repetitive; in orice algoritm pornim de la START si
ajungem la STOP, de aici rezulta linearitatea

➢ 3.2 Structura alternativa simpla (daca….altfel) – este acea


structura care contine o conditie (simpla sau compusa) care
este sau nu indeplinita si/sau instructiuni de urmat pe ramurile
de DA si/sau NU.
Ramura de NU (Altfel) este optionala. Daca este indeplinita
conditia, algoritm continua pe ramura DA, altfel continua pe
ramura NU (Altfel)

DA a>=b NU
SI b>0
3. STRUCTURI ALGORITMICE

3.3 Structura alternativa compusa (selectie in functie de o variabila) este acea structura
care contie mai multe ramuri, fiecare cu cate o conditie simpla care este sau nu
indeplinita si/sau instructiuni de urmat pe fiecare dintre ramuri. Ramura de NU (Altfel) este
optionala. Daca este indeplinita conditia, algoritmul continua pe ramura respectiva, altfel
contiuna pe o alta ramura unde conditia este indeplinita sau in ultima instanta pe ramura
NU (altfel) daca nici o conditie de pe una din celelalte ramuri nu a fost indeplinita

variabila

C C C C
1 2 3 n
3. STRUCTURI ALGORITMICE

3.4 Structuri repetitive sunt acele structuri in cadrul carora una sau mai multe instructiuni sunt
repetate de un anumit numar de ori sau cat timp este indeplinita o conditie (simpla sau compusa)
sau pana cand este indeplinita o conditie (simpla sau compusa)
Clasificare :
I. Din punct de vedere al numarului de pasi pe care il executa :
▪ Structuri repetitive cu numar cunoscut de pasi (ciclul “Pentru” sau “For”
▪ Structuri repetitive cu numar necunoscut de pasi (ciclul “Cat timp…Executa” si
ciclul “Repeta…pana cand”
II. Din punct de vedere al locului unde se evalueaza conditia de ciclare (repetare) :

▪ Structuri repetitive cu test initial si pas final (ciclul “Pentru” si ciclul “ Executa…Cat Timp)”
▪ Structuri repetitive cu pas initial si test final (ciclul “Repeta…Pana Cand”
3. STRUCTURI ALGORITMICE
▪ Structuri repetitive cu test initial si pas final

Initializezi “s” cu
s←0
valoarea “0” – Suma
“i” primeste valoarea 1
i←1
(contor de ciclare)

i<=3 NU
?

DA
Afisare s
s ← s+2

i ← i+1
STOP
3. STRUCTURI ALGORITMICE
▪ Structuri repetitive cu pas initial si test final
Initializezi “s” cu
s←0
valoarea “0” – Suma
“i” primeste valoarea 1
i←1
(contor de ciclare)

s ← s+2

i ← i+1

NU i<=3 DA
Afisare s
?

STOP
3. STRUCTURI ALGORITMICE

X
4. EXEMPLE DE EXERCITII REZOLVATE
4. EXEMPLE DE EXERCITII REZOLVATE
4. EXEMPLE DE EXERCITII REZOLVATE

Bulgari
de suma
4. EXEMPLE DE EXERCITII REZOLVATE
Structura repetitiva cu pas initial si test final
4. EXEMPLE DE EXERCITII REZOLVATE
4. EXEMPLE DE EXERCITII REZOLVATE
4. EXEMPLE DE EXERCITII REZOLVATE
5. TEMA
PCLP CURS 4
AGENDA :
1. ALGORITMI DE BAZA
1.1 Lucru cu cifrele unui numar intreg; operatorii DIV si MOD
1.2 Impartirea in cifre a unui numar intreg; suma cifrelor numarului
1.3 Verificarea unui numar daca este palindrom (1221;2552;343 etc)
1.4 Verificarea unui numar daca este patrat perfect
1.5 Verificarea unui numar daca este prim
1.6 Verificarea unui numar daca este perfect (egal cu suma divizorilor sai ; 6=1+2+3)
1.7 Determinarea cifrei minime/maxime dintre cifrele unui numar intreg dat “n”
2. EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
1. ALGORITMI DE BAZA

1.1 Lucru cu cifrele unui numar intreg; operatorii DIV si MOD

❑ DIV – furnizeaza catul intreg al impartirii a doua numere intregi a si b

Ex: 5 div 2 =2; 7 div 2 = 3; 4 div 2=2; 543 div 10 =54; 543 div 100=5; 543 div 1000=0

❑ MOD – furnizeaza restul impartirii a doua numere intregi a si b

Ex: 5 mod 2=1; 7 mod 3=1; 12 mod 2 =0; 567 mod 10=7; 567 mod 100=67; mod 1000=567
1. ALGORITMI DE BAZA
Limbaj pseudocod
START Ex: nr 456
1.2 Impartirea in cifre a
unui numar intreg; suma n,s intregi
cifrelor numarului Citire n
Citire n n ← 456
folosind operatorii DIV
s←0
si MOD
Cat timp n > 0 executa
s←0 S se initializeaza cu 0
s ← s+n mod 10
456 > 0 ? 0>0? n ← n div 10
45 > 0 ? n>0 NU
4>0? ? Afisare s
▪ D.I. : n
0>0?
▪ D.O. : s
DA
456 mod 10 = 6 s = 15
Afisare s
(s=6) s ← 0+6
45 mod 10 = 5 s ← s+n mod 10
(s=11) s ← 6+5
4 mod 10 = 4
(s=15) s ← 11+4 STOP
456 div 10 = 45 n ← n div 10
(n=45) n ← 45
45 div 10 = 4
(n=4) n ← 4
4 div 10 = 0 (n=0) n ← 0
1. ALGORITMI DE BAZA
1. ALGORITMI DE BAZA
1. ALGORITMI DE BAZA
1. ALGORITMI DE BAZA
1. ALGORITMI DE BAZA
2. EXEMPLE DE EXERCITII REZOLVATE
2. EXEMPLE DE EXERCITII REZOLVATE
2. EXEMPLE DE EXERCITII REZOLVATE
2. EXEMPLE DE EXERCITII REZOLVATE
2. EXEMPLE DE EXERCITII REZOLVATE
2. EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
PCLP CURS 5
AGENDA :
1. TABLOURI UNIDIMENSIONALE (VECTORI) – ALGORITMI DE BAZA
1.1 Declararea, citirea si afisarea unui vector
1.2 Determinarea minimului/maximului dintre elementele unui vector
1.3 Verificarea unui vector daca are elemente distincte
1.4 Sortarea elementelor unui vector: metoda bulelor
1.5 Cautarea unei chei k printre elementele unui vector (cautarea secventiala si cautarea binara)
1.6 Vectori ca multimi si operatii cu multimi: intersectie,reuniune,diferenta, produs cartezian
1.7 Suma/produsul elementelor unui vector
2. EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
4 div 10 = 0
4 div 10 = 0
4 div 10 = 0
PCLP CURS 6
AGENDA :
1. TABLOURI BIDIMENSIONALE (MATRICE) – ALGORITMI DE BAZA
1.1 Declararea, citirea si afisarea unei matrice
1.2 Determinarea minimului/maximului dintre elementele unei matrice
1.3 Verificarea unei matrice daca are elemente distincte
1.4 Operatii cu matrice: adunarea si inmultirea matricelor
1.5 Interschimbarea a doua linii sau coloane intr-o matrice
1.6 Schimbarea liniilor cu coloanele intr-o matrice (transpusa matricei)
1.7 Matrice patratice: diagonala principala, secundara,zone delimitate de cele diagonale
2. EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
PCLP CURS 7
AGENDA :
1. SIRURI DE CARACTERE – ALGORITMI DE BAZA
1.1 Functii des utilizate
1.2 Verificarea unui sir de caractere daca este palindrom (ex : “RADAR”)
1.3 Cautarea unui nume intr-un sir de caractere
1.4 Verificarea unei parole prin reintroducere
1.5 Inversarea a doua cuvinte intr-un sir de caractere
1.6 Criptarea simpla a unui sir de caractere cu ajutorul unei chei private
1.7 Decriptarea simpla a unui sir de caractere cand cunoasrem cheia privata
2. EXEMPLE DE EXERCITII REZOLVATE
3. TEMA
CARACTERE ASCII (acronimul pentru American Standard Code for Information Interchange
CODURI ASCII
PCLP CURS 8
PCLP CURS 9
Laboratorul 1 Generalităţi

1. Generalităţi

1.1 Tastatura

1.1.1 Tastele rapide (Hotkeys) F1…F12

1.1.2 Tastele alfanumerice:

Shift (⇑), Alt, Ctrl - (două din fiecare) Nu au Slash (/)


efect singure (se apasă simultan cu altă Backslash (\)
tastă) Tilda (~) Shift+
Tab Ampersand, ”coadă de maimuţă”,
Caps Lock = folosit la scrierea cu majuscule a rond, (@) Shift+2
Enter = lansează în execuţie o comandă Diez (#): Shift+3
Backspace = şterge caracterul din stânga Procent (%) Shift+5
cursorului Căciuliţa (^) Shift+6
Space (spaţiu) = introduce un blank And (&) Shift+7
Esc = Escape Apostrof (')
Ghilimele (") - NU două apostrofuri !
Bară verticală (|)

1.1.3 Taste speciale


• Insert = comută între modul inserare şi suprascriere
• Delete = şterge caracterul din dreptul cursorului
• Home = (acasă) mută cursorul la începutul rândului
• End = (sfârşit) mută cursorul la sfârşitul rândului curent
• Page up = deplasează conţinutul fişierului cu un ecran către începutul acestuia
• Page down (pereche)
• Ctrl + Home = mută cursorul la începutul ecranului (primul rând)
• Ctrl + End = mută cursorul la sfârşitul ecranului (ultimul rând)
• Ctrl + Page up = deplasează cursorul (şi implicit conţinutul afişat pe ecran) la
începutul fişierului
• Ctrl + Page down = deplasează cursorul la sfârşitul fişierului

1.1.4 Tastele numerice


Sunt active dacă led-ul lui Num Lock este aprins, altfel funcţionează ca Taste speciale

2
Laboratorul 1 Generalităţi

1.2 Ecranul aplicaţiei Borland C

Acesta conţine:
Bara de meniuri (sus) - prezintă mai multe meniuri (System, File - fişiere, Edit - editare,
Search) care conţin grupuri de comenzi specifice. Activarea ei se face cu tasta rapida F10 -
aşa cum se arată în bara de stare; deschiderea unui meniu se face apăsând simultan tastele
Alt şi litera evidenţiată din numele meniului.
Zona de lucru (la mijloc) - conţine una sau mai multe ferestre, din care, la un moment dat, e
activă una singură.
Elementele unei ferestre sunt:
ƒ Rama ferestrei - dublă, dacă fereastra este activă, simplă dacă este inactivă
ƒ Buton de închidere - în partea din stânga sus a ramei ([■])
ƒ Titlul ferestrei - pentru ferestrele de editare este numele fişierului deschis.
ƒ Numărul ferestrei - automat
ƒ Buton de maximizare/revenire - în partea din dreapta sus a ramei ([↑])
ƒ Bara de defilare verticală ce conţine săgeţile de deplasare la extremităţi şi butonul
care indică poziţia conţinutului ecranului în „lungul” fişierului (început/sfârşit)
ƒ Bara de defilare orizontală ce conţine săgeţile de deplasare la extremităţi şi butonul
care indică poziţia conţinutului ecranului în „latul” fişierului (stânga/dreapta)
ƒ Poziţia cursorului - indicată prin numărul liniei şi cel al coloanei - în partea din
stânga jos a ramei
ƒ Buton care indică modificarea conţinutului ferestrei după ultima salvare - în partea
din stânga jos a ramei [*]

Bara de stare (jos) - conţine comenzile disponibile la un moment dat şi combinaţiile de taste
pentru lansarea acestora. Conţinutul ei se modifică în funcţie de context (poziţia cursorului în
diferitele zone ale ecranului).

3
Laboratorul 1 Generalităţi

1.3 Principalele meniuri şi comenzi ale aplicaţiei

Acestea sunt:
1. Meniul System [≡] - conţine comenzi sistem şi pentru programe de transfer
2. Meniul File - conţine comenzi pentru gestiunea fişierelor (Deschidere, Salvare,
Tipărire, etc.)
a. New - Creează un nou fişier într-o nouă fereastră de editare
b. Open - Localizează si deschide un fişiere (creat deja)
c. Save - Salvează fişierul din fereastra de editare activă
d. Save as - Salvează fişierul din fereastra de editare activă cu un nume nou
e. Save all - Salvează toate fişierele modificate
f. Change dir - Schimbă directorul de lucru curent
g. Print - Tipăreşte conţinutul ferestrei active
h. DOS shell - iese temporar în sistemul de operare
i. Quit - Iese din aplicaţia Borland C++
3. Meniul Edit - conţine comenzi pentru operaţii de editare, anulare şi acces la
Clipboard
a. Undo - anulează ultima comandă de editare (consecutiv)
b. Redo - reface ultima comandă anulată
c. Cut - şterge textul selectat şi îl pune în Clipboard
d. Copy - copiază în Clipboard textul selectat
e. Paste - inserează conţinutul Clipboard-ului în fereastra curentă la poziţia
cursorului
f. Clear - şterge textul selectat
g. Copy example - copie în Clipboard exemplul dintr-o fereastră Help
h. Show Clipboard - arată conţinutul Clipboard-ului
4. Meniul Search - conţine comenzi pentru căutarea textului şi erorilor
a. Fiind - caută un text
b. Replace - caută un text şi îl înlocuieşte cu unul nou
c. Search again - repetă ultima comandă de căutare sau căutare şi înlocuire
d. Go to line number - mută cursorul la linia specificată
e. Previous error - mută cursorul la linia erorii anterioare
f. Next error - mută cursorul la linia erorii următoare
g. Locate function - caută la depanare o declaraţie de funcţie
5. Meniul Run - conţine comenzi pentru lansarea în execuţie a programului integral
sau pas cu pas
a. Run - lansează programului în execuţie
b. Program reset - termină sesiunea de depanare
c. Go to cursor - execută programul până la linia cursorului
d. Trace into - execută instrucţiunea următoare; pătrunde în corpul
funcţiilor
e. Step over - execută instrucţiunea următoare; “păşeşte” peste corpul
funcţiilor
f. Arguments - stabileşte parametrii liniei de comandă cu care va fi
executat programul
6. Meniul Compile - conţine comenzi pentru verificarea corectitudinii (compilarea)
programului
a. Compile - compilează fişierul din fereastra de editare activă
b. Make - Actualizează ţinta prin compilare şi legare, după caz
c. Link - Leagă fişierele ţintei fără recompilare
d. Build all - Reconstruieşte toate fişierele

4
Laboratorul 1 Generalităţi

7. Meniul Debug - conţine comenzi pentru inspectare, evaluare, stabilire de puncte


de întrerupere şi urmărire a variabilelor
a. Inspect - deschide o fereastră inspector pentru a examina valorile unei date
b. Evaluate/Modify - evaluează o variabilă sau expresie şi afişează valoarea
c. Call stack - arată funcţiile apelate de program până în punctul curent
d. Watches - adaugă, şterge sau editează variabile urmărite
e. Toggle breakpoint - inserează sau şterge un punct de oprire necondiţionată
a programului la linia curentă
f. Breakpoints - inserează puncte de oprire necondiţionată; vizualizează sau
editează aceste puncte
8. Meniul Project - conţine comenzi pentru gestiunea proiectelor: adăugare, ştergere
sau vizualizarea fişierelor proiect
9. Meniul Options - conţine comenzi pentru stabilirea opţiunilor mediului de
programare, a compilatorului şi depanatorului
10. Meniul Window - conţine comenzi pentru deschiderea, aranjarea şi afişarea listei
ferestrelor
a. Size/Move - modifică dimensiunea sau poziţia ferestrei active
b. Zoom - maximizează sau readuce fereastră activă la dimensiunea iniţială
c. Cascade - dispune ferestrele din zona de lucru suprapuse
d. Tile - dispune ferestrele din zona de lucru alăturat
e. Next - activează fereastra următoare
f. Close - închide fereastra activă
g. Close all - închide toate ferestrele
h. Message/Output/Watch/User screen - deschide una din ferestrele speciale:
de mesaje, de rezultate, de urmărire sau ecranul utilizatorului
i. List all - afişează lista tuturor ferestrelor deschise
11. Meniul Help - conţine comenzi pentru accesarea sistemului de ferestre de ajutor.
a. Contents - arată cuprinsul sistemului de ajutor
b. Index - arată index-ul sistemului de ajutor
c. Topic search - arată informaţii despre cuvântul din dreptul cursorului sau
afişează index-ul
d. Previous topic - arată din nou ultima fereastră de informaţii
e. Help on help - arată modul de utilizare a sistemului de ajutor
f. About - arată numărul versiunii programului

Observaţii:
1. Selectarea unei porţiuni de text se face astfel:
a. Se poziţionează cursorul cu ajutorul săgeţilor la un capăt al textului de selectat;
b. Ţinând tasta Shift apăsată se deplasează cursorul cu ajutorul săgeţilor
(←,→,↑,↓) către celălalt capăt al textului de selectat.
2. Pentru a scurta lungimea programelor şi deci şi durata etapei de redactare a acestora,
instrucţiunile care afişează valorile variabilelor pe ecran (cout, printf) pot fi omise,
iar valorile variabilelor pot fi urmărite în fereastra Watches din meniul Debug

1.4 Tipuri de fişiere

Executabile: EXE, COM, BAT


Neexecutabile:
• text: TXT
• documente: WRI, RTF, DOC

5
Laboratorul 1 Generalităţi

• imagini: BMP, JPG, GIF, TIF, PCX


• sunete: MP3, WAV, MIDI
• surse: C, CPP, BAS, PAS, FOR, M
• arhive: ZIP, ARJ, ACE, RAR
• imagini de disc: ISO, BIN

6
Laboratorul 2 Scheme logice şi pseudocod

2. Scheme logice şi pseudocod

Start
Start

Citeşte
Citeşte re,im
x

modul= f(a Nu
Dacă
re ⋅ re + im ⋅ im x=0

Nu
Dacă Da f(x)=0 Da Nu
Dacă
re=0
x<0
Nu
Nu Da Da
Dacă Dacă
re>0 im>=0 f(x) = 4x3 -5x2 … f(x) = ex - ln x

arg=- arg=arct(im/re arg=pi/2 arg=-pi/2


arctg(im/re) )

scrie
scrie f(x)
re,im

Stop Stop

Modulul si argumentul unui nr complex Calculul unei functii

2.1.1 Maximul a trei numere


1. citeşte a, b, c
2. dacă a>b
atunci max=a
altfel max=b
3. dacă c>max
atunci max=c
4. afişează max

2.1.2 Suma primelor n numere naturale


1. citeşte n
2. suma=0
3. cât timp i<n
i++
suma=suma+1
4. afişează suma

7
Laboratorul 2 Scheme logice şi pseudocod

Start Start
Start

Citeşte Citeşte n
Citeşte a,b,m,n
b
i=1
i=1, j=1 fact=1
Nu Dacă ` Da
a≠0,b≠ Nu Da
0 i<=n
cmmmc=0 cmmmc=a*b Da
Nu i<m
cmmdc=0 r=a%b;
a=b;b=r j<n
fact*=i

i=i+1
Nu Daca Da s = s + sin(a + 3 ⋅ i ) ⋅
r≠0
⋅ cos(b + 5 ⋅ j )
scrie
cmmmc=a r=a%b; i=i+1 fact
cmmmc a=b;b=r; j=j+1
cmmmc= cmmdc Stop

scrie s
scrie
cmmdc
cmmmc Stop

Stop
START

START
CITEŞTE a,b,c
CITEŞTE n
A Dacă a>=b F

A i<n F
max=a max=b

i++
sumă=sumă+i AFIŞEAZĂ sumă
A Dacă c>max F
STOP

max=c

AFIŞEAZĂ max

STOP

8
Laboratorul 2 Scheme logice şi pseudocod

2.2 ÎNTREBĂRI ŞI EXERCIŢII

2.2.1 Chestiuni teoretice


1. Care este deosebirea între algoritm şi program ?
2. Care sunt proprietăţile fundamentale ale algoritmilor ?
3. Care sunt modalităţile de reprezentare a algoritmilor ?

2.2.2 Chestiuni practice


1. Reprezentaţi algoritmul lui Euclid (pentru calculul celui mai mare divizor comun a 2
numere întregi) prin schema logică.
2. Proiectaţi un algoritm care să rezolve o ecuaţie de gradul I (de forma ax + b = 0), unde
a,b sunt numere reale. Discuţie după coeficienţi.
3. Proiectaţi un algoritm care să rezolve o ecuaţie de gradul II (de forma ax2 + bx + c = 0),
unde a,b,c sunt numere reale. Discuţie după coeficienţi.
4. Proiectaţi un algoritm care să testeze dacă un număr întreg dat este număr prim.
5. Proiectaţi un algoritm care să afişeze toţi divizorii unui număr întreg introdus de la
tastatură.
6. Proiectaţi un algoritm care să afişeze toţi divizorii primi ai unui număr întreg introdus de la
tastatură.
7. Proiectaţi un algoritm care calculează factorialul unui număr natural dat. (Prin definiţie
0!=1)

9
Laboratorul 3 Introducere

3. Introducere

3.1 Structura unui program în C++

Un program C obişnuit are următoarea structură (textul dintre /* şi */ reprezintă comentarii):


/*directive de preprocesare*/
#include <fisier>
/*includeri de fişiere sau biblioteci*/
/*atribuirea de nume simbolice şi definiţii de macrocomenzi*/
#define <def.constante>
/*directive de compilare condiţionată*/
/*definiţii de tipuri de date*/
/*declaraţii de variabile globale*/
/*definiţii de funcţii sau/şi descrierea unor functii*/
void main(void) /*antetul funcţiei principale main*/
{ /*începutul corpului funcţiei main*/
/*declaraţii de variabile locale*/
/*instrucţiunile funcţiei principale*/
return 0; /*valoarea returnată de funcţia main*/
} /*sfârşitul corpului funcţiei main*/
/*descrierea funcţiilor care au definiţiile mai sus*/
Precizare: compilatoarele pentru C şi C++ fac distincţie între litere mari şi mici.

Un program C++ constă în una sau mai multe funcţii din care numai una singură este funcţia
principală. Fiecare funcţie are un nume; al funcţiei principale este main. Celelalte funcţii au
nume definite de utilizator.
Def.: Un nume este o succesiune de litere şi eventual cifre, primul caracter fiind o literă.
Literele pot fi a-z, A-Z sau caracterul de subliniere (_). Numai primele 32 caractere sunt luate
în seamă.

Pentru ca un fişier text sau poată fi considerat un program sursă în limbajul C, acesta trebuie
să conţină minim antetul şi corpul funcţiei principale main, adică:
void main()
{

}
Aceste lucruri se găsesc în orice program C, indiferent de scopul acestuia.

3.2 Mesaje de eroare ale compilatorului

Mesaje eroare (alfabetic) Explicaţii


'…' is assigned a value that is never Avertisment: Valoarea calculată nu este
used folosită nicăieri în continuare
Bad file name format in include directive: Denumire greşită în directiva de preprocesare
Compound statement missing }: Caracter ”}” sau ”{” omis la o instruc compusă
Declaration syntax error: Eroare de sintaxă a declaraţiei.

10
Laboratorul 3 Introducere

Mesaje eroare (alfabetic) Explicaţii


Declaration terminated incorrectly Declaraţie terminată incorect
Expression syntax Eroare de sintaxă
For statement missing ; Caracter omis “;” la scrierea instructiunii for.
Function '…' should have a prototype: Funcţia “…” ar trebui să aibă un prototip;
pentru a putea fi folosită, ea trebuie fie definită
de utilizator, fie folosită o directivă de
preprocesare (#include <…>)
Function should return a value: Funcţia ar trebui să returneze o valoare - lipsă
void la tipul valorii returnate sau lipsă
instrucţiune return în corpul funcţiei
If statement missing ): Caracter “)” sau ”(” omis la scrierea
instrucţiunii “if”.
Illegal structure operation: Structură greşită a instrucţiunii (scriere/citire) -
la >> sau <<.
Misplaced else: Ramura “else” din instrucţiunea “if” este
poziţionată greşit.
Statement missing ; Caracter “;”omis (la instructiunea precedentă)
Undefined symbol '…' Simbol '…' (variabilă sau funcţie) nedefinit
Unexpected “…” Simbol neaşteptat - paranteză-acoladă în plus.
While statement missing ) Caracter “)”sau ”(” omis la scrierea instrucţiunii
while.

Pentru a obţine mai multe informaţii despre o anumita eroare, atunci când eroarea este
selectată în fereastra cu mesaje (Message), se apasă tasta F1.

3.3 Elementele limbajului C++

3.3.1 Caractere
La scrierea programelor C++ se foloseşte setul de caractere al codului ASCII (American
Standard Code for Information Interchange). Caracterele din acest set se codifică prin întregi
din intervalul [0, 255]. Un astfel de întreg poate fi păstrat în binar pe un octet (8 biţi)
Mulţimea caracterelor poate fi împărţită în trei grupe:
• caractere tipăribile
• caractere grafice (semitipăribile)
• caractere netipăribile
Caracterele tipăribile sunt cele ce pot fi scrise cu tastatura. Ele au codul ASCII între 32-127 şi
pot fi: litere mari şi mici, cifre, semne de punctuaţie, semnele operaţiilor aritmetice sau alte
caractere speciale. Atunci când scriem un program în C++ utilizăm de regulă aceste
caractere (32 - codul tastei spaţiu, 65-90 - literele mari, 87-122 - literele mici, 48-57 - cifrele)
Caracterele grafice(semitipăribile) nu au corespondent pe taste, ele se scriu numai după
regula ALT + <codul ASCII>. Nu se folosesc în scrierea elementelor de limbaj
Caracterele netipăribile nu se pot scrie cu tastele, ele reprezintă coduri ale unor acţiuni
speciale (7 - codul unui sunet emis de difuzor, 8 - ştergerea unui caracter oarecare la stânga,
13 - trecerea la un rând nou, 10 - trecerea la începutul rândului curent, 9 - tasta TAB)

11
Laboratorul 3 Introducere

3.3.2 Tipuri de date în limbajul C++


Datele care intervin în programe sunt de mai multe tipuri. În acest laborator vom prezenta
tipurile simple iar tipurile compuse vor fi prezentate în alte laboratoare. Tabelul de mai jos va
prezenta tipurile de bază:
Cuvânt Lungime in Format de reprezentare internă
cheie biţi
int 16 Întreg binar reprezentat prin complement faţă de 2 pe 2 octeţi,
cuprins în intervalul [-32768, 32767]
char 8 Caracter reprezentat prin codul ASCII, cuprins între 0 şi 255
float 32 Număr real reprezentat în virgulă flotantă în simplă precizie,
cuprins între [3.4⋅10-38, 3.4⋅1038]
double 64 Număr real reprezentat în virgulă flotantă în dublă precizie,
cuprins între [1.7⋅10-308, 1.7⋅10308]
short 16 Idem int
long 32 Întreg binar reprezentat prin complement faţă de 2 pe 4 octeţi,
cuprins în intervalul [-231, 231)
unsigned 16 Întreg binar fără semn reprezentat prin complement faţă de 2 pe 2
octeţi, cuprins în intervalul [0, 65535]
unsigned 32 Întreg binar reprezentat prin complement faţă de 2 pe 4 octeţi,
long cuprins în intervalul [0,232)

3.3.3 Constante
Sunt caracterizate prin tip şi valoare. Atât tipul cât şi valoarea se definesc prin caracterele
care o compun
REPREZENTAREA CONSTANTELOR ÎN C / C++
Tip dată Format de Mod de reprezentare Exemple
reprezentare
zecimal [- / +] <cifra de la 1 la 9> [<lista cifre de la 0 125
(în baza 10) la 9>] -11
întreg octal [- / +] 0 <cifra de la 1 la 7> [<lista cifre 0127
*) (în baza 8) de la 0 la 7>] -022
hexazecimal [- / +] 0 {x / X} <cifra 1-9 sau litera a-f 0xa12f
(în baza 16) sau A-F> [<lista cifre 0-7 sau litere a-f -0Xad105
sau A-F>]
în virgulă fixă [- / +] <partrea întreaga> . <partea 123
real zecimala> 123.7
Aceasta este scrierea unui număr raţional în .25
baza zece, unde virgula zecimală este
înlocuită de punctul zecimal. Partea
zecimală poate fi vidă
(flotant) în virgulă [- / +] <partrea intreaga> . <partea 78E4
mobilă zecimala> {e sau E} [- / +] <nr. intreg .1e-3
zecimal> 1234.567e-4
Aceasta reprezintă mantisa (ceea ce
este înainte de E) înmulţită cu 10 la
puterea dată de exponent (ceea ce este
după E)
între ‘<caracter>’ ‘a’ ‘A’
apostroafe
‘\<codul ASCII>‘ ‘\65’ ‘\7’
‘\42’ ‘\140’
caracter cu secvenţe ‘\<caracter special>‘ \t Tab

12
Laboratorul 3 Introducere

Tip dată Format de Mod de reprezentare Exemple


reprezentare
escape \n Nou rând
\a Bell (sunet)
\b Backspace
\r Retur de car
(poziţ cursorul in
rândul curent col 1)
\v Tabulator
vertical
\\ Backslash
\’ Apostrof
şir de între ghilimele “<sir>” “Acesta este un sir de
carac caractere”
cu secvenţe “sir caractere şi secv.escape” “Alte \tsecvente
escape \tescape \nintr-un sir”

Observaţie:
*) Ceea ce am scris anterior era valabil pentru constantele întregi de până la 16 biţi.
Constantele de 32 biţi sunt de tip long şi pentru a le nota le postfixăm una din: l sau L.
Pentru a specifica o constantă ca fiind de tip unsigned (fără semn) o postfixăm una din: u sau
U. Dacă o constantă este long şi unsigned în acelaşi timp, o postfixăm cu una din:
ul, lu, UL, LU
Exemple: 123, 0123, 40000, 04000, 0123456,
123L, 0123l, 0x123, 0xa1b2c3, 0XABCFL

13
Laboratorul 4 Intrări/ieşiri în C/C++

4. Intrări/ieşiri în C/C++
Cele mai simple instrucţiuni care pot fi utilizate în acest scop sunt cin şi cout. Ele se găsesc
în header-ul iostream.h (ce conţine funcţii pentru fluxuri de intrare-ieşire a datelor: in-out
stream) deci pentru a le utiliza trebuie să declarăm în program:
#include <iostream.h>
Instrucţiunea din C++ care scrie (pe ecran) variabile şi/sau expresii este:
cout <<expr.1[<<var1<<expr.2 [...]]
unde var.1, var.2 - reprezintă nume de variabile iar expr.1, expr.2 - reprezintă expresii.

Ex.: Pentru a afişa pe ecran pe o linie nouă, în cadrul unui mesaj, valorile a două variabile a
şi b folosim instrucţiunea:
cout<<"\na="<<a<<"\tb="<<b;
Instrucţiunea are următorul efect:
1. se trece pe o linie nouă (\n)
2. se afişează textul a=
3. se afişează valoarea variabilei a
4. se lasă un spaţiu (tab) (\t)
5. se afişează textul b=
6. se afişează valoarea variabilei b
Dacă a=2 şi b=5 atunci rezultatul instrucţiunii este:
a=2 b=5

Instrucţiunea din C++ care citeşte (de la tastatură) una sau mai multe variabile este:
cin >>var.1[>>var.2 [...]]
Ex.: Pentru a citi de la tastatură valorile a două variabile a şi b folosim instrucţiunea:
cin>>a>>b;
Alte instrucţiuni, mai puternice (dar cu o sintaxă mai complexă sunt) printf şi scanf din
biblioteca stdio.h (ce conţine funcţii standard de intrare-ieşire: standard input-output).
Instrucţiunea scanf are următoarea sintaxă:

scanf(sir_car_ctrl,adr_var.1[,adr_var.2 [...]])
unde:
sir_car_ctrl - Şir de caractere de control ce indică tipul variabileleor ce se vor citi:
%d - variabilă de tip decimal (întreg);
%f - variabilă de tip float (real);
%c - variabilă de tip caracter;
%s - variabilă de tip sir de caractere;
adr_var.1 - adresa variabilei 1
Obs: Numărul caracterelor de control trebuie să coincidă cu cel al variabilelor care se vor citi.
Ex. Pentru a se citi de la tastatură variabilele denumite: car (de tip caracter - char), intrg (de
tip întreg - int), re (de tip real - float) şi sir (de tip şir de caractere) sintaxa instrucţiunii este:
scanf("%c%d%f%s",&car,&intrg,&re,sir);
Instrucţiunea printf are următoarea sintaxă:
printf(sir_car_ctrl,var.1[,var.2 [...]])
unde:
sir_car_ctrl - Şir de caractere de control reprezentat de o succesiune de simboluri
“%” urmate de caractere si/sau cifre, ce indică tipul şi eventual formatul numeric al
variabilelor ce se vor scrie. Caracterele de formatare au următoarea semnificaţie:

14
Laboratorul 4 Intrări/ieşiri în C/C++

c - variabilă de tip caracter; o - în octal


d - variabilă de tip decimal (întreg); s - variabilă de tip şir de caractere;
e - în format ştiinţific x - în hexazecimal
f - variabilă de tip float (real); 0 - cu zerouri nesemnificative
g - cel mai scurt dintre f şi e - - aliniere la stânga
Formatul numeric se indică prin numărul total şi numărul de zecimale pentru cifrele
variabilelor numerice, separate prin “.”.
Obs: Numărul caracterelor de control trebuie să coincidă cu cel al variabilelor care se vor
scrie.
Ex. Pentru a se afişa pe ecran variabilele denumite: car (de tip caracter - char), intrg (de tip
întreg - int), re (de tip real - float) - pe şase spaţii dintre care trei zecimale - şi sir (de tip şir
de caractere) sintaxa instrucţiunii este:
printf("%c %d %6.3f %s",car,intrg,re,sir);
Sintaxa lor detaliată şi completă poate fi obţinută din Help-ul aplicaţiei BC.

4.1 Exemple

4.1.1 Exemplu
#include <iostream.h>
void main(void)
{ cout<<"ACESTA ESTE PRIMUL PROGRAM\n"; }

4.1.2 Exemplu
#include <iostream.h>
void main() //Citeste un intreg de 4 cifre apoi rescrie cifrele respective
precedate de câte un spatiu
{ int cif1, cif2, cif3, cif4;
cin>>cif1>>cif2>>cif3>>cif4;
cout<<cif1<<‘ ‘<<cif2<<‘ ‘<<cif3<<‘ ‘<<cif4;
}

4.1.3 Exemplu
#include <iostream.h>
void main() //Citeste o data calendaristica sub forma zzllaaaa (ziua-2
cifre, luna-2 cifre, anul-4 cifre) si o rescrie in forma aaaallzz
{ int ziua, luna, anul;
cin>>ziua>>luna>>anul;
cout<<anul<<‘/‘<<luna<<‘/‘<<ziua;
}

4.1.4 Exemplu - sizeof


//sizeof.cpp
#include <iostream.h>
#include <values.h>
#define PI 3.14359

void main ()
{
cout<<"tipul int memorat pe: "<<sizeof(int)<< " octeti\n";
cout<<"tipul int memorat pe: "<<sizeof(23)<<" octeti\n";
//23-const.zecimala int

15
Laboratorul 4 Intrări/ieşiri în C/C++

cout<<"int maxim="<<MAXINT<<'\n';
//const simbolice MAXINT,MAXLONG, ETC. -definite in<values.
cout<<"Const. octala 077 are val decimala:"<<077<<'\n';
cout<<"Const. hexagesimala d3 are val decimala :"<<0xd3<<'\n';
cout<<"Tipul unsigned int memorat pe: "<<sizeof(unsigned int)<<" octeti\n";
cout<<"Tipul unsigned int memorat pe: "<<sizeof(23U)<<" octeti\n";
cout<<"Tipul unsigned int memorat pe: "<<sizeof(23u)<<" octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(long int)<<" octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23L)<<" octeti\n";
cout<<"Tipul long int memorat pe: "<<sizeof(23l)<<" octeti\n";
//23 sau 23l-const. decimala long int
cout<<"Long int maxim="<<MAXLONG<<'\n';
cout<<"Tipul unsigned long memorat pe: "<<sizeof(unsigned long int)<<" octeti\n";
cout<<"Tipul unsigned long memorat pe: "<<sizeof(23UL)<<" octeti\n";
cout<<"Tipul unsigned long memorat pe: "<<sizeof(23Ul)<<" octeti\n";
//23UL sau 23ul-const. decimala unsigned long int
cout<<"Tipul unsigned long memorat pe: "<<sizeof(long long int)<<" octeti\n";long
long int d;
cout<<"Tipul unsigned long memorat pe: "<<sizeof(d)<<" octeti\n";
cout<<"Tipul short int memorat pe: "<<sizeof(short int)<<" octeti\n";
cout<<"Short int maxim="<<MAXSHORT<<'\n';
cout<<"Tipul float memorat pe: "<<sizeof(float)<<" octeti\n";
cout<<"Tipul float memorat pe: "<<sizeof(23.7f)<<" octeti\n";
//23.7f-const. decimala float
cout<<"Float maxim="<<MAXFLOAT<<'\n';
cout<<"Float minim="<<MINFLOAT<<'\n';
cout<<"Tipul double memorat pe: "<<sizeof(double)<<" octeti\n";
cout<<"Tipul double memorat pe: "<<sizeof (23.7)<<" octeti\n";
//23.7-const. decimala double
cout<<"Const. decim. doubla in notatie stiintifica: "<<23.7e-5<<'\n';
cout<<"Const. PI este:"<<PI<<'\n';
cout<<"Constanta PI este memorata pe: "<<sizeof(PI)<<"octeti\n";
cout<<"Double maxim="<<MAXDOUBLE<<'\n'<<"Double minim ="<<MINDOUBLE<<'\n';
cout<<"Tipul long double memorat pe: "<<sizeof(long double)<<" octeti\n";
cout<<"Tipul long double memorat pe: "<<sizeof(23.7L)<<" octeti\n";
//23.7L-const. decimala long double
cout<<"Cifra A din HEXA are val.: "<<0xA<<"\n";
cout<<"Cifra B din HEXA are val.: "<<0xB<<"\n";
cout<<"Cifra C din HEXA are val.: "<<0xC<<"\n";
cout<<"Cifra D din HEXA are val.: "<<0xD<<"\n";
cout<<"Cifra E din HEXA are val.: "<<0xE<<"\n";
cout<<"Cifra F din HEXA are val.: "<<0xF<<"\n";
cout<<"Val. const. hexa 0x7acle este: "<<0x7ac1e<<'\n';
cout<<"Val. const. octale 171 este: "<<0171<<'\n';
cout<<"O const. octala se memoreaza pe "<<sizeof(011)<<" octeti\n";
cout<<"O const.oct.long. se mem pe "<<sizeof(011L)<<" octeti\n";
}

4.1.5 Exemplu
#include<iostream.h>
#include<values.h>
#include<stdio.h>
#include<conio.h>

void main()
{
int a=8,b,c=8,g=9;
clrscr();
cout<<"nr.maxim este: "<<MAXLONG<<'\n';
cout<<"Un char este memorat pe "<<sizeof('m')<<" octeti\n";
cout<<"sirul jhgkk este memorat pe "<<sizeof("jhgkk")<<" octeti\n";
cout<<"sirul j\thgkk este memorat pe "<<sizeof("j\thgkk")<<" octeti\n";

16
Laboratorul 4 Intrări/ieşiri în C/C++

cout<<"UN nr int este memorat pe "<<sizeof(a)<<"octeti\n";


cout<<"valoarea 12000*3L este "<<12000*3L<<'\n';
cout<<"valoarea cifrei B din hexa in baza 10 este "<<0xB<<"\n";
cout<<"valoarea B+C din hexa in baza 10 este "<<0xB+0xc<<"\n";
cout<<"2<9:"<<(2<9)<<'\n';
cout<<"c="<<c<<" si g="<<g<<'\n';
cout<<"c==g rezulta "<<(c==g)<<'\n';cout<<"c="<<c;cout<<" g="<<g<<'\n';
cout<<"c=g da rezultatul "<<(c=g)<<'\n';cout<<"c="<<c;cout<<" g="<<g<<'\n';
cout<<"c="<<(c=9);b=++c;cout<<".Pentru b=++c se obtine b="<<b<<" si
c="<<c<<'\n';
getch();
}

4.1.6 Exemplu - intrări-ieşiri standard


//Intrari/iesiri standard //in octal
#include<conio.h> printf("\ni in octal=%o",i);
#include<stdio.h> //in hexa
printf("\ni in hexa=%x",i);
void main() //float
{ printf("\nf=%f",f);
char c;int i;float f;char sir[10]; //cu lungime si precizie impusa
clrscr(); printf("\nf=%10.2f",f);
printf("Introduceti un //stiintific
char/intreg/float/sir: \n"); printf("\nf=%e",f);
scanf("%c%d%f%s",&c,&i,&f,sir); //stiintific cu precizie data
//caracter si cod caracter printf("\nf=%.3e",f);
printf("\nc=%c cod=%d",c,c); //c m scurt dintre f si e
//intreg printf("\nf=%g",f);
printf("\ni=%d",i); //sir cu lungime fixa
//cu lungime de cimp printf("\nsir=%4.6s",sir);
printf("\ni=%6d",i); getch();
//aliniat la stinga }
printf("\ni=%-6d;i=%d",i,i);
//cu zerouri nesemnificative
printf("\ni=%06d",i);

17
Laboratorul 5 Operatori şi expresii

5. Operatori şi expresii

5.1 Instrucţiunea de atribuire

Este instrucţiunea prin care unei variabile i se atribuie o expresie. Simbolul folosit este
semnul „=”.
În tabelul de mai jos sunt prezentate principalele variante ale instrucţiunii de atribuire
operaţia sintaxa exemple observaţii
Atrib. simplă <variabilă> = <expresie>; x=tan(pi()/3)
;
Atribuirea <variabilă> <op> = x+=y; Este echivalentă cu:
combinată cu <expresie>; i-=2; <variabilă> = <variabilă> op
un operator a*=ln(a); <expresie>;
alfa /=n;

5.2 Operatori aritmetici, relaţionali şi logici, şi pe biţi

5.2.1 Operatori aritmetici unari: -, ++ , --


“++” - Incrementare - Măreşte valoarea variabilei cu 1.
“--“ - Decrementare - Micşorează valoarea variabilei cu 1
Pot fi în formă prefixată (Ex. ++a) - prioritate mare, sau postfixată (Ex. b++) - prioritate mică.

5.2.2 Operatori aritmetici binari: +, -, *, /, % (modulo)

5.2.3 Operatori aritmetici binari compuşi (cu atribuire): +=, -=, *=, /=, %=
Semnif: expr1 op = expr2 ⇔ expr1 = expr1 op expr2.
Ex. a+=2 ⇔ a=a+2

5.2.4 Operatori relaţionali binari: >, >=, <, <=, ==, != (diferit)

5.2.5 Operatori logici pe cuvânt: && (ŞI), || (SAU), ! (NOT)


Ordinea descrescătoare a prioritaţii: !, >, >=, <, <=, &&, ||
a b a&&b a||b aXORb !a
0 0 0 0 0 1
0 1 0 1 1 1
1 0 0 1 1 0
1 1 1 1 0 0
Pentru aXORb nu exista operator dar se poate folosi (a||b)&&!(a&&b)

18
Laboratorul 5 Operatori şi expresii

5.2.6 Operatori logici pe bit: ~ (NOT), & (ŞI), | (SAU), ^ (XOR), <<, >> (deplasare biţi
stânga/dreapta)

5.2.7 Operatorul condiţional „ ? :”


Este un operator ternar (necesită 3 operanzi), utilizat în construcţii de forma:
expresie1 ?expresie2:expresie3
Se evaluează expresia1. Dacă aceasta are o valoare diferită de zero, atunci tipul şi valoarea
întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei2. Altfel (dacă expresie1 are
valoarea zero), tipul şi valoarea întregii expresii vor fi aceleaşi cu tipul şi valoarea expresiei3.
Deci operatorul condiţional este folosit pentru a atribui întregii expresii tipul şi valoarea
expresiei2 sau a expresiei3, în funcţie de o anumită condiţie. Acest lucru este echivalent cu:
Dacă expresie1 diferită de zero
Atunci evaluează expresie2
Altfel evaluează expresie3

5.2.8 Prioritatea operatorilor


Tabelul 5.1 prezintă ierarhia tuturor operatorilor (grupaţi pe categorii) folosiţi în limbajul C cu
priorităţile lor şi regulile de asociativitate. Operatorii dintr-o categorie au aceeaşi prioritate.
Reţineţi că toţi operatorii, cu excepţia operatorilor unari, a acelor combinaţi cu atribuire şi a
operatorului ?, se asociază de la stânga la dreapta. Operatorii unari (*, &, -) şi operatorul ? se
asociază de la dreapta la stânga.
Tabelul 5.1 Prioritatea operatorilor
Clasă de
Nr. Operatori Asociativitate
operatori
1. Primari () [] . -> :: de la stânga la dreapta
! (NOT pe cuvânt) ~ (NOT pe bit) ++
2. Unari de la stânga la dreapta
-- sizeof (tip)
- (unar) *(deferenţiere) &
de la dreapta la stânga
(referenţiere)
3. Multiplicativi * / % de la stânga la dreapta
4. Aditivi + - de la stânga la dreapta
5. Deplasare pe bit << >> de la stânga la dreapta
6. Relaţionali < <= > >= de la stânga la dreapta
7. De egalitate == != de la stânga la dreapta
8. & (ŞI logic pe bit) de la stânga la dreapta
9. ^ (XOR pe bit) de la stânga la dreapta
10. | (SAU logic pe bit) de la stânga la dreapta
11. && (ŞI logic pe cuvânt) de la stânga la dreapta
12. || (SAU logic pe cuvânt) de la stânga la dreapta
13. Condiţional ?: de la dreapta la stânga
= += -= *= %=
14. De atribuire &= ^= |= <<= >>= de la dreapta la stânga
15. Virgulă , de la stânga la dreapta

19
Laboratorul 5 Operatori şi expresii

5.3 Conversia între bazele de numeraţie

5.3.1 Conversia zecimal-binar Operaţie Cât Rest


Aceasta se realizează prin împărţiri succesive la doi până când câtul 24:2 12 0
devine zero; şirul resturilor în ordine inversă formează numărul în 12:2 6 0
baza doi. 6:2 3 0
Ex.: 2410 = 110002. Acest lucru s-a obţinut conform operaţiilor din 3:2 1 1
tabelul alăturat. 1:2 0 1

5.3.2 Conversia binar-zecimal


Numărul în baza 10 este suma produselor dintre cifrele numărului în baza doi şi doi ridicat la
o putere egală cu poziţia cifrei în număr; numerotarea începe din dreapta cu poziţia zero.
Ex.: 110102 = 1·24 + 1·23 + 0·22 + 1·21 + 0·20 = 2610

5.3.3 Conversia hexazecimal-binar


Se scrie fiecare simbol al numărului hexazecimal sub formă binară.
Ex.: DFH = 110111112 deoarece DH = 1310 = 11012, iar FH = 1510 = 11112

5.3.4 Conversia binar-hexazecimal


Numărul binar se împarte în grupuri de câte patru cifre, începând de la dreapta la stânga, iar
apoi fiecare grup de cifre este scris în baza şaisprezece.
Ex.: 1101010 = 01101010 = 6AH deoarece 0110 = 610 = 6H, iar 1010 = 1010 = AH

//Aria triunghiului- formula lui Heron


#include <iostream.h>
5.4 Exemple #include <math.h>

main()
{
5.4.1 Operatori aritmetici unsigned int a,b;
#include <iostream.h> float c,S,p;
void main(void) //Citeste cantitatea
cout<<"\nIntroduceti prima latura a
si pretul apoi calculeaza valoarea ";cin>> a;
expresiei cout<<"\nIntroduceti a doua latura b
{ ";cin>> b;
float pret, cantitate; /*cout<<"\nIntroduceti a treia latura
cout<<“Dati cantitatea si pretul: c ";cin>> c;*/
”; c=hypot(a,b);
cin>>cantitate>>pret; p=(a+b+c)/2;
cout<<“Valoarea=”<<cantitate*pret; S=sqrt(p*(p-a)*(p-b)*(p-c));
} cout<<"\nIpotenuza este "<<c;
cout<<"\nSemiperimetrul este "<<p;
cout<<"\nAria este "<<S;
//Program cu operatii aritmetice }
#include<iostream.h>
void main(void)
{ int a,b; float c,d,e;
cout<<“Dati doua numere intregi:”; 5.4.2 Incrementari/decrementari/atribuiri
cin>>a>>b;
Care sunt valorile variabilelor a,b şi dupa
cout<<“Suma=“<<a+b<<“\nProdusul=”<<a
*b<<“\nDiferenta=”<<a-
execuţia fiecăreia dintre următoarele
b<<“\nCâtul=”<<a/b; instrucţiuni:
}

20
Laboratorul 5 Operatori şi expresii

Valori initiale: a= 0; b= 0; c= 0 cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t


a=(++b)+(++c) c= "<<c;
cout<<"\nAsta-i tot !";
a=b+++c++ getch();
a=(++b)+c++
a=b--+--c }
a=(++c)+c
a+=2
b-=3 5.4.3 Operatori relaţionali şi logici
c*=4 //Operatori relationali si logici
a/=2 #include<conio.h>
#include<stdio.h>
// Incrementari/decrementari/atribuiri
#include<conio.h> void main ()
#include<iostream.h> {
int x1=1,x2=20,x,cond;
void main() printf("\nx= "); scanf("%d",&x);
{ //verifica daca un nr indepl o
int a=0,b=0,c=0; conditie
clrscr(); cond=x1<x&&x<x2||(x%2);
cout<<"\nValori initiale:\n\ta= printf("\nconditia
"<<a<<";\t b= "<<b<<";\t c= "<<c; x1<x&&x<x2||(x%%2) este %d",cond);
a=(++b)+(++c); cond=10>5&&!(10<9)||3<=4;
cout<<"\na=(++b)+(++c) duce la ..."; printf("\nconditia
getch(); 10>5&&!(10<9)||3<=4 este %d",cond);
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t
c= "<<c; printf("\n!0&&0||0 este %d,
a=b+++c++; dar",!0&&0||0);
cout<<"\na=b+++c++ duce la ..."; printf("\n!(0&&0)||0 este
getch(); %d",!(0&&0)||0);
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t getch();
c= "<<c; }
a=(++b)+c++;
cout<<"\na=(++b)+c++ duce la ...";
getch(); //Operatori logici
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t
#include <iostream.h>
c= "<<c;
a=b--+--c; void main()
cout<<"\na=b--+--c duce la ..."; { int a=0, b=10, c=100, d=200;
getch(); int rezult; rezult=a&&b;
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t cout<<”a&&b=”<<rezult<<’\n’;
c= "<<c; //Afisare a&&b=0
a=(++c)+c; rezult=a||b;
cout<<"\na=(++c)+c duce la ..."; cout<<”a||b=”<<rezult<<’\n’;
getch(); //Afisare a||b=1 (sau valoare
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t nenula)
c= "<<c;
rezult=!a;cout<<”!a=”<<rezult<<’\n’;
a+=2;
cout<<"\na+=2 duce la ..."; getch(); //Afisare !a=1 (sau valoare nenula)
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t rezult=!b;
c= "<<c; cout<<”!b=”<<rezult<<’\n’;
b-=3; //Afisare !b=0
cout<<"\nb-=3 duce la ..."; getch(); rezult=(a>b) || (b>c);cout<<”(a>b)
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t || (b>c)=”<<rezult<<’\n’;
c= "<<c; //Afisare (a>b) || (b>c) =1(sau
c*=4; valoare nenula)
cout<<"\nc*=4 duce la ..."; getch(); rezult=!(c<d);cout<<”!(c<d)=”<<rezul
cout<<"\n\ta= "<<a<<";\t b= "<<b<<";\t
t<<’\n’;
c= "<<c;
a/=2; //Afisare !(c>d)=0
cout<<"\na/=2 duce la ..."; getch(); rezult=(a-b)&&1;cout<<”(a-
b)&&1=”<<rezult<<’\n’;

21
Laboratorul 5 Operatori şi expresii

//Afisare (a-b)&&1 =1(sau valoare 5.4.4 Operatori pe biţi


nenula) Programul afişează rezultatul următoarelor
rezult=d||b&&a;cout<<”d||b&&a=”<<rez expresii:
ult<<’\n’;
//Afisare d||b&&a =1
} Val iniţială x= 7, în binary 00000111
x=x<<1 dă x= 14, în binar 00001110
5.4.3.1 An bisect x=x<<3 dă x= 112, în binar 01110000
x=x<<2 dă x= 192, în binar 11000000
Să se scrie un program care citeşte un întreg x=x>>1 dă x= 96, în binar 01100000
din intervalul [1600, 4900], ce reprezintă un x=x>>2 dă x= 24, în binar 00011000
an calendaristic, afişează 1 dacă anul este x=~x dă x= 231, în binar 11100111
bisect şi 0 în caz contrar sau dacă anul nu
aparţine intervalului indicat mai sus. SI
Un an, din calendarul gregorian, este bisect 7, în binar 00000111
dacă este multiplu de patru şi nu este 14, în binar 00001110
multiplu de 100 sau dacă este multiplu de x=(7&14) dă x= 6, în binar 00000110
400. Această regulă este valabilă pentru anii
care nu sunt anteriori anului 1600. SAU
Dacă notăm cu an anul calendaristic, atunci 128, în binar 10000000
el este bisect dacă de exemplu: 3, în binar 00000011
an%4==0 (an este multiplu de 4) x=(128|3) dă x= 131, în binar 10000011
an%100!=0 (an nu este multiplu de 100).
Deci anul este bisect dacă expresia XOR
(1) an%4==0 && an%100!=0 este adevărată. 127, în binar 01111111
De asemenea, anul este bisect şi în cazul în 120, în binar 01111000
care expresia x=(127^120) dă x= 7, în binar 00000111
(2) an%40()==0 (an este multiplu de 400)
este adevărată. //Operatii pe biti
Deci anul este bisect dacă este adevărată #include<conio.h>
expresia (1) sau (2), adică dacă este #include<iostream.h>
adevărată expresia:
an%4==0 && an%100! =0 || an%400==0 dectobin(int x)
{
int i=8,bin,c,r[8]={0,0,0,0,0,0,0,0};
//PROGRAMUL BIII12 do
#include <stdio.h> {
void main ( ) r[i-1]=x%2; x/=2; i--;
/* citeste un intreg care reprezinta }
un an calendaristic din while(x);
intervalul [1600,4900] si afiseaza 1 for(i=0;i<8;i++)
daca anul este bisect cout<<r[i];
}
si zero daca nu este sau nu apartine
intervalului indicat */ void main()
{ {
int an, bisect; unsigned char x=7;
printf("Anul: "); clrscr();
scanf("%d", &an); cout<<"\n\t\tx= "<<int(x)<<"\tin binar
bisect=an>=1600 && an<=4900 && ";dectobin(x);
(an%4==0 && an%100!=0 || an%400==0); x=x<<1; cout<<"\nx=x<<1 dă\tx=
printf("an=%d\t%d\n",an,bisect); "<<int(x)<<"\tin binar ";dectobin(x);
} x=x<<3; cout<<"\nx=x<<3 dă\tx=
"<<int(x)<<"\tin binar ";dectobin(x);
x=x<<2; cout<<"\nx=x<<2 dă\tx=
"<<int(x)<<"\tin binar ";dectobin(x);
x=x>>1; cout<<"\nx=x>>1 dă\tx=
"<<int(x)<<"\tin binar ";dectobin(x);

22
Laboratorul 5 Operatori şi expresii

x=x>>2; cout<<"\nx=x>>2 dă\tx= void main( ) /* citeste un număr si


"<<int(x)<<"\tin binar ";dectobin(x); afisează valoarea lui absoluta */
x=~x; cout<<"\nx=~x dă\tx= {
"<<int(x)<<"\tin binar ";dectobin(x); double a;
//SI scanf("%lf", &a );
cout<<"\n\nSI\t\t7\tin binar printf("a=%g\tabs(a)=%g\n",a, a < 0 ?
";dectobin(7); -a : a );
cout<<"\n\t\t 14\tin binar }
";dectobin(14);
x=7&14; cout<<"\nx=(7&14) dă\tx=
"<<int(x)<<"\tin binar ";dectobin(x);
//SAU 5.4.6 Operatorul cast
cout<<"\n\nSAU\t\t128\tin binar Să se scrie un program care citeşte un întreg
";dectobin(128); şi afişează rădăcina pătrată din numărul
cout<<"\n\t\t 3\tin binar
";dectobin(3);
respectiv.
x=128|3; cout<<"\nx=(128|3) dă\tx= //PROGRAMUL BIII17
"<<int(x)<<"\tin binar ";dectobin(x); #include <stdio.h>
//SAU exclusiv #include <math.h>
cout<<"\n\nXOR\t\t127\tin binar void main( )
";dectobin(127); {/* - citeste pe n; - calculează si
cout<<"\n\t\t120\tin binar afisează rădăcina pătrata din n *
";dectobin(120); long n;
x=127^120; cout<<"\nx=(127^120) dă\tx= scanf("%ld", &n);
"<<int(x)<<"\tin binar ";dectobin(x);
getch();
printf("n=%ld\tsqrt(n)=%g\n",n,
} sqrt((double)n));
}
5.4.5 Operatorul ternar Observaţie:
//Op ternar ?
în acest program, pentru extragerea rădăcinii
#include<conio.h> pătrate s-a utilizat funcţia sqrt. Ea are
#include<iostream.h> prototipul: double sqrt(double);
Acest prototip este definit în fişierul math.h.
void main()
{ Să se scrie un program care citeşte pe n de
int x,y; tip întreg şi afişează valoarea expresiei
clrscr(); n/(n+1) cu 15 zecimale.
cout<<"Introd x: "; cin>>x;
//PROGRAMUL BIII18
y=(x>5) ?1:0;
#include <stdio.h>
cout<<"y= "<<y;
void main( ) /* - citeste pe n;
getch();
- calculează si afisează pe n/(n+1)
cu 15 zecimale */
}
{
Să se scrie un program care citeşte două long n;
numere şi afişează maximul dintre ele. scanf("%ld", &n);
//PROGRAMUL BIII19 printf("n=%ld\tn/(n+1)=%.15g\n", n,
#include <stdio.h> (double)n/(n+1));
void main () /* citeste doua numere si }
afisează maximul dintre ele */
{ Observaţie:
double a,b; Expresia n/(n+1) realizează împărţirea
scanf("%lf %lf",&a,&b); întreagă a lui n la n + 1. Pentru a obţine câtul
printf("a=%g\tb=%g\tmax(a,b)=%g\n", împărţirii cu 15 zecimale este necesar să se
a,b, a > b ? a : b);
}
efectueze împărţirea neîntreagă. În acest
scop s-a convertit operandul n spre lipul
Să se scrie un program care citeşte un double. În felul acesta, conform regulei
număr şi afişează valoarea lui absolută. conversiilor implicite, se converteşte spre
//PROGRAMUL BIII20
double şi cel de al doilea operand şi apoi se
#include <stdio.h> face împărţirea celor doi operanzi flotanţi.

23
Laboratorul 5 Operatori şi expresii

5.4.7 Operatorul virgulă }


Să se scrie un program care citeşte doi Observaţie:
întregi şi afişează maximul dintre valorile lor Expresia:
absolute. (c = a<0 ?-a), (d = b<0 ?-b:b), (c>d) se
//PROGRAMUL BIII23 compune din trei expresii care se evaluează
#include <stdio.h> de la stânga la dreapta.
void main( ) /* citeste doi intregi Prima atribuie lui c valoarea absolută a lui a,
si afisează maximul dintre valorile a doua atribuie lui d valoarea absolută a lui
!or absolute */ b, iar a treia testează relaţia c>d. Valoarea
{
întregii expresii coincide cu 1 dacă c>d şi cu
int a,b,c,d;
scanf("%d%d", &a,&b); zero în caz contrar.
printf("a=%d\tb=%d\tmax(abs(a),abs(b
))=%d\n", a, b, ((c=a<0 ?-a:a),
(d=b<0 ? -b : b), (c>d)) ? c : d);

5.5 Probleme propuse

1. Să se realizeze programe care execută următoarele acţiuni:


2. Se citeşte un unghi în grade; se cere să se transforme în radiani (360° = 2π rad)
3. Calculează perimetrul şi aria unui cerc de rază r citită de la tastatura
4. Calculează perimetrul şi aria unui triunghi de laturi date.
5. Calculează expresia: -3·x2 + x·y - y/x
?

5.6 ÎNTREBĂRI ŞI EXERCIŢII

5.6.1 Chestiuni teoretice

1. Ce reprezintă datele şi care sunt 13. Ce tipuri de variabile se utilizează


atributele lor ? pentru datele numerice ?
2. Care sunt diferenţele între constante şi 14. Care sunt calificatorii folosiţi alături de
variabile ? tipurile de bază pentru obţinerea
3. Cine determină tipul unei constante ? tipurilor derivate de date ?
4. Ce sunt identificatorii ? 15. Ce semnifică parantezele unghiulare <
5. Ce sunt directivele preprocesor ? > care încadrează numele unui fişier
6. Ce reprezinta variabilele ? header ?
7. Ce sunt constantele ? 16. Care este diferenţa între constantele
8. Enumeraţi tipurile simple de variabile. 35.2e-1 şi 3.52 ? Dar între "\t" şi '\t' ?
9. Câte tipuri de directive preprocesor 17. Ce tip are constanta 6.44 ?
cunoasteţi ? Exemple. 18. Care este diferenţa între operatorii = şi
10. Care este modalitatea de a interzice ==?
modificarea valorii unei variabile ? 19. Ce reprezintă caracterele "escape" ?
11. Ce loc ocupă declararea varibilelor în 20. Constante întregi.
cadrul unui program sursă scris în 21. Constante caracter.
limbajul C++ ? 22. Ce tipuri de conversii cunoaşteţi ?
12. Ce conţin fişierele header ? 23. Care sunt conversiile realizate în mod
automat, de către compilator ?

24
Laboratorul 5 Operatori şi expresii

24. Constante şir de caractere. 28. Operatorul sizeof.


25. Constante reale. 29. Operatori aritmetici binari compuşi.
26. Ce operatori ternari cunoasteţi ? 30. Operatorul de referenţiere.
27. Operatorul virgulă. 31. Operatori relaţionali binari.

5.6.2 Chestiuni aplicative


1. Să se scrie declaraţiile pentru definirea constantelor simbolice: pi, g (acceleraţia
gravitaţională), unghi_drept, dimensiune_MAX.
2. Care va fi rezultatul afişat pe ecran în urma execuţiei următoarelor secvenţe de
instrucţiuni:
‰ double a=9/2; cout<<a*5<<’\n’;
‰ double a=9.7, b=5.6; cout<<(a+6<b)<<’\n’;
‰ double a=9/4; cout<<a*6<<’\n’;
‰ double x=3;int y=++x+5;cout<<y<<’\n’;
‰ int a=7; cout<<(!a)<<’\n’;
‰ int a=10.5; cout<<a++<<’\n’; cout<<a<<’\n’;
‰ int a=7; cout<<++a<<’\n’; cout<<a<<’\n’;
‰ int a=10; cout<<a++<<’\n’; cout<<a<<’\n’;
‰ double a=7/2; cout<<a<<’\n’;
‰ int x=3; int y=x++-2; cout<<y<<’\n’;
‰ int x=3; int y=++x+5; cout<<y<<’\n’;
‰ double a=5.6, b=7.45; cout<<(a>b)<<’\n’;
3. Să se verifice corectitudinea următoarelor secvenţe. Pentru cele incorecte, explicaţi sursa
erorilor.
‰ double a=9.7, b=5.2; int c=(a+6<b)++; cout<<c<<’\n’;
‰ double a=7/5; double c=a*5++; cout<<c<<’\n’;
‰ double a=9.7, b=5.6; int c=(a%6<b)++; cout<<c<<’\n’;
‰ double a=5.6, b=7.45; cout<<++(a+5>b)<<’\n’;
‰ double a=9.8; double b=9.7; cout<<a%b<<’\n’;
‰ cout<<&(a+8)<<'\n';
‰ int I=8; cout<<(I+10)++<<'\n';
‰ double a=8.7; A=(a+8)/56; cout<<A<<'\n';
‰ int x=3/5; int y=x++; char x='J'; cout<<"y="<<y<<'\n';
‰ char a='X'; const int b=89; b+=8; cout<<"b="<<b<<"
a="<<a<<'\n';
4. Să se scrie un program care afişează următoarele mesaje:
• Sirul "este dupa-amiaza" este memorat pe .... octeti.
• marime intreaga este memorata pe ... octeti.
• marime reala, in simpla precizie este memorata pe ... octeti!
• marime reala, in dubla precizie este memorata pe ... byti!
• Constanta caracter 'Q' memorata pe ... octeti!
• Sirul "a\n\n" este memorat pe ... octei!
• Sirul "\n" este memorat pe ... biti!
• Caracterul '\' este memorat pe .... biti.
5. Să se evalueze expresiile, ştiind că: int i=1;int j=2;int k=-7;double x=0;double y=2.3;
‰ -i - 5 * j >= k + 1
‰ 3 < j < 5
‰ i + j + k == -2 * j
‰ x && i || j - 3
6. Ce operaţie logică şi ce mască trebuie să folosiţi pentru a converti codurile ASCII ale
literelor mici în litere mari ? Dar pentru conversia inversă ?
7. O deplasare la dreapta cu 3 biţi este echivalentă cu o rotaţie la stânga cu câţi biţi ?

25
Laboratorul 5 Operatori şi expresii

8. Să se seteze pe 1 toţi biţii dintr-un octet, cu excepţia bitului cel mai semnificativ.
9. Să se scrie un program care citeşte o valoare întreagă. Să se afişeze un mesaj care să
indice dacă numărul citit este par sau impar.
10. Să se citeasca două valori întregi. Să se calculeze şi să se afişeze restul împărţirii celor
două numere.

26
Laboratorul 6 Structuri de decizie (alternative, de selecţie)

6. Structuri de decizie (alternative, de selecţie)

6.1 Structura de decizie: instrucţiunea if

Aceasta corespunde cazurilor când în algoritmul problemei intervine o decizie.


Este instrucţiunea principală în C care descrie structura alternativă. Pentru un pseudocod
de forma:
dacă (<condiţie>) atunci <instrucţiune>
instrucţiunea if este:
if (<condiţie>) <instrucţiune>;
iar pentru un pseudocod de forma:
dacă (<condiţie>) atunci <instr1> altfel <instr2>
instrucţiunea if este:
if (<condiţie>) <instr1>; else <instr2> ;
OBSERVAŢIE: Dacă una din instrucţiunile de pe ramura "if" sau "else" este o instrucţiune
compusă, atunci ea se încadrează între acolade:
{ <instr1>; <instr2>; ... }
şi nu se mai termină cu punct-virgulă. În caz contrar programul va executa numai prima
instrucţiune de pe ramură.

6.2 Structura de selecţie cu ramuri multiple:


instrucţiunea switch

În unele cazuri este necesară o decizie multiplă specială.


Instrucţiunea switch permite acest lucru. test expr

DACĂ expresie=expr_const_1
instrucţiune1;
[ieşire;] instrucţiune1
ALTFEL DACĂ expresie=expr_const_2
break
instrucţiune2;
[ieşire;]
… instrucţiune2
ALTFEL DACĂ expresie=expr_const_n-1
instrucţiune_n-1; break
[ieşire;]
ALTFEL instrucţiune_n;

Se testează dacă valoarea pentru expresie este una instrucţiune_n


dintre constantele specificate (expr_const_1,
expr_const_2, etc.) şi se execută instrucţiunea de pe
ramura corespunzătoare. În schema logică test_expresie este una din condiţiile:
expresie=expr_const_1, expresie=expr_const_2, etc.
Sintaxa:

27
Laboratorul 6 Structuri de decizie (alternative, de selecţie)

switch (expresie)
{
case expresie_const_1: instructiune_1; [break;]
case expresie_const_2: instructiune_2; [break;]
. . . . . . . . . . . . . .
case expresie_const_n-1: instructiune_n-1;[break;]
[ default: instructiune_n; ]
}

6.3 Exemple if, switch

6.3.1 Maximul a trei numere

6.3.1.1 Pseudocodul: void main()


{
1.citeşte a,b,c int cod=1; float x,y,z; char op;
2.dacă a>b atunci max=a altfel max=b while(cod)
3.dacă c>max atunci max=c {
4.scrie max printf("\nIntroduceti expresia
Start (valoare operator valoare): ");
scanf("%f %c %f",&x,&op,&y);
switch(op)
Citeşte
a, b, c
{
case '+':z=x+y;break;
case '-':z=x-y;break;
Nu Dacă Da
case '*':z=x*y;break;
a>b
case '/':z=x/y;break;
max=b max=a default: printf("\nOperator
eronat"); cod=0; z=0;
}
Da printf("%.2f %c %.2f=
Dacă %.2f",x,op,y,z);
c>max max=c }
}
Scrie “Max =” , max Să se scrie un program care citeşte o cifră
din intervalul [1,7] şi afişează denumirea
Stop
zilei din săptămînă corespunzătoare cifrei
respective (1-luni, 2-marţi etc).
6.3.1.2 Programul: //PROGRAMUL BIV25
#include<iostream.h> #include <stdio.h>
main() #include <stdlib.h>
{ void main( )
int a,b,c,max; /* citestc o cifra din intervalul
cout<<"Dati a b c"; cin>>a>>b>>c; [1,7] si afiseaza denumirea zilei
if(a>b) max=a; din saptamina corespunzatoare
else max=b; cifrei respective */
if(c>max) max=c; {
cout<<"maximul="<<max; int i;
} scanf("%d", &i);
switch(i)
{
6.3.2 Calculator de buzunar case 1: puts("luni");break;
//Instruc de selectie switch case 2: puts("marti");break;
#include<stdio.h> case 3: puts("miercuri"); break;

28
Laboratorul 6 Structuri de decizie (alternative, de selecţie)

case 4: puts("joi"); break; default: puts("Valoare gresita


case 5: puts("vineri"); break; !");exit(1);
case 6: puts("simbata"); break; }
case 7: puts("duminica"); break; }

6.4 Probleme propuse

Să se alcătuiască programe care să rezolve următoarele probleme:

6.4.1 Calculul volumului unui corp geometric


Să se scrie un program care afişează un mesaj de tip meniu şi în funcţie de un caracter citit
de la tastatură (1 pentru paralelipiped, 2 - Cilindru, 3 - Con, 4 - Sferă, 0 - terminare program)
citeşte dimensiunile necesare şi calculează şi afişează în cadrul unui mesaj volumul corpului
respectiv (Vp = H·B·L; Vcil = π·R2·H; Vcon = π·R2·H/3; Vsf = π·D3/6).

Start

Citeşte
a, b, c

Nu Da
Dacă
a=0

Δ = b2 – 4ac

Da
Nu

Dacă
Da
i<iter
Scrie “Ec
are rad x
x0=x
Nu Dacă Da
Δ>0 b=0

Scrie “Ec e de
gradul unu
x1 = -c/b

Nu Dacă Da Nu Daca Da
Δ<0 c=0

-b
-b± Δ -b re = 2a
x1,2 = x1,2 = 2a
2a

im = 2a

Scrie “Ec are Scrie “Ec are Scrie “Ec are Scrie “Ec nu Scrie “Ec are
doua rad dif” rad dubla” rad compl” are nici o o infinit ate de
x1 şi x2 x1 = x2 x1,2 = re±i⋅im solutie” solutii”

Stop

2.1.1.1 scrie "ec.are o infinitate de


6.4.2 Ecuaţia de gradul 2 (vezi şi schema sol."
logică) 2.1.1.2 altfel scrie "ec.nu are sol"
1.citeşte a,b,c 2.1.2 altfel scrie "ec.are sol.unică x=",-c/b
2.dacă a=0 atunci altfel
2.1.dacă b=0 atunci 2.2 d=b*b-4*a*c
2.1.1.dacă c=0 atunci 2.2.1 dacă d>0 atunci
2.2.1.1.x1=(-b- d )/(2*a)

29
Laboratorul 6 Structuri de decizie (alternative, de selecţie)

x2=(-b+ d )/(2*a) 3.1.2 altfel arg = -pi/2


scrie "x1=",x1,"x2=",x2 3.2 altfel
2.2.1.2 altfel dacă re>0 atunci
dacă d=0 atunci 3.2.1 arg=arctg(im/re)
2.2.1.2.1 scrie "ec.are 3.2.2 altfel arg=-arctg(im/re)
rad.dubla x=",-b/(2*a) 4.scrie re,im
altfel
2.2.1.2.2 re = -b/(2*a) 6.4.4 Rezolvarea unui sistem de două
ecuaţii cu două necunoscute x,y
im = -d /(2*a)
scrie "ec.are 1.citeşte a11,a12,a21,a22,b1,b2
sol.complexe re = ", re," im = ",im 2.det = a11*a22-a21*a12
3.detx = b1*a22-b2*a12
6.4.3 Modulul şi argumentul unui număr 4.dety = a11*b2-a21*b1
complex 5.x = detx/det; y = dety/det
1.citeşte re,im
6.4.5 Sa se calculeze şi sa se afişeze
2.modul = re*re+im*im valoarea funcţiei f pentru un x dat:
3.dacă re=0 atunci
3.1 4x3 + 5x2 - 2x + 1, x<0
dacă im>=0 atunci f(x)= 100, x=0
x
3.1.1 arg=pi/2 e - ln x, x>0

Start

Citeşt
e

modul= re ⋅ re + im ⋅ im

N Dacă
D
re=0

N Dacă D D Dacă N
re>0 im>=0

arg=- arg=arct(im/r arg=pi/2 arg=-pi/2

scrie re,im

Stop

30
Laboratorul 7 Structura ciclică cu test iniţial.

7. Structura ciclică cu test iniţial.


Aceasta corespunde cazurilor când în algoritmul problemei intervine iteraţia unei acţiuni până
la o condiţie de oprire.

7.1 Instrucţiunea while

Este principala instrucţiune în C++ care descrie structura alternativă.


Pentru un pseudocod de forma:
cât timp (<condiţie>) execută <instrucţiune>
instrucţiunea while este:
while (<condiţie>) <instrucţiune>;

7.2 Exemple - while

1.citeşte a,b
7.2.1 Algoritmul lui Euclid 2.dacă (a<>0) şi (b<>0)
Start 2.1.cmmmc=a*b
2.2. r = a%b //restul
2.3.a = b
Citeşte a,b
2.4.b = r
2.5.cât timp r<>0
N Dacă D 2.5.1.r = a%b //restul
a≠0, 2.5.2.a = b
2.5.3.b = r
cmmmc=0 cmmmc=a*b 2.6.cmmdc = a
cmmdc=0 r=a%b; 2.7.cmmmc = cmmmc/cmmdc
a=b;b=r 2.8.scrie cmmmc,cmmdc

N Daca D Programul:
r≠0 //Algoritmul lui Euclid
#include<iostream.h>
cmmmc=a; r=a%b; main()
cmmmc=
cmmmc
; a=b;b=r; {
cmmdc long int a,b,r,cmmmc,cmmdc;
cout<<"a=";cin>>a; cout<<"b=";cin>>b;
if(a!=0&&b!=0)
scrie {
cmmdc; cmmmc; cmmmc=a*b; r=a%b; a=b; b=r;
while (r!=0)
{
Stop r=a%b; a=b; b=r;
cout<<"\na=
"<<a<<"\tb="<<b<<"\tr="<<r;
}
Pseudocodul: cmmdc=a;
cmmmc = cmmmc/cmmdc;

31
Laboratorul 7 Structura ciclică cu test iniţial.

cout<<"\ncmmmc= "<<cmmmc<<" cmmdc= 7.2.3 Suma primelor “n” numere naturale


"<<cmmdc;
#include <iostream.h>
}
} void main()
{int suma=0,i=0,n;
cout << "\nSpecificati numarul
n:";
7.2.2 Produsul primelor “n” numere cin >> n;
naturale=factorial while(i<n)
#include <iostream.h> {
void main() i++;
{int prod=1,i=0,n; char c; suma=suma+i;
cout << "\nSpecificati numarul n:"; }
cin >> n; cout << "\nSuma primelor " << n <<
while(i<n) {i++; prod=prod*i;}
" numere naturale=" << suma <<
cout << "\nFactorial de " << n << "="
<< prod << "\n";
"\n";
cin >> c; }
}

7.3 Instrucţiunea for

În majoritatea limbajelor de programare de nivel înalt, instrucţiunea for implementează


structura ciclică cu număr cunoscut de paşi. În limbajul C instrucţiunea for poate fi utilizată
într-un mod mult mai flexibil.

Reprezentare în pseudocod:
evaluare expresie1 (particular iniţializare contor)

0 evaluare expresie1
expresie2
CÂT TIMP expresie2
1 REPETĂ
instrucţiune
ÎNCEPUT
instructiune
evaluare
evaluare expresie3 (particular expresie3
incrementare contor) SFÂRSIT
Figura 3.3. Structura ciclică cu test iniţial
Sintaxa:
for (expresie1; expresie2; expresie3)
instructiune;
unde:
expresie1 – reprezintă initializarea contorului;
expresie2 – conditia de rămânere in ciclu;
expresie3 – modificarea contorului
Nu este obligatorie prezenţa expresiilor, ci doar a instrucţiunilor vide.

7.4 Exemple - for

32
Laboratorul 7 Structura ciclică cu test iniţial.

5.1.2.j=j+1
7.4.1 Calculul factorialului 5.2.i=i+1
//Calculul factorialului 6.scrie s
#include<iostream.h>
#include<conio.h> Programul:
void main() #include<iostream.h>
{ #include<math.h>
long int i,n,fact=1; main()
clrscr(); {
cin>>n; float s,a,b; int m,n,i,j;
for(i=1;i<=n;i++) cout<<"a="; cin>>a; cout<<"b=";
fact*=i; cin>>b; cout<<"m="; cin>>m;
cout<<fact;
cout<<"n="; cin>>n;
getch();
}
for(i=1,j=1; i<=m,j<=n; i++,j++)
s=s+ sin(a+3*i)*cos(b+5*j);
cout<<"Suma="<<s;
}
7.4.2 Calculul unei sume Start
Să se calculeze suma dublă
m


n Citeşte n
∑ sin(a+3*i)*cos(b+5*j).
j=1
i=1 i=1
Start

Nu Da
Citeşte i<=n
a,b,m,n

i=1, j=1
fact*=i

Nu i<m
Da i=i+1
j<n

scrie
s=s+sin(a+3*i)*cos(b+5*j) fact

i=i+1 Stop
j=j+1

7.4.3 Afisarea codurilor ASCII ale


scrie caracterelor
s //Coduri ASCII caractere
#include<conio.h>
Stop #include<stdio.h>
Pseudocodul: void main()
1.citeşte a,b,m,n {
2.i=1 3.j=1 4.s=0 int i,j;
5.cât timp (i<=m) clrscr();
5.1.cât timp (j<=n) // printf("\ncaracASCII\tcod
5.1.1.s=s+ sin(a+3*i)*cos(b+5*j) zecimal\tcod octal");

33
Laboratorul 7 Structura ciclică cu test iniţial.

for(i=0;i<=255;i+=10) //Genereaza numerele Fibonacci


{ #include<stdio.h>
printf("\n"); #include<conio.h>
for(j=1;j<=10;j++)
if(i+j<=255) printf("%d: %c void main()
",i+j,i+j); {
//if(!(i%25)) getch(); int f0=0,f1=1,fi,n;
} clrscr();
getch(); printf("Introd n:");
} scanf("%d",&n);
if(n>=2)
Sirul lui Fibonacci, primii n {
termeni. for(f0=0,f1=1;f1<=n;f0=f1,f1=fi)
Dacă n=0: f(0)=0, n=1: f(1)=1, altfel: {
f(i) = f(i-2) + f(i - 1) fi=f0+f1;
printf("\nfi=%d",fi);
Pseudocodul:
//
1. f0=0, 2.f1=1 printf("\nf0=%d\tf1=%d\tfi=%d",f0,f
3. citeşte n 1,fi);
4.dacă n>=2 }
4.1.pentru f0=0 şi f1=1, cât timp }
f1≤n, f0=f1, f1=fi, repeta getch();
4.1.1.fi=f0 + f1 }
4.1.2.Scrie fi
Programul:

34
Laboratorul 8 Structura ciclică cu test final

8. Structura ciclică cu test final

8.1 Instrucţiunea do - while

Pentru un pseudocod de forma:


<instrucţiune 1>
cât timp (<condiţie>) execută <instrucţiune 1>
instrucţiunile C++ sunt:
<instrucţiune 1>; while (<condiţie>) <instrucţiune 1>;
Dar aceste instrucţiuni se pot înlocui cu o singură instrucţiune do-while astfel:
do <instrucţiune 1> while (<condiţie>);
Aceasta nu reprezintă decât structura iterativă cu test final, "repetă instrucţiune cât timp
condiţie"

8.2 Exemple - do - while

#include<iostream.h>
8.2.1 Calculul sumei unor numere citite void main()
de la tastatură până la introducerea {
numărului zero. float s,x; s=0;
cout<<"Dati numerele de adunat
Pseudocodul:
(0-oprire)";
1.s=0 do
2.repetă { cin>>x; s+=x;}
2.1.citeşte x while (x!=0);
2.2.s=s+x cout<<s;
cât timp (x!=0) }

Programul:

8.2.2 Problema 1:
Să se alcătuiască un program în care să fie implementate o funcţie pentru ridicarea lui 2 la o
putere întreagă şi una pentru calculul radicalului de ordinul doi pe baza şirului lui Newton.
Strategia de rezolvare: Funcţia care va calcula puterea întreagă a lui 2 se bazează pe efectul
de deplasare a biţilor din reprezentarea binară a unui număr. Astfel, o deplasare la stânga a
lui a de b ori (a<<b) presupune o înmulţire a lui a cu 2 de b ori: a<<b este echivalentă cu a⋅2b.
La fel, o deplasare la dreapta la nivel de bit, a lui a cu b poziţii (a>>b) presupune o împărţire
a lui a cu 2 de b ori (a⋅2-b).
Construcţia funcţiei ce calculează rădăcina pătrată a unui număr x are la bază şirul lui
⎛ x⎞
Newton, dat prin relaţia de recurenţă an+1 = 0.5⎜an + a ⎟ , unde primul element a1 = 1, iar n>2.
⎝ n⎠
Funcţia calculează termenii succesivi ai şirului până când diferenţa, în valoare absolută,
dintre doi termeni succesivi este mai mică decât eroarea acceptată pentru calcul.

/*Program 8.

35
Laboratorul 8 Structura ciclică cu test final

Calculul ridicarii lui 2 la o return q;


putere intreaga si }
calculul radacinii patrate fara
utilizarea functiei sqrt*/ void main()
{
#include<iostream.h> int a; char Exit;
#include<conio.h> do
#include<math.h> {
clrscr();
int pow2(int x) cout<<"Dati un numar A =";
{//Functia calculeaza 2^n. cin>>a;
int y=1; cout<<"2^"<<a<<" =
return (y<<x); "<<pow2(a)<<endl;
} cout<<"Radical
(2^"<<a<<")="<<rad2(pow2(a))<<endl;
float rad2(float x) cout<<"Pentru iesire apasati->
{//Functia calculeaza radacina e..";
patrata a lui x. Exit=getch();
}
float p=1, q=(1+p)/2, err=1e-6;
do while(Exit!='e');
{p=q; q=(p+x/p)/2;} }
while(fabs(q-p)>err);
printf("\nIntroduceti val x: ");
8.2.3 Calculul unei sume cu o precizie scanf("%f",&x);
impusă T=S=1; k=1;
do
Să se calculeze suma S =
∑ (-1)k·xk
k! până
{
printf("\nk= %d\tT= %12.4f\tS=
k=1 %14.10f\t|T/S|=
când |T/S| < ε. %14.10f",k,T,S,fabs(T/S));
Obs: T[k] = -T[k-1]·x/k, iar S[k] = S[k-1] + T=-T*x/k; S+=T; k++;
T[k] }
while(fabs(T/S)>=eps);
getch();
8.2.3.1 Pseudocod: }
1. Citeşte x, eps,
2. T = S = k = 1, Secvenţele următoare descriu strict
3. Repetă metoda prezentată şi nu întreg
3.1. T = -T·x/k, programul !
3.2. S = S + T,
Programele următoare se bazează pe
3.3. k = k + 1
următoarele instrucţiuni:
cât timp |T/S| ≥ ε
1. împărţire întreagă (modulo) a unui
4. Scrie S
număr întreg la 10 prin care se obţine
cifra unităţilor numărului. Ex: 1234%10
8.2.3.2 Programul →4
2. împărţire propriu-zisă a unui număr
//Calculul unei sume
întreg la 10 prin care se obţine tot un
#include<conio.h>
#include<math.h> întreg. Ex: 1234/10 → 123 şi NU 123.4
#include<stdio.h>
8.2.4 Suma cifrelor unui număr "n"
void main() s=0;nl=n;
{ do
float x,T; double S,eps=1e-05; int {
k; s+=nl%10;//se obtine pe rind
//clrscr(); nl/=10; //fiecare cifra incepind

36
Laboratorul 8 Structura ciclică cu test final

//cu cea a unitatilor 8.2.8 Apariţia unei cifre "a" într-un


} număr "n"
while(nl); nr=0;nl=n;
cout<<"\nSuma cifrelor nr. "<<n<<" do
= "<<s; {
if(nl%10==a)
8.2.5 Ştergerea unei cifre "a" dintr-un nr++;
număr "n" nl/=10;
}
nl=0;
while(nl);
do
cout<<"\nCifra "<<a<<" apare de
{
if (n%10!=a) nl=nl*10+n%10; "<<nr<<" ori";
n/=10;
} 8.2.9 Inserarea unei cifre "a" pe o poziţie
while(n); "k" a unui număr "n"
do nl=0;i=0;//poz.se numără de la
{ sfârsit
n=n*10+nl%10; while(i++<k)
nl/=10; {
} nl=nl*10+n%10;
while(nl); n/=10;
cout<<"\nNoul numar: "<<n; }
nl=nl*10+a;
8.2.6 Oglindirea unui număr "n" do
n_o=0;nl=n; {
do n=n*lD+nl%10; nl/=10;
{ }
n_o=n_o*10+nl%10; while(nl);
nl/=10; cout<<"\nNoul numar este: "<<n;
}
while(nl); 8.2.10 Cifra maximă "cmax" a unui
cout<<"\nOglinditul lui "<<n<<" număr "n"
este "<<n_o; cmax=0;nl=n;
do
8.2.7 Trecerea unui număr "n" din baza {
10 în baza b∈[2..9] if(cmax<n%10)
aux=n_b=0; cmax=nl%10;
do nl/=10;
{ }
aux=aux*10+n%b; while (nl) ;
n/=10; cout<<"\ncmax="<<cmax;
}
while(n); 8.2.11 Trecerea unui număr "n" din baza
do b∈[2..9] în baza 10
{ n_10=0;p=l;
n_b=n_b*10+aux%10; do
aux/=10; {
} n_10=n_10+n%10*p;
while(aux); n/=10;
cout<<"\nNumarul in baza "<<b<<" p*=b;
este "<<n_b; }
while(n);
cout<<n_10;

37
Laboratorul 8 Structura ciclică cu test final

8.3 Exerciţii

Să se alcătuiască programe care să rezolve următoarele probleme:


4.1.e=0 //exponentul la care apare
8.3.1 Descompunerea unui număr în factorul în descompunere
factori primi 4.2.cât timp (n%f==0) //n se divide la f
4.2.1.n=n/f
8.3.1.1 Pseudocodul: 4.2.2.e=e+1
1.citeşte n 4.3.dacă (e<>0) scrie f," la ",e
2.n=abs(n) 4.4.dacă (f==2) f=f+1 altfel f=f+2
3.f=2 //factorul prim de testat
4.cât timp (f<=n)

8.4 Facilităţi de întrerupere a unei secvenţe

8.4.1 Instrucţiunea break


Utilizată în cadrul instrucţiunilor ciclice, instrucţiunea break "forţează" ieşirea din acestea.
Fără a se mai testa valoarea expresiei (condiţia) care determină repetarea corpului
instrucţiunii ciclice, se continuă execuţia cu instrucţiunea care urmează instructiunii ciclice.
Astfel, se întrerupe repetarea corpului instrucţiunii ciclice, indiferent de valoarea condiţiei de
test.
Utilizarea în cadrul instrucţiunii switch: În situaţia în care s-a ajuns la o valoare a unei
expresiei constante egală cu cea a expresiei aritmetice, se execută instrucţiunea
corespunzătoare acelei ramuri. Dacă se întâlneşte instrucţiunea break, parcurgerea este
întreruptă (nu se mai compară valoarea expresiei aritmetice cu următoarele constante), deci
se va trece la execuţia primei instrucţiuni de după switch. Dacă nu este întâlnit break,
parcurgerea continuă. Instrucţiunea break cauzează deci, ieşirea imediată din switch.

8.4.2 Instrucţiunea continue


Întâlnirea instrucţiunii continue determină ignorarea instrucţiunilor care o urmează în corpul
instrucţiunii ciclice şi reluarea execuţiei cu testarea valorii expresiei care determină repetarea
sau nu a corpului ciclului.

8.4.3 Modul de utilizare a instrucţiunilor break şi continue


do while(expresie1) for(expr1; expr2;
{ instructiune1; expr3)
{ instructiune1;
instructiune2; { instructiune1;
if (expresie2) instructiune2; instructiune2;
break; if (expresie2) if (expresie2)
else break; break;
continue; else else
instructiune3; continue; continue;
} instructiune3; instructiune3;
while (expresie1); } }

38
Laboratorul 8 Structura ciclică cu test final

printf("\nIntroduceti
expresia (valoare operator
valoare): ");
8.5 Exemple break, continue scanf("%f %c %f",&x,&op,&y);
switch(op)
{
8.5.1 Calculator de buzunar case '+':z=x+y;break;
case '-':z=x-y;break;
//Instruc de selectie switch case '*':z=x*y;break;
#include<stdio.h> case '/':z=x/y;break;
default: printf("\nOperator
void main() eronat"); cod=0; z=0;
{ }
int cod=1; float x,y,z; char op; printf("%.2f %c %.2f=
while(cod) %.2f",x,op,y,z);
{ }
}

8.6 ÎNTREBĂRI ŞI EXERCIŢII

8.6.1 Chestiuni teoretice


1. Care sunt instrucţiunile care implementează în limbajul C structura condiţională ?
2. Care sunt instrucţiunile care implementează în limbajul C structura secvenţială ?
3. Care sunt instrucţiunile care implementează în limbajul C structura repetitivă cu test iniţial ?
4. Care sunt instrucţiunile care implementează în limbajul C structura repetitivă cu test final ?
5. Ce deosebiri sunt între instrucţiunea while şi instrucţiunea do-while ?
6. Pornind de la sintaxa instrucţiunii for, stabiliţi echivalenţa între aceasta şi instrucţiunile while şi
do-while.

8.6.2 Chestiuni practice


1. Să se calculeze aria unui triunghi, cunoscându-se mărimea laturilor sale. Numerele care
reprezintă mărimile laturilor vor fi introduse de utilizator. Se va testa mai întâi dacă cele 3
numere reprezentând mărimea laturilor pot forma un triunghi ( a <= b+c, b <= c+d, c <= a+b).
2. Să se rescrie următoarea secvenţă, folosind o singură instrucţiune if.
if (n<0)
if (n>=90)
if (x!=0)
int b= n/x;
xy = (x+y)2
3. Să se găsească toate numerele de două cifre care satisfac relaţia: __
4. Să se citească un şir de numere reale, până la întâlnirea numarului 800 şi să se afişeze
valoarea minimă introdusă, suma şi produsul elementelor şirului.
5. Scrieţi un program care să verifice inegalitatea 1/(n+1) < ln[(n+1)/n] < 1/n, unde n este un
număr natural pozitiv, introdus de la tastatură.
6. Fie funcţia
ex-3 , x ∈ [0, 1)
Să se calculeze f(x), x citit de la tastatură.
f(x)= sinx+cosx , x ∈ [1, 2)
0,9ln(x+3) , x ∈ [2, 100]
7. Să se scrie un program care calculează şi afişează maximul a 3 numere reale (a, b şi c) citite
de la tastatură.
8. Să se scrie un program care calculează şi afişează minimul a 3 numere reale (a, b şi c) citite
de la tastatură.

39
Laboratorul 8 Structura ciclică cu test final

9. Să se citească 2 caractere care reprezintă 2 litere mari. Să se afişeze caracterele citite în


ordine alfabetică.
10. Să se citească 3 caractere care reprezintă 3 litere mici. Să se afişeze caracterele citite în
ordine alfabetică.
11. Să se scrie un program care citeşte o cifră. În funcţie de valoarea ei, să se facă următorul
calcul: dacă cifra este 3, 5 sau 7 să se afişeze pătratul valorii numerice a cifrei; dacă cifra este
2, 4 sau 6 să se afişeze cubul valorii numerice a cifrei; dacă cifra este 0 sau 1 să se afişeze
mesajul "Valori mici"; altfel., să se afişeze mesajul "Caz ignorat!".
12. Fie şirul lui Fibonacci, definit astfel:
f(0)=0, f(1)=1, f(n)=f(n-1)+f(n-2) în cazul în care n>1.
Să se scrie un program care implementează algoritmul de calcul al şirului Fibonacci.
13. Să se calculeze valoarea polinomului Cebîşev de ordin n într-un punct x dat, cunoscând
relaţia:
T0(x)=1, T1(x)=x şi Tk+1 (x) - 2xTk (x) + Tk -1(x) = 0
14. Să se citească câte 2 numere întregi, până la întâlnirea perechii (0, 0). Pentru fiecare pereche
de numere, să se calculeze şi să se afişeze cel mai mare divizor comun.
15. Se citesc câte 3 numere reale, până la întâlnirea numerelor 9, 9, 9. Pentru fiecare triplet de
numere citit, să se afişeze maximul.
16. Se citeşte câte un caracter până la întâlnirea caracterului @. Să se afişeze numărul literelor
mari, numarul literelor mici şi numărul cifrelor citite; care este cea mai mare (lexicografic) literă
mare, literă mică şi cifră introdusă.
17. Se citesc câte 2 numere întregi, până la întâlnirea perechii de numere 9, 9. Pentru fiecare
pereche de numere citite, să se afişeze cel mai mare divizor comun al acestora.
18. Să se calculeze suma seriei
1 + x3/3 - x5/5 + x7/7 - …
cu o eroare mai mică decât epsilon (epsilon citit de la tastatură). Să se afişeze şi numărul de
termeni ai sumei.
19. Să se citească un număr întreg format din 4 cifre (abcd). Să se calculeze şi să se afişeze
valoarea expresiei reale: 4*a + b/20 -c + 1/d.
20. Să se scrie un program care afişează literele mari ale alfabetului în ordine crescătoare, iar
literele mici - în ordine descrescătoare.
21. Să se scrie un program care generează toate numerele perfecte până la o limită dată, LIM. Un
număr perfect este egal cu suma divizorilor lui, inclusiv 1 (exemplu: 6=1+2+3).
22. Să se calculeze valoarea sumei urmatoare, cu o eroare EPS mai mică de 0.0001:
S=1+(x+1)/ 2! + (x+2)/ 3! + (x+3)/ 3! + ... , unde 0<=x<=1, x citit de la tastatură.
23. Să se genereze toate numerele naturale de 3 cifre pentru care cifra sutelor este egală cu
suma cifrelor zecilor şi unităţilor.
24. Să se citească câte un număr întreg, până la întâlnirea numărului 90. Pentru fiecare numar să
se afişeze un mesaj care indică dacă numărul este pozitiv sau negativ. Să se afişeze cel mai
mic număr din şir.
25. Să se genereze toate numerele naturale de 3 cifre pentru care cifra zecilor este egală cu
diferenţa cifrelor sutelor şi unităţilor.
26. Să se calculeze suma:
(1 + 2!) / (2 + 3!) - (2+3!) / (3+4!) + (3+4!) / (4+5!) - .....

40
Laboratorul 9 Tablouri unidimensionale

9. Tablouri unidimensionale

9.1 Vectori

Adeseori în programe se folosesc grupe mari de date. Gruparea acestora se face în mai
multe moduri. Un mod simplu de a grupa datele este de a grupa datele este de a considera
date de acelaşi tip în aşa fel încât grupa respectivă să formeze o mulţime ordonată de
elemente la care ne referim prin indici. O astfel de grupă se numeşte tablou. Unui tablou i se
dă un nume; tipul comun al elementelor este şi tipul tabloului respectiv. De exemplu o
mulţime ordonată de întregi reprezintă un tablou de tip întreg.
În cazul când elementele care se grupează într-un tablou sunt ele însele tablouri vom avea
nevoie de mai mulţi indici pentru a ne referi la ele; în acest caz avem un tablou
multidimensional (n-dimensional, n fiind numărul de indici) altfel - tablou unidimensional.
Exemple simple de tablouri unidimensionale sunt vectorii cu componentele de acelaşi tip. O
matrice este un tablou bidimensional.
Referirea la elementele unui tablou se face printr-o variabilă cu indici. O variabilă cu indici se
compune din numele tabloului urmat de valorile indicilor fiecare indice fiind reprezentat de o
expresie inclusă între paranteze pătrate.
Valoarea inferioară a indicilor este 0. De exemplu dacă vect este un tablou cu 10 elemente
atunci ne referim la elementele lui cu ajutorul variabilelor cu indici:
vect[0] primul element
............
vect[9] ultimul element
Dacă mat este o matrice de 3 linii a două coloane fiecare atunci elementele vor fi referite
prin:
mat[0][0] mat[0][1] prima linie
mat[1][0] mat[1][1] a doua linie
mat[2][0] mat[2][1] a treia linie

9.2 Declaraţia de tablou

Un tablou ca orice variabilă simplă trebuie declarat înainte de a fi utilizat. Declaraţia de tablou
în forma cea mai simplă conţine tipul comun elementelor sale, numele tabloului şi limitele
superioare pentru fiecare indice incluse între paranteze pătrate:
tip nume [lim_1][lim_2]...[lim_n] = {lista valori}
unde tip este tipul de bază al tabloului iar lim_i este limita superioară a celui de al i-lea indice;
înseamnă că indicele al i-lea poate lua valorile: 0, 1,..., lim_n-1 (lim_n - sunt expresii
constante).
La întâlnirea unei declaraţii de tablou compilatorul alocă o zonă de memorie necesară
păstrării valorii elementelor sale.

9.3 Exemple

41
Laboratorul 9 Tablouri unidimensionale

float
9.3.1 Instrucţiunile de citire a primelor n temp,suma,media,min,max,a[100];
elemente ale unui vector clrscr();
for(i=0; i<n; i++) cin>>a[i]; printf("Dati nr. de elem ale
sirului N=");
9.3.2 Instrucţiunile de scriere a primelor scanf("%2d",&N);
for(i=1;i<N+1;i++)
n elemente ale unui vector
{
for(i=0; i<n; i++) cout<<a[i]; printf("A[%2d]=",i);
scanf("%f",&temp);
9.3.3 Operaţii cu elemente unui vector a[i]=temp;
Să se alcătuiască un program care să }
determine valoarea minimă, maximă, suma min=a[1];max=a[1];
şi media elementelor unui şir de numere for(i=2;i<N+1;i++)
{
reale.
if(a[i]<min) min=a[i];
if(a[i]>max) max=a[i];
9.3.3.1 Strategia de rezolvare: }
Va fi citit mai întâi numărul curent de suma=0;
elemente ale şirului, iar apoi vor fi citite for(i=1;i<N+1;i++)
succesiv elementele şirului folosind o suma+=a[i];
variabilă intermediară temp. media=float(suma)/N;
Pentru determinarea valorii minime şi printf("Valoarea minima a sirului
maxime a şirului se iniţializează atât MIN =%g\n",min);
printf("Valoarea maximii a siruJui
minimul cât şi maximul cu prima poziţie din MAX =%g\n",max);
şir, după care, succesiv, vor fi comparate printf("Suma elementelor sirului
elementele şirului cu minimul curent şi SUMA =%g\n",suma);
respectiv cu maximul curent. Dacă valoarea printf("Valoarea medie a sirului
comparată a elementului şirului este mai MED =%g\n",media);
mare decât maximul curent, atunci această N=getche();
valoare devine maximul curent. Similar se }
petrec lucrurile pentru valoarea minimă.
Pentru calculul sumei elementelor şirului,
variabila suma se iniţializează cu zero, 9.3.4 Produsul scalar a doi vectori
după care fiecare element al şirului se
adaugă la valoarea curentă a sumei, 9.3.4.1 Program:
conform relaţiei: suma= suma + a[i], relaţie #include<iostream.h>
ce poate fi scrisă simplificat astfel: main()
suma+=a[i]. Media aritmetică se calculează {
prin raportarea sumei elementelor la unsigned n,i; float
numărul de elemente din şir. a[100],b[100],p;
cout<<“dati dimensiunea:”;cin>>n;
for (i=0;i<n;i++)
/* Program 6.
{ cout<<“a[“<<i<<“]”; cin>>a[i];
Determinarea valorilor minima si
}
maxima ale unui sir de numere
for (i=0;i<n;i++)
reale.
{ cout<<“b[“<<i<<“]”; cin>>b[i];
Determinarea sumei elementelor
}
sirului si a mediei aritmetice a
p=0; for (i=0;i<n;i++)
acestora.*/
p+=a[i]*b[i]; cout<<“Produsul=“<<p;
#include<stdio.h>
}
#include<conio.h>

void main()
{
int i,N;

42
Laboratorul 9 Tablouri unidimensionale

9.3.5 Sortarea crescătoare a elementelor principală să fie elementele de maxim ale


unui vector cu n elemente reale fiecărei linii. Se consideră că elementele
matricii sunt distincte.
9.3.5.1 Pseudocod: Vom determina mai întâi coloanele
1. Citeşte n elementelor de maxim ale fiecărei linii într-
2. Pentru i=0,n-1 citeşte v[i] un vector c. Apoi vom verifica dacă valorile
3. m=n, sort=0 coloanelor sunt distincte, în caz contrar nu
4. Cât timp (m>0) şi (sort=0) este posibilă rearanjarea liniilor conform
4.1. sort=1 cerinţelor problemei.
4.2. Pentru i=0,m-1 Exemplu: Dimensiunea matricii: 3.
dacă (v[i]>v[i+1]) ⎡2 1 8⎤
4.2.1. sort=0 Elementele matricii: ⎢⎢ 9 2 0 ⎥⎥ . O soluţie
4.2.2. aux=v[i] ⎣5 7 6⎦
4.2.3. v[i]=v[i+1] ⎡ 9 2 0 ⎤
4.2.4. v[i+1]=aux este: ⎢⎢ 5 7 6 ⎥⎥ .
4.3. m=m-1 ⎣2 1 8⎦
5. Pentru i=0,n-1 scrie v[i]
9.3.6.1 Programul este următorul:

9.3.5.2 Programul: #include<stdio.h>


//Sortarea elementelor unui vector int
#include<iostream.h> c[10],mat1[10][10],mat[10][10],i,j,
poz,max1,n;
void main()
{ int maxim(int i) ;
int i,n,m,sort=0,v[10],aux;
cout<<"\nDati dimens vect n: void main()
";cin>>n; {/* Citire dimensiune*/
for(i=0;i<n;i++) printf("Dimensiunea matricii: ");
{ scanf("%d",&n);
cout<<"Elem v["<<i<<"]= "; /* Citire matrice */
cin>>v[i]; printf("Elementele matricii: ");
} for(i=1;i<=n;i++)
m=n; for(j=1;j<=n;j++)
while((m>0)&&(sort==0)) scanf("%d",&mat[i][j]);
{ /* Aflarea maximelor pe linii */
sort=1; for(i=1;i<=n;i++)
for(i=0;i<m-1;i++) c[i]=maxim(i);
if(v[i]>v[i+1]) /* Se verifica daca coloanele
{ obtinute sunt unice */
sort=0; for(i=1;i<n;i++)
aux=v[i]; v[i]=v[i+1]; for(j=i+1;j<=n;j++)
v[i+1]=aux; if(c[i]==c[j])
} {puts ("Problema nu are
m--; solutie"); return; }
} /* Copierea liniilor cu maximul pe
for(i=0;i<n;i++) diagonala principala in alta
cout<<"\nv["<<i<<"]= "<<v[i]; matrice */
} for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
mat1[c[i]][j]=mat[i][j];
puts("O solutie este: ");
9.3.6 Problema 5: for(i=1;i<=n;i++)
Să se facă rearanjarea liniilor unei matrici {
astfel încât elementele de pe diagonala for(j=1;j<=n;j++)
printf ("%5d",mat1[i][j]);

43
Laboratorul 9 Tablouri unidimensionale

puts(" "); max1=mat[i][1];


} for(j=2;j<=n;j++)
} if(mat[i][j]>max1)
{max1=mat[i][j]; poz=j; }
int maxim(int i) return poz;
{ }
poz=1;
/* Se determina coloana unui
element de maxim al liniei i */

44
Laboratorul 10 Şiruri de caractere

10. Şiruri de caractere

10.1.1 Problema 1:Fiind dat un cuvânt, să se afişeze toate prefixele acestuia.


Se va determina mai întâi lungimea cuvântului. Întrucât nu se cere o anumită ordine a
prefixelor, le vom genera de la cel mai lung (întregul cuvânt) la cel mai scurt (prima literă).
Pentru a reduce dimensiunea vom înlocui la fiecare pas ultima literă cu terminatorul de şir.
#include<stdio.h>
#include<string.h>

void main()
{
int n; char cuv[128];
printf("\nIntroduceti cuvantul: ");scanf ("%s",cuv);
n=strlen(cuv);
while(n--)
{printf ("\n%s",cuv);
cuv[n]=0;
}
}

10.1.2 Stoilescu 202 Problema 2:


Să se verifice dacă un număr este palindrom. Un număr este considerat palindrom dacă citit
de la stânga la dreapta sau invers, are aceeaşi valoare. Exemple: 1221, 121, 50905.
Numărul se va converti într-un şir de caractere cu ajutorul funcţiei ltoa din biblioteca
standard, apoi şirul se caractere se va compara cu inversul său. Pentru obţinerea inversului
unui şir se va folosi funcţia strrev din biblioteca string.h.
#include <string.h>
#include <stdio.h>
#include <stdlib.h>

void main()
{
long n;
char sir1[100], sir2[100];
printf("Introduceti numarul: ");
scanf("%ld",&n);
ltoa(n,sir1,10); //transforma numarul in sir
strcpy(sir2,sir1);
strrev(sir2); //inverseaza ordinea caracterelor din sir
if(strcmp(sir1,sir2)==0)
puts("\nNumarul este palindrom!");
else
puts("\nNumarul nu este palindrom!");
}

10.1.3 Problema 5:
Fiind date n şiruri de caractere care reprezintă n cuvinte, să se determine toate perechile de
rime formate.

45
Laboratorul 10 Şiruri de caractere

Pentru aceasta se vor compara cu ajutorul funcţiei strcmp pe rând ultimele două litere ale
fiecărui cuvânt cu ultimele două litere ale celorlalte cuvinte. Dacă acestea coincid atunci se
va tipări perechea de şiruri găsită.

//Stoilescu 2.05
#include<string.h>
#include<stdio.h>

void main()
{
char a[20][20]; int i,n,j;
printf("Numarul de cuvinte: ");scanf("%d",&n);
puts("Cuvintele: ");
for(i=0;i<n;i++)
scanf("%s", &a[i]);
puts("Se formeaza rimele:");
for(i=0;i<n-1;i++)
for (j=i+1;j<n;j++)
if(strcmp(&a[i][strlen(a[i])-2], &a[j][strlen(a[j])-2]) == 0)
printf("%s------------%s\n",a[i],a[j]);
}

10.1.4 Cel mai lung cuvânt cititSă se scrie un program care citeşte o succesiune de
cuvinte şi-l afişează pe cel mai lung dintre ele.
Prin cuvânt înţelegem o succesiune de caractere diferite de caracterele albe. Vom presupune
că un cuvânt nu are mai mult de 100 de caractere. Cuvintele sunt separate prin spaţii. La
sfârşit se tastează sfârşitul de fişer (Ctrl+Z) pentru a termina succesiunea de cuvinte.
//PROGRAMUL BVIII11
#include <stdio.h>
#include <string.h>
#define MAX 100
void main () /* citeste o succesiune de cuvinte si-l afiseaza pe cel mai
lung dintre ele */
{
int max=0,i; char cuvint[MAX+1]; char cuvint_max[MAX+1];
printf("\nIntroduceti cuvintele urmate de Ctrl-Z: \n");
while(scanf("%100s",cuvint) != EOF)
if(max < (i=strlen(cuvint)))
{ max = i; strcpy(cuvint_max,cuvint);}
if(max)
printf("Cel mai lung cuvint: %s", cuvint_max);
}

Observaţii:
1. Cuvântul citit se păstrează în tabloul cuvint de MAX+1 elemente. La citire se utilizează
specificatorul de format: %100s care permite să se citească cel mult 100 de caractere diferite
de cele albe. Funcţia scanf păstrează caracterul NULL după ultimul caracter citit. Deci, un
cuvânt de 100 de caractere ocupă 101 octeţi.
2. După citirea unui cuvânt se apelează funcţia strlen pentru a determina numărul
caracterelor citite prin scanf şi păstrate în tabloul cuvint. În acest caz s-a utilizat expresia:
i = strlen(cuvint)
Apoi se compară lungimea cuvântului citit cu max.
Variabila max are ca valoare lungimea maximă a cuvintelor citite înaintea celui curent. Iniţial
max = 0, deoarece nu există nici un cuvânt citit. Dacă max este mai mic decât lungimea

46
Laboratorul 10 Şiruri de caractere

cuvântului citit curent, atunci lui max i se atribuie această valoare, iar cuvântul citit este
transferat în zona de memorie alocată tabloului cuvânt_max. În acest scop se apelează
funcţia strcpy:
strcpy(cuvint_max, cuvint);

10.1.5 Program citire şi ordonare cuvinteSă se scrie un program care citeşte două cuvinte
şi le afişează în ordine crescătoare.
Cuvântul se defineşte ca în exerciţiul precedent, adică este o succesiune de cel mult 100 de
caractere care nu sunt albe. Cuvintele sunt separate prin spaţii (caractere albe).
//PROGRAMUL BVIII12
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAX 100

void main ( ) /* citeste doua cuvinte si lc afiseaza in ordine crescatoare


*/
{
char cuv1[MAX+1]; char cuv2[MAX+1] ;
if(scanf("%100s",cuv1) != 1)
{ printf("nu s-a tastat un cuvint\n"); exit(1); }
if(scanf("%100s",cuv2) != 1)
{ printf("nu s-a tastat un cuvint\n"); exit(1); }
if(strcmp(cuv1,cuv2) < 0)
{ /* primul cuvint tastat este mai mic decit cel de-al doilea */
printf("%s\n",cuv1) ; printf("%s\n",cuv2);
}
else
{ printf("%s\n",cuv2) ; printf("%s\n",cuv1); }
}

Să se scrie un program care citeşte o succesiune de cuvinte şi-l afişează pe cel mai mare.
Prin cuvânt înţelegem o succesiune de cel mult 100 de caractere care nu sunt albe.
Cuvintele sunt separate prin caractere albe. Succesiunea de cuvinte se termină cu sfirşitul de
fişier.
//PROGRAMUL BVIII13
#include <stdio.h>
#include <string.h>
#define MAX 100

void main() /* citeste o succesiune de cuvinte si-l afiseaza pe cel mai


mare */
{
char cuv_crt[MAX+1]; char cuv_max[MAX+1];
cuv_max[0] = '\0'; /* cuv_max se initializeaza cu cuvintul vid */
while(scanf("%100s",cuv_crt) != EOF)
if(strcmp(cuv_crt,cuv_max) > 0)
/* cuvintul curent este mai mare decit cel pastrat in cuv_max */
strcpy(cuv_max,cuv_crt);
printf("cel mai mare cuvint este\n"); printf("%s\n", cuv_max);
}

47
Laboratorul 11 Tablouri multidimensionale

11. Tablouri multidimensionale

11.1 Exemple

11.1.1 Declararea unui tablou bidimensional


int mat1[2][3]; //Tablou bidimensional numit mat1 cu 2x3 elemente intregi
int mat2[10][10]; //Tablou bidimensional numit mat2 cu 10x10 elemente
reale

11.1.2 Instrucţiunile de citire a primelor m linii şi n coloane ale unei matrici


for(i=0; i<m; i++)
for(j=0; j<n; j++)
cin>>a[i] [j];

11.1.3 Instrucţiunile de scriere a primelor m linii şi n coloane ale unei matrici


for(i=0; i<n; i++,cout’\n’)
for(j=0; j<n; j++)
cout<<a[i] [j];

11.1.4 Suma a două matrici:


Programul:
#include<iostream.h>
main()
{
unsigned n,m,j,i;
float a[10][10],b[10][10],c[10][10];
cout<<“nr linii:”;cin>>n; cout<<“nr coloane:”;cin>>m;
for (i=0;i<n;i++)
for (j=0;j<m;j++)
{ cout<<“a[“<<i<<“,”<<j<<“]”; cin>>a[i][j]; }
for (i=0;i<n;i++)
for (j=0;j<m;j++)
{ cout<<“b[“<<i<<“,”<<j<<“]”; cin>>b[i][j]; }
for (i=0;i<n;i++)
for (j=0;j<m;j++)
c[i][j]=a[i][j]+b[i][j];
for (i=0;i<n;i++,cout<<’\n’)
for (j=0;j<m;j++)
cout<<c[i][j]<<’\t’;
}

11.2 Probleme propuse

Să se alcătuiască programe care să rezolve următoarele probleme:

48
Laboratorul 11 Tablouri multidimensionale

pentru j=1,n
11.2.1 Valoarea unui polinom într-un citeşte a[i][j]
punct, unde coeficienţii polinomului 3. Pentru i=1,n
sunt memoraţi într-un vector pentru j=1,p
citeşte b[i][j]
11.2.1.1 Pseudocod: 4. Pentru i=1,m
1 citeşte g,x pentru j=1,p
2 1=0 c[i][j]=0
3 cât timp i<n 5. Pentru i=1,m
3.1 citeşte p[i] pentru j=1,n
3.2 i=i+1 pentru k = 1,p
4 v=p[0], xi=x, i=1 c[i][j]= c[i][j] + a[i][k]*b[k][j]
// v - valoarea, xi - xi 6. Pentru i=1,m
5 cât timp i<n pentru j=1,p
5.1 xi=xi*x scrie c[i][j]
5.2 v=v+xi*p[i]
5.3 i=i+1
6 scrie v

11.2.2 Produsul a două polinoame

11.2.2.1 Pseudocod:
1 citeşte g1,g2
2 i=0
3 cât timp i<g1
3.1 citeşte p1[i]
3.2 i=i+1
4 i=0
5 cât timp i<g2
5.1 citeşte p2[i]
5.2 i=i+1
6 i=0
7 cât timp i<(g1+g2)
7.1 q[i]=0
7.2 i=i+1
8.i=0
9 cât timp i<g1
9.1 j=0
9.2 cât timp j<g2
9.2.1 q[i+j]= q[i+j]+p1[i]*p2[j]
9.2.2 j=j+1
9.3 i=i+1
10 i=0
11 cât timp i<g1+g2
10.1 scrie q[i]
10.2 i=i+1

11.2.3 Produsul a două matrici

11.2.3.1 Pseudocod:
1. Citeşte m,n,p
2. Pentru i=1,m

49
Laboratorul 11 Tablouri multidimensionale

11.3 ÎNTREBĂRI ŞI EXERCIŢII

11.3.1 Chestiuni teoretice


1. Care este diferenţa dintre şirurile de caractere şi vectorii de caractere ?
2. Ce sunt tablourile ?
3. De ce tablourile reprezintă date structurate ?
4. Prin ce se referă elementele unui tablou ?
5. Cine impune tipul unui tablou ?

11.3.2 Chestiuni aplicative


1. Se citesc de la tastatura elementele unei matrici de caractere (nr. linii=nr. coloane),
A(NXN), N<=10.
a) Să se afişeze matricea A;
b) Să se formeze şi să se afişeze cuvântul format din caracterele pe pe diagonala principală
a matricii A;
c) Să se calculeze şi să se afişeze numărul de litere mari, litere mici şi cifre din matrice;
d) Să se afişeze cuvântul format din caracterele de pe diagonala secundară;
e) Să se afişeze procentul literelor mari, al literelor mici şi al cifrelor de pe cele 2 diagonale;
f) Să se afişeze caracterele comune aflate pe liniile p şi q (p, q < N, p şi q citite de la
tastatură);
g) Să se afişeze în ordine alfabetică, crescătoare, literele mari aflate pe coloanele impare.
2. Se citesc de la tastatură elementele unei matrici cu elemente reale, B (N X N), N<=8.
a) Să se afişeze matricea B;
b) Să se calculeze şi să se afişeze produsul elementelor de pe coloanele impare;
c) Să se calculeze şi să se afişeze matricea A, unde: A = ( B + BT)2;
d) Să se formeze şi să se afişeze vectorul V, ale cărui elemente sunt elementele pozitive din
matricea A;
e) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în

triunghiurile haşurate:
f) Să se calculeze procentul elementelor pozitive aflate pe diagonala secundară;
g) Să se calculeze şi să se afişeze matricea C, unde: C = 3 * BT + B2;
h) Să se calculeze şi să se afişeze matricea D, unde: D = B + B2+ B3 + B4;
i) Să se interschimbe coloanele matricii A astfel: prima cu ultima, a doua cu antipenultima,
etc.
3. Se citesc de la tastatură elementele unei matrici de numere întregi C (N X N), N<=10.
a) Să se afişeze matricea C;
b) Să se calculeze şi să se afişeze procentul elementelor impare de pe liniile pare;
c) Să se calculeze şi să se afişeze matricea B, unde: B = C2;
d) Să se calculeze şi să se afişeze matricea E, unde: E = (C + CT)2 + I, unde I este matricea
unitate;
e) Să se afle elementul minim din matricea C;
f) Să se înlocuiască elementul maxim din matricea C cu valoarea val, introdusă de la
tastatură;
g) Să se afişeze elementele matricii C care sunt numere prime;
h) Să se calculeze şi să se afişeze sumele şi produsele elementelor matricii A, aflate în

triunghiurile haşurate:

50
Laboratorul 12 Pointeri şi adrese

12. Pointeri şi adrese


Există doi operatori unari care permit utilizarea variabilelor pointer:
‰ & - operatorul adresă (de referenţiere) - pentru aflarea adresei din memorie a unei variabile;
‰ * - operatorul de indirectare (de deferenţiere) - care furnizează valoarea din zona de memorie
spre care pointează pointerul operand.

Sintaxa declaraţiei unui pointer de date este:


tip *identificator_pointer;
Simbolul * precizează că identificator_pointer este numele unei variabile pointer de
date, iar tip este tipul obiectelor a căror adresă o va conţine.
Exemplu:
int u, v, *p, *q; // *p, *q sunt pointeri de date (către int)
double a, b, *p1, *q1; // *p1, *q1 sunt pointeri către date de tip double

Operatorul "*" se numeşte operatorul de referenţiere şi este aplicat unei adrese, întorcând
valoarea memorată la acea adresă.
De exemplu, în declaraţia:
int *n;
n este adresa unei variabile de tip întreg, iar *n este valoarea memorată la adresa n.
OBSERVAŢIE: Orice adresă este memorată sub forma unui număr întreg, pe 2, 4 sau 8
octeţi (în mod implicit 2)

Operatorul invers se notează "&" şi se numeşte operatorul de dereferentiere (operatorul


adresă)
De exemplu instrucţiunea: &x=y are semnificaţia: adresa lui x ia valoarea y.

12.1 Exemple

x=4; cout<<"x= "<<x<<'\n';


12.1.1 Pointeri cout<<"*ptr= "<<*ptr<<'\n';
// x si *ptr reprezinta acelasi
//Pointeri - exemple
obiect, un intreg cu valoarea 4
#include<iostream.h>
x=70; // echivalenta cu
*ptr=70;
void main()
y=x+10; // echivalenta cu
{
y=*ptr+10
int x=5, y, *ptr;
// ptr - variabila pointer catre un
int *q;
int; x,y-variabile predefinite,
q=&x;
simple, de tip int
*q=8; // echivalenta cu
x=8;
cout<<"\n\nValoarea lui x:
//q=&5; // invalida - constantele
"<<x<<"\nAdresa variabilei x este:
nu au adresa
"<<&x<<'\n';
//*x=9; // invalida - x nu este
ptr=&x;// atribuire: variabila ptr
variabila pointer
contine adresa variabilei x
//x=&y; //invalida: x nu este
cout<<"Variabila pointer ptr are
variabila pointer, deci nu poate fi
valoarea: "<<ptr<<" si adreseaza
folosita cu operatorul de indirectare
obiectul: "<< *ptr<<'\n';
y=*q+3; // echivalenta cu y=x+3;
y=*ptr; cout<<"y="<<y<<'\n'; // y=5
q=0; // seteaza x pe 0

51
Laboratorul 12 Pointeri şi adrese

q+=1; // echivalenta cu ( q)++


sau cu x++ cout<<"sir1+2="<<(sir1+2)<<"\tpsir+2="
int *r; <<(psir+2)<<'\n';
r=q; // sir1+2=rul 1 psir+2=rul 1
/* copiaza continutul lui q(adresa cout<<"*(sir1+2)="<< *(sir1+2)<<'\n';
lui x) Śn r, deci r va pointa tot // *(sir1+2)=r valoarea elementului
catre x (va conîine tot adresa lui de indice 2
x)*/ void *pv1, *pv2;
pv1=psir; pv2=sir1;
double w=3.5, *r1, *r2; r1= &w;
r2=r1; cout<<"pv1="<<pv1<<"\t&pv1="<<&pv1<<'\
cout<<"r1="<<r1<<'\t'; n';
//afiseaza valoarea pointerului
r1(adresa lui w) cout<<"pv2="<<pv2<<"\t&pv2="<<&pv2<<'\
cout<<"&r1="<<&r1<<'\t'; // n';
afiseaza adresa variabilei r1 pi=&b; pd=&v; psir=sir2;
cout<<"*r1= "<<*r1<<'\n';
double z=*r1; // cout<<"*pi="<<*pi<<"\tpi="<<pi<<"\t&pi
echivalenta cu z=w ="<<&pi<<'\n';
cout<<"z="<<z<<'\n';
} cout<<"*pd="<<*pd<<"\tpd="<<pd<<"\t&pd
="<<&pd<<'\n';

cout<<"*psir="<<*psir<<"\tpsir="<<psir
12.1.2 Legătura pointeri - şiruri de <<"\t&psir="<<&psir<<'\n';
caractere }
Să se scrie următorul program şi să se
urmărească rezultatele execuţiei acestuia.
//Pointeri si sirurie de caractere 12.1.3 Pointer la vector - ex 1
#include <iostream.h> În limbajul C, cazul parametrilor tablou
#include<conio.h> constituie o excepţie de la regula
void main(void) transferului parametrilor prin valoare.
{ Numele unui tablou reprezintă, de fapt,
textmode(3); adresa tabloului, deci a primului element
int a=-5, b=12, *pi=&a; din tablou.
double v=-2.24, *pd=&v;
char sir1[]="Sirul 1", sir2[]="Sirul
2", *psir=sir1; Să se scrie următorul program (care
ilustrează legătura dintre pointeri şi vectori)
şi să se urmărească rezultatele execuţiei
cout<<"a="<<a<<"\t&a="<<&a<<"\tb="<<b< acestuia.
<"\t&b="<<&b<<'\n';
#include <iostream.h>
cout<<"*pi="<<*pi<<"\tpi="<<pi<<"\t&pi
="<<&pi<<'\n'; void main(void)
cout<<"*pd="<<*pd<<"\tpd="<<pd<<"\t {int a[10] = {0,1,2,3,4,5,6,7,8,9};
&pd="<<&pd<<'\n'; int *pi1 = a;
int *pi2 = &a[0]; int *pi3;
cout<<"*sir1="<<*sir1<<"\tsir1="<<sir1 cout<<"a="<<a<<"&a="<<&a<<"*a="<<*a
<<"\t&sir1="<<&sir1<<'\n'; <<'\n';
// *sir1=s sir1=Sirul 1 cout<<"a+1="<<(a+1)<< " &a[1]="<<
&sir1=0xffd6 &a[1]<<'\n';
cout<<"a[1]="<<a[1]<< " *(a+1)="<<
cout<<"*sir2="<<*sir2<<"\tsir2="<<sir2 *(a+1)<<'\n';
<<"\t&sir2="<<&sir2<<'\n';
cout<<"pi1="<<pi1<<"pi2="<<pi2<<'\n
// *sir2=s sir2=Sirul 2
&sir1=0xffce ';
int x=*pi1; /* x primeste valoarea
cout<<"*psir="<<*psir<<"\tpsir="<<psir locatiei a carei adresa se afla in
<<"\t&psir="<<&psir<<'\n'; variabila pointer pi1, deci valoarea
// *psir=s psir=Sirul 1 lui a[0] */
&sir1=0xffcc cout<<"x="<<x<<'\n';

52
Laboratorul 12 Pointeri şi adrese

x=*pi1++; // x = *pi1 = a[0] = 0, void main()


iar apoi *pi1= a[1] = 1 {int a[3][3]={{5,6,7}, {55,66,77},
cout<<"x="<<x<<'\n'; {555,666,777}};
x=(*pi1)++; /* x = 1: intai clrscr();
atribuirea, apoi incrementarea valorii cout<<"a="<<a<<" &a="<<&a<<"
spre care indica pi1. &a[0]="<<&a[0]<<'\n';
In urma incrementarii, valoarea lui cout<<"Pointeri catre vectorii
a[1] devine 2 */ linii\n";
cout<<"x="<<x<<'\n'; cout<<*pi1<<'\n';
for (int i=0; i<3; i++){
x=*++pi1; //echivalent cu *(++pi1)
cout<<"x="<<x<<'\n'; cout<<" *(a+"<<i<<")="<<*(a+i);
x=++(*pi1); cout<<"x="<<x<<'\n'; cout<<" a["<<i<<"]="<<a[i]<<'\n';
pi1=a; }
pi3=pi1+3; // afişarea matricii
cout<<"pi1="<<pi1<<"*pi1="<<*pi1<<"&pi for (int i=0; i<3; i++){
1="<<&pi1<<'\n'; for (int j=0; j<3; j++)
cout<<"pi3="<<pi3<<"*pi3="<<*pi3<<"&pi cout<<*(*(a+i)+j)<<'\t'; //sau:
3="<<&pi3<<'\n'; cout<<*(a[i]+j)<<'\t';
cout<<"pi3-pi1="<<(pi3-pi1)<<'\n'; cout<<'\n';
//pi3-pi1=3 }
}
}

12.1.6 Pointer la matrice - 2


12.1.4 Pointer la vector - ex 2
//Pointer la matrice
//Pointer la vector #include <iostream.h>
#include <iostream.h> #define DIM1 3
#define DIM 3 #define DIM2 2
float cere_element(int i) float cere_element(int i,int j)
{float elem; {
cout<<"a("<<(i+1)<<")="; float elem;
cin>>elem; cout<<"\n"; cout<<"a("<<(i+1)<<","<<(j+1)<<")=";
return elem; cin>>elem;cout<<"\n";
} return elem;
void afis_tablou(float *ptablou) }
{int i;
for(i=0;i<DIM;i++) void afis_tablou(float **ptablou)
{
cout<<"a("<<(i+1)<<")="<<*(ptablou+i)< int i,j;
<"\n"; for(i=0;i<DIM1;i++)
} for(j=0;j<DIM2;j++)
cout
void main() <<"a("<<(i+1)<<","<<(j+1)<<")="<<*((*p
{ tablou)+i*DIM2+j)<<"\n";
float tablou[DIM]; }
int i;
float *ptablou; void main()
ptablou=tablou; {
cout<<"Introduceti elementele float tablou[DIM1] [DIM2];
tabloului\n"; int i,j; float *ptablou;
for(i=0;i<DIM;i++) ptablou=*tablou;
tablou[i]=cere_element(i); cout<<"Introduceti elementele
cout<<"Elementele tabloului sunt:\n"; tabloului\n";
afis_tablou(ptablou); for(i=0;i<DIM1;i++)
} for(j=0;j<DIM2;j++)
tablou[i][j]=cere_element(i,j);
cout<<"Elementele tabloului sunt:\n";
12.1.5 Pointer la matrice - 1 afis_tablou(&ptablou);
}
#include<iostream.h>
#include<conio.h>

53
Laboratorul 12 Pointeri şi adrese

12.2 ÎNTREBĂRI ŞI EXERCIŢII

12.2.1 Chestiuni teoretice


1. În ce constă operaţia de incrementare a pointerilor ?
2. Tablouri de pointeri.
3. Ce sunt pointerii generici ?
4. Ce operaţii se pot realiza asupra variabilelor pointer ?
5. De ce numele unui pointer este rvalue ?
6. Ce fel de variabile pot constitui operandul operatorului de deferenţiere ?
7. Operatorul de referenţiere.
8. Unui pointer generic i se poate atribui valoarea unui pointer cu tip ?
9. Care este legătura între tablouri şi pointeri ?
10. De ce numele unui tablou este lvalue ?

12.2.2 Chestiuni practice


1. Să se implementeze programele cu exemplele prezentate.
2. Să se scrie programele pentru exerciţiile rezolvate care au fost prezentate.
3. Analizaţi următoarele secvenţe de instrucţiuni. Identificaţi secvenţele incorecte (acolo
unde este cazul) şi sursele erorilor:
‰ int a,b,*c; a=7; b=90; c=a;
‰ double y, z, *x=&z; z=&y;
‰ char x, **p, *q; x = 'A'; q = &x; p = &q; cout<<”x=”<<x<<’\n’;
cout<<”**p=”<<**p<<’\n’; cout<<”*q=”<<*q<<’\n’;
cout<<”p=”<<p<<” q=”<<q<<”*p=”<<*p<<’\n’;
‰ char *p, x[3] = {'a', 'b', 'c'}; int i, *q, y[3] = {10, 20, 30};
p = &x[0];
for (i = 0; i < 3; i++)
{
cout<<”*p=”<<*p<<” p=”<<p<<’\n’;
p++;
}
q = &y[0];
for (i = 0; i < 3; i++)
{
cout<<”*q=”<<*q<<”q=”<<q<<’\n’;
q++;
}
‰ const char *sirul=”să programăm”; *(sirul)++;
‰ double a, *s; s=&(a+89); cout<<”s=”s<<’\n’;
‰ double a1, *a2, *a3; a2=&a1; a2+=7.8; a3=a2; a3++;
‰ int m[10], *p;p=m;
for (int i=0; i<10; i++)
cout<<*m++;
‰ void *p1; int *p2; int x; p2=&x; p2=p1;
‰ char c=’A’; char *cc=&c; cout<<(*cc)++<<’\n’;

54
Laboratorul 13 Funcţii

13. Funcţii

13.1 Structura unei funcţii

O funcţie este formată din antet şi corp:


antet_functie
{
corp_functie
}
Sau:
tip_val_return nume_func(lista_declaratiilor_param_ formali)
{
declaratii_variabile_locale
instructiuni
[return valoare] //optional
}
Antetul funcţiei conţine deci următoarele 3 elemente:
• tipul valorii returnate de funcţie
• numele funcţiei
• lista declaraţiilor parametrilor formali

O funcţie poate fi apelată printr-o construcţie urmată de punct şi virgulă, numită instrucţiune
de apel, de forma:
nume_functie (lista_parametrilor_efectivi);
Parametrii efectivi trebuie să corespundă cu cei formali ca ordine şi tip.

13.2 Transferul parametrilor unei funcţii

Funcţiile comunică între ele prin argumente (parametri). Există următoarele moduri de
transfer (transmitere) a parametrilor către funcţiile apelate:

13.2.1 Transfer prin valoare;


Exemplul devenit clasic este cel al funcţiei de permutare (interschimbare) a două variabile.
Fie funcţia vschimb definită astfel:
void vschimb (float x, float y)
{ float t=x; x=y; y=t; }

void main()
{ float a=4.7, b=9.7;
. . . . . . . . . . .
schimb(a, b); // apel functie
. . . . . . . . . . . }
Parametri funcţiei vschimb sunt transmişi prin valoare: parametrilor formali x, y li se atribuie
(la apel) valorile parametrilor efectivi a, b. Funcţia vschimb permută valorile parametrilor
formali x şi y, dar permutarea nu are efect asupra parametrilor efectivi a şi b.

55
Laboratorul 13 Funcţii

13.2.2 Transfer prin pointeri


Pentru ca funcţia de interschimbare să poată permuta valorile parametrilor efectivi, în limbajul
C/C++ parametrii formali trebuie să fie pointeri către valorile care trebuie interschimbate:

void pschimb(float *x, float *y)


{ float t=*x; *x=*y; *y=t; }

void main()

{ float a=4.7, b=9.7;


. . . . . . . . . . .
pschimb(&a, &b); // apel functie
/* SAU:
float *pa, *pb;
pa=&a; pb=&b;
pschimb(pa, pb);*/
. . . . . . . . . . . }
Se atribuie pointerilor x şi y valorile pointerilor pa, pb, deci adresele variabilelor a şi b.
Funcţia pschimb permută valorile spre care pointează pointerii x şi y, deci valorile lui a şi b.

13.2.3 Transfer prin referinţă.


În limbajul C++ acceaşi funcţie de permutare se poate defini cu parametri formali de tip
referinţă.
void rschimb(float &x, float &y)
{ float t=x; x=y; y=t; }

void main()
{ float a=4.7, b=9.7;
. . . . . . . . . . . . . . .
rschimb(a, b); // apel funcţie
. . . . . . . . . . . . . . . }
În acest caz, x şi y sunt sinonime cu a şi b (nume diferite pentru aceleaşi grupuri de locaţii de
memorie). Interschimbarea valorilor variabilelor x şi y înseamnă interschimbarea valorilor
variabilelor a şi b.

13.3 Funcţii definite de utilizator

În afară de funcţiile predefinite existente în header-ele <stdlib.h>, <math.h>,


<iostream.h>, <string.h> - există posibilitatea de a se construi noi funcţii de către
programator(utilizator).
Sintaxa definiţiei unei funcţii este:
<tip valoare returnată> <nume funcţie> (<tip parametru> [*] <nume
parametru> [,...])
{
<lista variabile auxiliare>;
<instructiuni>;
[return <variabila>;]
}
unde:
• <tip valoare returnată> - poate fi oricare din tipurile de bază sau void (tipul vid)

56
Laboratorul 13 Funcţii

• <tip parametru> - poate avea orice tip cu excepţia lui void


• [*] - este un parametru opţional, utilizat numai pentru parametrii a căror valoare se
modifică (spunem că funcţia are efecte laterale)
• <instrucţiuni> - au aceeaşi sintaxă cu cele dintr-un program, servesc la calculele
intermediare din corpul funcţiei
• <lista variabile auxiliare> - sunt variabile locale funcţiei, nu sunt văzute în afara funcţiei
instrucţiunea return este principala instrucţiune a unei funcţii, ea înseamnă returnarea de
către funcţie a rezultatului care va fi transmis programului principal sau altei funcţii care o
apelează; ea este obligatorie în toate funcţiile cu excepţia celor de tip void

Sintaxa apelului unei funcţii este:


<nume funcţie> ( <nume parametru> [,...])
deci numele funcţiei urmat de lista parametrilor între paranteze; aceştia poartă numele de
parametrii actuali iar parametrii din definiţia funcţiei se numesc parametrii formali. Este
necesar ca parametrii actuali să corespundă ca număr şi tip cu parametrii formali.

OBSERVAŢIE: De obicei funcţiile se declară şi se definesc la începutul programului, dar se


mai pot declara şi astfel: se declară la început prototipul şi apoi la sfârşit definirea =
descrierea detaliată (inclusiv prototipul).

13.4 Exemple

13.4.1 Funcţie pentru calculul void main()


maximului a două numere reale. {
float max(float x, float y) float a=4.5, b=9.3;
{ cout<<"\nInitial\ta= "<<a<<"\tb=
float a; "<<b;
if (x>y) a=x; else a=y; schimb_v(a, b); // apel
return a; functie
} cout<<"\nValoare\ta= "<<a<<"\tb=
"<<b;
schimb_p(&a, &b); // apel
13.4.2 Schimbarea valorilor a două functie
variabile - transferul parametrilor unei cout<<"\nPointer\ta= "<<a<<"\tb=
funcţii "<<b;
//Transferul parametrilor unei schimb_r(a, b); // apel
functii functie
#include<iostream.h> cout<<"\nRef\ta= "<<a<<"\tb=
"<<b;
//Transfer prin valoare }
void schimb_v (float x, float y)
{ float t=x; x=y; y=t; }
13.4.3 Minimul elementelor unui tablou
//Transfer prin pointeri Programul:
void schimb_p(float *x, float *y)
//Minimul elementelor unui tablou
{ float t=*x; *x=*y; *y=t; }
#include <iostream.h>
#define DIM 5
//Tansfer prin referinta
void schimb_r(float &x, float &y)
float min2v(float a,float b)
{ float t=x; x=y; y=t; }
{return (a<b?a:b);}

57
Laboratorul 13 Funcţii

//FUNCTIA BVIII2
int sorttab(float tablou[DIM]) int pcit_int(char text[], int *x)
{ /* - citeste un intreg si-l pastreaza
int i,indmin; float valmin; in zona de memorie a carei adresa este
valoarea lui x;
valmin=tablou[0]; indmin=0;
- returneaza:
for(i=1;i<DIM;i++) 0 - la intilnirea sfirsitului de
{ fisier;
valmin=min2v(valmin,tablou[i]); 1 - altfel */
if(valmin==tablou[i]) indmin=i; {
} char t[255];
return indmin; for( ; ; )
} {
printf(text);
void tiptab(float tablou[DIM]) if(gets(t) == NULL) return 0;
if(sscanf(t,"%d", x) == 1) return 1;
{
}
int i; }
for(i=0;i<DIM;i++)

cout<<"tabl("<<i<<")="<<tablou[i]<
<"\n"; 13.4.4.2 Să se scrie o funcţie
} (pcit_int_lim) care citeşte un întreg
de tip int care aparţine unui interval dat.
void main() Ea are parametrii:
{ text - Tablou unidimensional de t i p
float tabl [DIM]; int imin,i;
char
cout<<"introduceti elementele
tabloului\n"; int - întreg de tip int .
for(i=0;i<DIM;i++) sup - întreg de tip int.
{ pint - Pointer spre întregi de tip int; are
cout<<"tabl ("<<i<<")="; ca valoare adresa zonei de memorie în
cin>>tabl[i]; care se păstrează numărul citit.
cout<<"\n"; funcţia de faţă returnează:
} 0 - La înltâlnirea sfârşitului de fişier.
cout<<"Tabloul initial\n"; 1 - Altfel.
tiptab(tabl);
//FUNCTIA BVIII3
imin=sorttab(tabl);
int pcit_int(char[], int *); /*
cout<<"Elementul minim din tablou
prototip */
este: tabl("<<imin<<")="<<
tabl[imin]<<"\n";
int pcit_int_lim(char text[], int
}
inf, int sup, int *pint)
/* - citeste un intreg de tip int
ce apartine intervalului [inf.sup]
13.4.4 Realizarea apelului prin referinţă si-l\
utilizînd parametri de tip pointer pastreaza in zona de memorie a
carei adresa este valoarea
13.4.4.1 Să se scrie o funcţie (pcit_int) parametrului pint;
care afişează caracterele unui tablou şi - returneaza:
0 - la intilnirea sfirsilului de
citeşte un întreg de tip int.
fisier;
Funcţia are doi parametri: 1 - altfel. */
text - Tablou unidimensional de tip {
caracter. for(;;)
x - Pointer spre întregi de tip int; are ca {
valoare adresa zonei de memorie în care if(pcit_int(text, pint) == 0)
se păstrează valoarea întregului citit. return 0; /* s-a intilnit EOF */
if(*pint >= inf && *pint <= sup)
Funcţia de faţă returnează 0 la întîlnirea
return 1;
sfîrşitului de fişier şi 1 altfel.

58
Laboratorul 13 Funcţii

printf("intregul tastat nu }
apartine intervalului:");
printf("[%d,%d]\n", inf,sup);
printf("se reia citirea\n");
}

13.4.5 Operaţii cu matrici cu ajutorul prodmat[i][j]=prodmat[i][j]+mat1[i]


unor funcţii: [k]*mat2[k][j];
Programul: }
}
//Operatii cu matrici realizate cu
functii
void afisare(int nl,int nc,int
#include<iostream.h>
mat[DIM][DIM])
#include<stdio.h>
{
#define DIM 10
int i,j;
for(i=0;i<nl;++i)
void citire(int nl,int nc,int
{
mat[DIM][DIM])
for(j=0;j<nc;++j)
{
cout<<mat[i][j]<<" ";
int i,j;
cout<<"\n";
for(i=0;i<nl;++i)
}
{
}
cout<<"\n ***** Linia
"<<i<<"\n";
void main()
for(j=0;j<nc;++j)
{
{
int m1[DIM][DIM], m2[DIM][DIM],
cout<<"Introduceti elementul
sum[DIM][DIM];
["<<i<<","<<j<<"] :
int a,b,c,d,i,j; char selector;
";cin>>mat[i][j];
}
cout<<"\nIntr. nr-le de linii si
}
coloane pentru prima matrice, m:
}
";cin>>a;
cout<<"
int suma(int mat1[DIM][DIM], int
si n: ";cin>>b;
mat2[DIM][DIM],int nl,int nc,int
cout<<"\nIntr. nr-le de linii si
summat[DIM][DIM])
coloane pentru a doua matrice, m:
{
";cin>>c;
int i,j;
cout<<"
for(i=0;i<nl;++i)
si n: ";cin>>d;
{
cout<<"\n\nPrima matrice:\n";
for(j=0;j<nc;++j)
citire(a,b,m1);
cout<<"\n\nA doua matrice:\n";
summat[i][j]=mat1[i][j]+mat2[i][j];
citire(c,d,m2);
}
printf("Tastati:'s' pentru suma\n
return 0;
'd' pentru diferenta\n 'p'
}
pentru produs\nAici: ");
cin>>selector;
void prod(int mat1[DIM][DIM], int
switch (selector)
mat2[DIM][DIM], int m,int n,int
{
p,int prodmat[DIM][DIM])
case's':
{
{
int i,j,k;
if ((a==c)&&(b==d))
for(i=0;i<m;++i)
{
for(j=0;j<n;++j)
suma(m1,m2,a,b,sum);
{
afisare(a,b,m1);
prodmat[i][j]=0;
cout<<"\n +\n\n";
for(k=0;k<p;++k)
afisare(c,d,m2);
cout<<"\n=\n";

59
Laboratorul 13 Funcţii

afisare(c,d,sum); /*Functia citeste valorile


} elementelor unei matrici */
else void citire (float ta[NMAX][NMAX],
cout<<"Nu se poate efectua int ordin, char numev)
suma deoarece numerele de linii si {
coloane au nereguli"; float temp;
break; printf("\nElementele matricii
} %c\n",numev);
case'd': for (int i = 1,j; i<ordin+1;
{ i++)
cout<<"FACETI VOI DIFERENTA"; for(j=1; j<ordin+1; j++)
break; {
} printf("%c[%d,%d]=
case'p': ",numev,i,j);
{ scanf ("%f",&temp);
if(b==c) ta[i][j]=temp;
{ }
prod(m1,m2,a,d,b,sum); }
afisare(a,b,m1); /*Functia scrie valorile
cout<<"\n*\n\n"; elementelor unei matrici */
afisare(c,d,m2); void scriere(float ta[NMAX][NMAX],
cout<<"\n=\n\n"; int ordin, char numev)
afisare(a,d,sum); {
} int trec;
break; printf("\nAfisarea valorii
} elementelor pentru matricea
default: cout<<"Nu s-a introdus %c:\n",numev);
una din literele cerute !"; trec=1;
} for(int i=1,j; i<ordin+1; i++)
} for(j=1; j<ordin+1; j++)
{
printf("%c[%d,%d]= %f",numev,
13.4.6 Calculul puterii şi transpusei unei i,j,ta[i][j]);
matrici pătrate if(trec++==ordin)
{printf("\n"); trec=1;}
Să se alcătuiască un program pentru else printf("\t");
ridicarea la putere a unei matrici pătratice şi }
pentru calculul transpusei acesteia. printf("\nApasa orice
tasta!");getch();
13.4.6.1 Strategia de rezolvare: }
în cazul matricilor pătratice A(n,n) numărul
/*Functia efectueaza ridicarea la
de linii şi de coloane este egal cu ordinul
patrar, a unei matrici */
matricii. Transpusa se obţine prin void patrat(float
interschimbarea elementelor din partea ta[NMAX][NMAX],float
dreaptă a diagonalei principale cu cele tb[NMAX][NMAX], int ordin)
având indicii liniei şi coloanei inversaţi. {
for (int i=1,j,k; i<ordin+1; i++)
/* Program 14. for(k=1; k<ordin+1; k++)
Ridicarea la o putere a unei {
matrici patratice. Calculul tb[i][k]=0.0;
transpusei unei matrici for(j=1; j<ordin+1; j++)
patratice.*/
#define NMAX 20 // Numarul maxim de tb[i][k]+=ta[i][j]*ta[j][k];
linii sau coloane al matriciilor }
#include <stdio.h> }
#include <conio.h>

60
Laboratorul 13 Funcţii

/*Functia calculeaza transpusa unei stochează valoarea uneia dintre variabilele


matrici*/ ce trebuiesc interschimbate:
void transpusa(float temp=ta[i][j];
ta[NMAX][NMAX], int ordin) ta[i][j]=ta[j][i];
{ ta[j][i]=temp;
float temp; Dacă am fi aplicat direct relaţia:
for(int i=1,j; i<ordin; i++) ta[i][j]=ta[j][i];
for(j=i+1; j<ordin+1; j++) valoarea variabilei ta[i][j] s-ar fi pierdut
{ fiind înlocuită cu cea a variabilei ta[j][i] şi
temp=ta[i][j]; astfel (valoarea variabilei ta[j][i] nefiind
//interschimba valorile a doua modificată) matricea ar fi fost alterată,
variabile de tip float
devenind simetrică faţă de diagonala
ta[i][j]=ta[j][i];
ta[j][i]=temp; principală.
} în apelul funcţiei pătrat o scriere de tipul:
} pătrat(a,a,n); nu ar fi dus la calculul
pătratului matricii a ci la alterarea valorilor
void main(void) elementelor acesteia. în cazul şirurilor,
{ //Functia principala aceeaşi variabilă şir nu poate constitui
float a[NMAX][NMAX], pentru o funcţie şi argument "valoare" şi
b[NMAX][NMAX]; int n; argument "variabilă".
clrscr();
printf("Ordinul matricii A = ");
scanf("%d",&n);
citire(a,n,'A'); 13.5 Probleme propuse
patrat(a,b,n);
puts("\nMatricea B=A*A: ");
scriere(b,n,'B'); 1. Să se realizeze un program care
transpusa(b,n); implementează operaţii cu vectori utilizând
puts("\nMatricea transpusa:"); funcţii (citire, scriere, produs scalar, sortare)
scriere(b,n,'B'); 2. Să se realizeze un program care
} calculează valoarea unui polinom utilizând
o funcţie pentru calculul puterii
Pentru ca elementele matricii să nu se
piardă în timpul operaţiei de transpunere,
se utilizează o variabilă intermediară care

61
Laboratorul 14 Funcţii - continuare

14. Funcţii - continuare


b
14.1.1 Calculul derivatei unei funcţii I=⌠
⌡f(x) dx =
Derivata unei funcţii într-un punct a
reprezintă panta tangentei la graficul f(a)+f(b)
funcţiei în punctul respectiv, adică: = h⎡ +f(a+h) +f(a+2h)+…f(a+(n-1)h)⎤ ,
⎣ 2 ⎦
f(x) - f(x-h) b-a
f'(x) = lim h unde: h= n , n fiind numărul de diviziuni
h→0
f(x)
//Calculul derivatei unei functii
#include <stdio.h>
#include <math.h>

double fd(double);
double
deriv(double,double,double(*)(doub
le));

void main() x
{
h
double d,x,h;
printf("\nx= "); a x1 x2 xn-1 b
scanf("%lf",&x);
for(h=0.1;h>=1e-06;h/=10)
{ 14.1.2.1 Programul:
d=deriv(x,h,fd);
printf("\nx=%f; h= %f; d= //Calculul integralei prin metoda
%lf",x,h,d); trapezelor
} #include <stdio.h>
printf("\nx=%f; d= #include <math.h>
%lf",x,-sin(x));
} double fc(double);
double
double deriv(double x,double ing(double,double,double(*)(double
h,double (*f)(double)) ));
{
double it; void main()
it=((*f)(x)-(*f)(x-h))/h; {
return it; double i,a,b;
} printf("\nLimitele a,b: ");
scanf("%lf %lf",&a,&b);
double fd(double x) i=ing(a,b,fc);
{ printf("\na=%f; b=%f; i=
return cos(x); %lf",a,b,i);
} }

double ing(double x,double


y,double (*f)(double))
14.1.2 Calculul integralei definite a unei
{
funcţii prin metoda trapezelor int n=120,k;
Relaţia de calcul: double it,h,S;
h=(y-x)/n;
for(k=1,S=0.0;k<n;k++)

62
Laboratorul 14 Funcţii - continuare

S=S+(*f)(x+k*h); double fc(double x)


it=(h/2)*((*f)(x)+(*f)(y))+h*S; {
return it; return x*x;
} }

14.2 Funcţii predefinite

14.2.1 Biblioteca matematică (math.h)


Este bibliotecă care conţine toate funcţiile matematice. Unele dintre cele mai utilizate sunt
prezentate în următorul tabel:
Nume Sintaxa Ce returneaza Exemplu
abs double abs (double x) valoarea #include <iostream.h>
absolută a unui #include <math.h>
număr real void main(void)
{ int number = -1234;
cout<<"valoarea absoluta a
nr."<<number<<‘=‘<<abs(number));}
sqrt double sqrt (double x) radical
acos double acos (double arccosinus
x)
asin double asin (double x) arcsinus
cos double cos (double x) cosinus (la toate #include <iostream.h>
funcţiile #include <math.h>
trigonometrice void main(void)
argumentul e în { double result, x = 0.5; result = cos(x);
radiani) cout<<"cos("<<x<<”)=“<<result);}
cosh double cosh (double cosinus
x) hiperbolic
exp double exp (double x) exponenţiala
floor double floor (double rotunjire prin
x) lipsă
ceil double ceil (double x) rotunjire prin
adaus
fmod double fmod (double restul împărţirii #include <stdio.h>
x,double y) lui x la y #include <math.h>
void main(void)
{ double x=5.0, y = 2.0; double result;
result=fmod(x,y);
cout<<"restul lui"<<x<<“la”<<y<<‘=‘<<result;}
hypot double hypot (double ipotenuza
x,double y) triunghiului de
catete x şi y
ldexp double ldexp(double calculează #include <stdio.h>
x, int exp); produsul dintre #include <math.h>
primul parametru int main(void)
şi 2 la puterea { double value; double x=7;
dată de cel de al /* ldexp ridica 2 la puterea 3 apoi inmulteste
rezultatul cu 7*/
doilea parametru
value = ldexp(x,3); cout<<"ldexp="<<value;}
log double log(double x); logaritm natural

63
Laboratorul 14 Funcţii - continuare

Nume Sintaxa Ce returneaza Exemplu


log10 double log10(double logaritm zecimal
x);
pow double pow(double x, puterea unui
double y); număr la alt
număr
pow1 double pow10(int p); puterea lui 10 la
0 un număr întreg
sin double sin(double x); sinus
sinh double sinh(double x); sinus hiperbolic sinh(x) = (ex - e-x)/2
tan double tan(double x); tangenta
tanh double tanh(double tangenta
x); hiperbolică

14.2.2 Biblioteca string.h


Conţine funcţii pentru şiruri de caractere
Nume Sintaxa Ce face Exemplu
strcat strcat(s1, Concatenează şirul #include <string.h>
s2) s2 la sfârşitul şirul s1 #include <stdio.h>
int main(void)
{
char destination[25];
char *blank = " ", *c = "C++",
*turbo = "Turbo";
strcpy(destination, turbo);
strcat(destination, blank);
strcat(destination, c);
printf("%s\n", destination);
}
strcmp strcmp(s1, Comparare de şiruri; #include <string.h>
s2) #include <stdio.h>
dă valoarea 0 dacă
s1=s2, negativ dacă int main(void)
s1<s2 şi pozitiv dacă {
s1>s2. char *buf1 = "aaa", *buf2 = "bbb",
*buf3 = "ccc";
int ptr;

ptr = strcmp(buf2, buf1);


if (ptr > 0)
printf("buffer 2 is greater than
buffer 1\n");
else
printf("buffer 2 is less than
buffer 1\n");

ptr = strcmp(buf2, buf3);


if (ptr > 0)
printf("buffer 2 is greater than
buffer 3\n");
else
printf("buffer 2 is less than
buffer 3\n");
}
strcpy strcpy(s1, Copiază şirul s2 în s1 #include <stdio.h>
s2) #include <string.h>

int main(void)
{

64
Laboratorul 14 Funcţii - continuare

Nume Sintaxa Ce face Exemplu


char string[10]; char *str1 =
"abcdefghi";
strcpy(string, str1);
printf("%s\n", string);
}
strlen strlen(s1) Determina lungimea #include <stdio.h>
#include <string.h>
sirului s1
int main(void)
{
char *string = "Borland
International";
printf("%d\n", strlen(string));
}

14.2.3 Biblioteca stdlib


Conţine funcţiile de conversie; le vom prezenta în următorul tabel:
Nume Sintaxa Ce face Exemplu
atof double atof(const conversia unui şir la
char *s); real dublă precizie
atol long atol(const conversia unui şir la #include <iostream.h>
char *s); #include<stdlib.h>
întreg long
void main (void) { long l;
char* str=“9876”;
l=atol(str);
cout<<“atol(“<<str<<“)=“<<l
;}
atoi int atoi(const conversia unui şir la
char *s); întreg simplu
itoa char* itoa(int conversia unui întreg #include <stdlib.h>
value;char* #include <iostream.h>
la şir de caractere cu
void main(void) { int
string;int lungimea dată de al n=123; char str[5];
radix); treilea parametru itoa(n,str,4);
cout<<“itoa(“<<n<<“)=“<<str
;}
ltoa char* ltoa(long conversia unui întreg
value;char* long la şir de caractere
string;int cu lungimea dată de al
radix); treilea parametru
ultoa char* conversia unui întreg
ultoa(unsigned unsigned long la şir de
long value;char* caractere cu lungimea
string;int dată de al treilea
radix); parametru
ftoa char* ftoa(float conversia unui real
value;char* dublă precizie la şir de
string;int caractere cu lungimea
radix); dată de al treilea
parametru
rand int rand(void) generează un număr #include <stdlib.h>
#include <iostream.h>
aleator cuprins între 0
void main(void) { int i;
şi 10000 cout<<“zece nr aleatoare de
la 0 la 99”; for (i=0;
i<10; i++)
cout<<rand()%100<<‘\n’;}
random int rand(int num) generează un număr

65
Laboratorul 14 Funcţii - continuare

Nume Sintaxa Ce face Exemplu


aleator cuprins între 0
şi num-1
system void system(char* lansează în execuţie o #include <stdlib.h>
string) #include <iostream.h>
comandă DOS
void main(void) {
cout<<“Continutul
directorului curent:\n”;
system("dir");}

14.3 Biblioteci de funcţii scrise de către utilizator

În cazul folosirii mai frecvente a anumitor funcţii, acestea pot fi scrise grupat într-un fişier
bibliotecă, şi apelate apoi ori de câte ori este nevoie.
Programul următor apelează funcţia suma, care se găseşte într-un fişier header User_Lib.H
//Biblioteci de functii
#include "USER_LIB.H"
void main()
{
int a=2,b=3,c;
//functia suma se gaseste in fisierul antet USER_LIB.H
c=suma(a,b);
}

Biblioteca de funcţii este un fişier header/antet (cu extensia h) scris de către utilizator, căruia
îi pot fi adăugate funcţii după nevoie.
#ifndef _USER_LIB_
#define _USER_LIB_

int suma(int x,int y)


{return x+y;}

#endif

14.4 Exemple

cout<<"\nvaloarea lui "<<10<<" la


14.4.1 Exemplul 1: Funcţii din biblioteca puterea "<<b<<" este: "<<pow10(b);
matematică cout<<"\nvaloarea log nat din
"<<b<<" este: "<<log(b);
//Functii din biblioteca matematica cout<<"\nvaloarea log zecimal din
#include<math.h> "<<b<<" este: "<<log10(b);
#include<iostream.h> cout<<"\nvaloarea lui e la
#include<stdio.h> puterea "<<b<<" este: "<<exp(b);
cout<<"\nvaloarea lui "<<a<<"*2
main() la "<<b<<" e: "<<ldexp(a,b);
{ cout<<"\nvaloarea absoluta a nr
float a,b,c,d;
real "<<b<<" este: "<<fabs(b);
cout<<"introduceti a: ";cin>>a;
cout<<"\nvaloarea partii intregi
cout<<"introduceti b: ";cin>>b;
a nr real "<<b<<" este:
cout<<"\nvaloarea lui "<<a<<" la
"<<floor(b);
puterea "<<b<<" este: "<<pow(a,b);

66
Laboratorul 14 Funcţii - continuare

} cout<<”str1=”<<str1<<”
str2=”<<str2<<’\n’;
difer=strcmp(str1, str2);
14.4.2 Operaţii cu şiruri de caractere if (difer == 0)
cout<<”Siruri echivalente!\n”;
#include <iostream.h> else if (difer>0)
#include <string.h> cout<<str1<<” mai mare
void main() (lexicografic) decât
{ “<<str2<<’\n’;
char sir1[] = ”abcd”, sir2[] = else
”abcde”, sir3 = "abcdef”, sir4 = cout<<str1<<” mai mic
"de”; (lexicografic) decât
cout<<strcmp(sir1, sir2)<<’\n’; // “<<str2<<’\n’;
afisare:-101 cout<<”str1=”<<str1<<’\n’;
// ’e’ = 101, ’a’ = 97, ’d’ = 100 cout<<”str3=”<<str3<<’\n’;
//’0’ - ’e’ = -101 strcpy (str3, str1);
cout<<strcmp(sir2, sir1)<<’\n’; cout<<”str1=”<<str1<<’\n’;
//afisare: 101 cout<<”str3=”<<str3<<’\n’;
cout<<strcmp(sir1, "")<<’ '; strcat (str3, str1);
//compararea variabilei sir1 cu cout<<”str1=”<<str1<<’\n’;
constanta sir vid cout<<”str3=”<<str3<<’\n’;
char str1[20]=”hello”; }
char str2[20]=”goodbye”;
char str3[20];
int difer, lungime;

67

You might also like