Documente Academic
Documente Profesional
Documente Cultură
LIMBAJE DE PROGRAMARE
CAPITOLUL 1.
Exemple de propoziţii:
1) În orice triunghi suma unghiurilor sale este egală cu 180o;
2) 3+2=5;
3) 2>5;
4) Balena este un mamifer.
5) Planeta Saturn este satelit al Pamântului.
De obicei se vor nota propoziţiile prin litere mici: p,q,r ... şi cu v(p), v(q),
1
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
v(p) v(!p)
1 0
0 1
0 0 0
0 1 0
1 0 0
1 1 1
0 0 0
0 1 1
Implicaţia propoziţiilor. Să 1considerăm
0 1
propoziţia compusă (p)Vq a cărei
1 1 1
valoare de adevăr rezultă din tabela urmatoare
0 0 1 1
0 1 1 1
1 0 0 0
1 1 0 1
0 0 1 1 1
0 1 1 0 0
1 0 0 1 0
1 1 1 1 1
3
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
Proprietăţi:
∨ 0 1
0 0 1
1 1 1
DEFINIŢIA 1.4. Operaţia binară notată ∧ sau ⋅, definită prin tabelul 3.2. se
numeşte conjuncţie.
∧ 0 1
0 0 0
1 0 1
DEFINIŢIA 1.5. Operaţia unară notată ! definită prin tabelul 3.3. se numeşte
negaţie.
x !x
0 1
1 0
5
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
DEFINIŢIA 1.7. Operaţia binară notată ⊕, definită prin tabelul 1.4. se numeşte
suma modulo 2 sau sau-exclusiv.
⊕ 0 1
0 0 1
1 1 0
Vom nota prin B2n produsul cartezian al mulţimii B2 cu ea însăşi de n ori. Deci
B2n = B2×B2×...×B2.
Un n-uplu x = (x1, x2, ..., xn) ∈ B2n va fi numit punct din B2n. Prin f(x) =
6
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
Prin yi ∈ B2, i ∈ {0, 1, ... , 2n-1 } am notat valorile funcţiei f în toate punctele din
B2n.
De exemplu, se poate defini astfel funcţia booleană de trei variabile din tabelul
1.6.
a B c f(a,b,c)
0 0 0 0
0 0 1 0
0 1 0 1
0 1 1 1
1 0 0 0
1 0 1 0
1 1 0 1
7
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
1 1 1 0
R1. Pentru fiecare linie din tabel pentru care yi=1 se va construi un
termen conjunctiv în conformitate cu regula R2. Termenii conjunctivi se vor
lega între ei prin operatori de disjuncţie.
Cei trei termeni conjunctivi corespund liniilor y2, y3 şi y6. Valorile celor trei
variabile în aceste linii sunt respectiv 010, 011 şi 110. Aplicând cele trei reguli,
se obţine formula de mai sus.
După cum este cunoscut din calculul propoziţiilor, o funcţie booleană
8
www.cartiaz.ro – Carti si articole online gratuite de la A la Z
poate avea mai multe reprezentări prin expresii. Acelaşi calcul al propoziţiilor
defineşte diverse forme normale şi descrie metode de simplificare a expresiilor
care reprezintă funcţii booleene. Obţinerea unei expresii prin regulile R1-R3 de
mai sus conduce la forma normală disjunctivă perfectă.
9
CAPITOLUL 2.
SISTEME ŞI BAZE DE NUMERAŢIE
I, V, X, L, C, D, M
care corespund valorilor: unu, cinci, zece, cincizeci, o sută, cinci sute, respectiv
o mie.
49 = IL = LIC
Alte neajunsuri ale acestui mod de scriere: numerele mari sunt în general
lungi şi adesea de necuprins cu privirea, iar operaţiile aritmetice cu aceste
semne sunt foarte anevoioase.
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
10
2.2. Sisteme poziţionale de numeraţie în diverse baze
TEOREMA 2.1. Pentru orice număr natural nenul x, există în mod unic un
număr natural n numit rang şi n+1 numere naturale c0, c1, ... cn numite cifre în
baza b, care satisfac relaţiile:
bn ≤ x < bn+1
Acest număr n este cel din enunţul teoremei. În continuare, vom aplica
inducţia completă după n.
x = y⋅b + r, cu 0 ≤ r < b
Vom pune acum c0 = r, care este determinat în mod unic. Dacă bn+1 ≤ x <
bn+2, rezultă că bn ≤ y < bn+1. Pentru y este valabilă ipoteza de inducţie, deci
pentru el există n+1 cifre, pe care le vom nota c1, c2, ..., cn+1 şi care sunt de
asemenea unic determinate. Rezultă că avem:
11
şi că sunt verificate celelalte două relaţii din teoremă. Cu aceasta, teorema
este complet demonstrată.
Să ataşăm acum fiecărui număr din mulţimea { 0, 1, ..., b-1 } câte un
simbol (caracter, semn etc.) în aşa fel, încât la numere diferite să ataşăm
simboluri diferite. Convenim, de asemenea, că atunci când ne referim la o cifră
ci, să-i scriem de fapt simbolul Ci asociat numărului ci. Cu aceste convenţii (şi
cu ipoteza că simbolurile "(" şi ")" nu reprezintă cifre, avem reprezentarea
numărului x în baza b:
(CmCm-1...C1C0)b
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F
ultimele şase simboluri, de fapt primele şase litere ale alfabetului, scrise fie cu
majuscule fie cu minuscule, desemnează numerele 10, 11, 12, 13, 14 şi 15 ca
cifre în baza 16.
Din raţiuni de scriere comodă, şi pentru evitarea unor confuzii,
simbolurile de cifre dintr-o anumită bază sunt preluate în bazele de
numeraţie superioare. Astfel, în orice bază de numeraţie cu b ≤ 16 se
folosesc simbolurile indicate mai sus, fiecare simbol indicând acelaşi număr,
indiferent de bază. De exemplu, în baza 7 se folosesc simbolurile 0 ÷ 6, iar
12
în baza 13 se folosesc simbolurile 0 ÷ 9, A ÷ C; simbolul B este cifră doar
începând cu baza 12 şi reprezintă cifra care are valoarea 11.
DEFINIŢIA 2.1. Reprezentarea unui număr real x > 0 în baza b este (şi se
scrie):
x = (cncn-1...c1c0,c-1c-2c-3...)b
dacă sunt îndeplinite condiţiile:
1) x = cnbn+cn-1bn-1+...+c1b+c0+c-1b-1+c-2b-2+c-3b-3...
2) ci ∈ {0,1,...,b-1} , ∀ i ∈ {n,...,1,0,-1,-2,-3,...}
3) cn ≠ 0
4) ∀ k≤ 0 ∃ j < k astfel, încât cj < b-1
TEOREMA 2.2. Fiind dată o bază de numeraţie b, pentru orice număr real x >
0 există o reprezentare unică în baza b conform definiţiei 4.1. Numărul:
13
(cncn-1...c1c0)b
(0,c-1c-2c-3...)b
Citind ultima coloană din tabelul 2.1 de jos în sus, obţinem rezultatul
conversiei:
(985437)10 = (33042113)6
Deîmpărţit Impărţitor Cât Rest Simbol
n (baza 10) (q) (baza 10) (cn) cifră (Cn)
(baza 10) (baza 10) (baza 6)
0 985437 6 164239 3 3
1 164239 6 27373 1 1
2 27373 6 4562 1 1
3 4562 6 760 2 2
4 760 6 126 4 4
5 126 6 21 0 0
6 21 6 3 3 3
7 3 6 0 3 3
În fine, aplicăm aceeaşi metodă pentru a trece din baza 6 în baza 16, cu
calculele făcute în baza 6. Tabelul 2.3 redă aceste calcule, toate numerele din
tabel fiind în baza 6.
16
2.2.3.2. Conversia părţilor fracţionare prin înmulţiri succesive
0 43359375
.8
3 46875
3 75
6 0
În continuare vom converti tot în baza 8 numărul 0,51437, dar vom reţine
numai trei cifre după virgulă:
0 51437
⋅8
17
4 11496
0 91968
7 35744
- ----
0 45
⋅8
3 60
4 8
6 4
3 2
1 6
4 8
6 4
3 2
1 6
- --
0 8 5
⋅ 16
13 6 0
9 6
9 6
- ---
Observaţii:
18
observă apariţia perioadei. Dacă conversia se face cu ajutorul calculatorului,
depistarea perioadei este dificilă, motiv pentru care se foloseşte doar prima
sau a doua condiţie de oprire.
0 4631
⋅ (12)8
5 7772
11 7704 ; (11)8 = (9)10
11 6650
10 422 ; (10)8 = (8)10
5 264
3 410
-- -----
20
stânga şi din dreapta virgulei zecimale şi să evidenţiem astfel câteva triade:
Se observă că numerele:
este un număr de trei cifre în baza 2, deci un număr între 0 şi 7. Altfel spus, o
astfel de paranteză este o cifră în baza 8. Vom nota cu ri , cu i = l / 3
această cifră.
(110100101010,00111101)2 = (D2A,3D)16
Este evident că cel mai simplu mod de a face conversii între aceste două
baze de numeraţie este acela al folosirii bazei 2 ca intermediar. Pentru a nu
opera cu şiruri nesfârşite de cifre binare, facem următoarele recomandări:
- Pentru trecerea din baza 8 în baza 16, se grupează la stânga şi dreapta
virgulei, câte 4 cifre octale. Acestea vor fi transformate mai întâi în 12 cifre
binare, care apoi vor fi transformate în 3 cifre hexazecimale.
- Pentru trecerea din baza 16 în baza 8, se procedează analog, adică se
grupează la stânga şi dreapta virgulei, câte 3 cifre hexazecimale. Acestea vor fi
transformate mai întâi în 12 cifre binare, care apoi vor fi transformate în 4 cifre
octale.
( 2735 4357, 3576 )8 = (010 111 011 101 100 011 101 111 , 011
101 111 110)2 =
(0101 1101 1101 1000 1110 1111 , 0111 0111 1110 )2 = ( 5DD
8EF , 77E )16
23
CAPITOLUL 3.
CODIFICAREA INFORMAŢIEI
Prin A+ vom nota mulţimea tuturor cuvintelor ce se pot forma cu litere din A.
Deci
24
A+ = A ∪ A2 ∪ ... ∪ An ∪ ...
DEFINIŢIA 3.2. Un cod pentru care toate cuvintele de cod au aceeaşi lungime
n se numeşte uniform, iar n se numeşte lungimea codului. În acest caz avem
că
C : S → An
a .- n -. 1 .----
ă .-.- o --- 2 ..---
25
b -... ö ---. 3 ...--
c -.-. p .--. 4 ....-
d -.. q --.- 5 .....
e . r .-. 6 -....
f ..-. s ... 7 --...
g --. ş ---- 8 ---..
h .... t - 9 ----.
i .. u ..- 0 -----
j .--- ü ..-- . ......
k -.- v ...- , .-.-.-
l .-.. w .-- ; -.-....
m -- x -..- : ---...
y -.-- ? ..--..
z --.. ! --..--
C : S → C(S) ⊆ A+
este bijectivă. În acest caz problema decodificării se pune astfel: fiind dat un
cuvânt w ∈ A+ să se determine si ∈ S astfel încât C(si) = w sau să se
răspundă că nu există un astfel de si. Cu alte cuvinte, trebuie evaluată în w
funcţia:
C-1 : C(S) → S
S = { 0, 1, ..., 9 } şi A = { 1, 2, 3 }
0 1 2 3 4 5 6 7 8 9
11 12 212 222 31 321 322 211 3321 3312
Fie S = { _, a, b, . . ., z, A, B, . . ., Z, 0, 1, . . ., 9, +, ., ;, :, $, . . .} mulţimea
caracterelor tipăribile, existente la fiecare imprimantă, tastatură etc.
Pentru codificarea acestor caractere în vederea prelucrării lor automate,
standardele internaţionale impun o serie de restricţii. După cum se va vedea,
aceste restricţii sunt benefice pentru prelucrarea automată a caracterelor.
Să considerăm mulţimile: l mulţimea literelor mici ale alfabetului latin, L
mulţimea literelor mari (în aceste mulţimi nu intră caracterele româneşti ă, â, î,
ş, ţ), c mulţimea cifrelor zecimale, s mulţimea caracterelor speciale (spaţiul îl
vom nota cu _), iar f mulţimea caracterelor funcţionale, cele care nu apar la
tipărire (afişare), ci doar dirijează tipărirea (afişarea). Aşadar:
27
l = { a, b, ..., z }, L = { A, B, ..., Z },
c = { 0, 1, ..., 9 }, s = { _, +, ;, :, $, ... },
f = {CR, LF, TAB, FF, BEL, BS, . . . }
C: S → [0,m] ,
unde m este 127 sau 255. Dacă considerăm reprezentarea binară, avem de-a
face cu un cod uniform pe 7 biţi, respectiv pe 8 biţi. Având în vedere faptul că
octetul este unitatea de adresare a memoriei, codul pe 7 biţi se extinde la 8 biţi
punând 0 la bitul cel mai semnificativ. Deci codificarea unui caracter este un
număr care încape pe un octet.
0 00 NUL 32 20 64 40 @ 96 60 `
1 01 SOH 33 21 ! 65 41 A 97 61 a
2 02 STX 34 22 " 66 42 B 98 62 b
3 03 ETX 35 23 # 67 43 C 99 63 c
4 04 EOT 36 24 $ 68 44 D 100 64 d
5 05 ENQ 37 25 % 69 45 E 101 65 e
6 06 ACK 38 26 & 70 46 F 102 66 f
7 07 BEL 39 27 ' 71 47 G 103 67 g
8 08 BS 40 28 ( 72 48 H 104 68 h
9 09 TAB 41 29 ) 73 49 I 105 69 I
10 0A LF 42 2A * 74 4A J 106 6A j
11 0B VT 43 2B + 75 4B K 107 6B k
28
12 0C FF 44 2C , 76 4C L 108 6C l
13 0D CR 45 2D - 77 4D M 109 6D m
14 0E SO 46 2E . 78 4E N 110 6E n
15 0F SI 47 2F / 79 4F O 111 6F o
16 10 DLE 48 30 0 80 50 P 112 70 p
17 11 DC1 49 31 1 81 51 Q 113 71 q
18 12 DC2 50 32 2 82 52 R 114 72 r
19 13 DC3 51 33 3 83 53 S 115 73 s
20 14 DC4 52 34 4 84 54 T 116 74 t
21 15 NAK 53 35 5 85 55 U 117 75 u
22 16 SYN 54 36 6 86 56 V 118 76 v
23 17 ETB 55 37 7 87 57 W 119 77 w
24 18 CAN 56 38 8 88 58 X 120 78 x
25 19 EM 57 39 9 89 59 Y 121 79 y
26 1A SUB 58 3A : 90 5A Z 122 7A z
27 1B ESC 59 3B ; 91 5B [ 123 7B {
28 1C FS 60 3C < 92 5C \ 124 7C |
29 1D GS 61 3D = 93 5D ] 125 7D }
30 1E RS 62 3E > 94 5E ^ 126 7E ~
31 1F US 63 3F ? 95 5F _ 127 7F _
4. Intervalele:
[C('a') , C('z')],
[C('A') , C('Z')],
[C('0') , C('9')]
31
CAPITOLUL 4.
Algoritmică şi programare
4.1. Algoritm
33
Pentru marcarea începutului descrierii unui algoritm se
foloseşte propoziţia standard:
SFÂRŞIT ALGORITM.
34
unde condiţie este de obicei o expresie relaţională sau
logică iar S este un grup de propoziţii standard (poate fi şi
doar o propoziţie standard).
Execuţie:
1) Se evaluează condiţia;
2) Dacă condiţia este adevărată atunci se execută S şi se trece
la propoziţia următoare; dacă condiţia nu este îndeplinită
(falsă) atunci se trece automat la propoziţia următoare.
Execuţie:
1) Se evaluează condiţia;
2) Dacă condiţia este adevărată atunci se execută S1 şi se
trece la propoziţia următoare; dacă condiţia nu este
adevărată (falsă) atunci se execută S2 şi se trece la
propoziţia următoare.
Alternativa generalizată se descrie prin propoziţia standard:
SELECTEAZĂ i DINTRE
V1 : S1;
V2 : S2;
. . .
Vn : Sn
SFÂRŞITSELECTEAZĂ
Execuţie:
1) Dacă valoarea lui i este egală cu Vi atunci se execută
secvenţa Si.
2) Se dă controlul propoziţiei de după SFÂRŞITSELECTEAZĂ.
Execuţie:
1) Se evaluează condiţia;
2) Dacă condiţia este adevărată atunci se execută S şi se reia
35
evaluarea condiţiei; dacă condiţia nu este adevărată atunci
se trece la propoziţia imediat următoare.
REPETĂ
S;
PÂNĂCÂND condiţie;
SFÂRŞITREPETĂ;
Execuţie:
1) Se execută S;
2) Dacă condiţia este falsă se reia execuţia S; dacă condiţia
este adevărată atunci se trece la propoziţia imediat
următoare.
S;
CÂTTIMP not condiţie EXECUTĂ
S;
SFÂRŞITCÂTTIMP;
contor:=liminiţială;
REPETĂ
S;
contor:=contor+pas;
PÂNĂCÂND (contor > limfinală şi pas > 0) sau (contor <
limfinală şi pas < 0)
SFÂRŞITREPETĂ;
36
Execuţie:
1) Se iniţializează contorul cu liminiţială;
2) Se execută S; şi se incrementează contorul cu pas (dacă
pasul este 1 nu este obligatoriu să fie pus în evidenţă, e
implicit);
3) Se testează dacă contorul nu depăşeşte limita finală şi se
reia punctul 2); dacă contorul depăşeşte limita finală
atunci se trece controlul la propoziţia următoare.
Exemple:
1) Să se determine dacă un număr natural, n este palindrom sau
nu. Precizăm că un număr este palindrom dacă valoarea sa
este egală cu valoarea oglinditului său (citit de la dreapta
spre stânga).
prima abordare
a doua rafinare
1) directive de preprocesare 2)
directive de preprocesare
void main(void)
void main(void)
{ declaraţii
{ declaraţii
instrucţiuni
instrucţiuni
}
}
implementare funcţia f1
. . .
implementare funcţia fn
40
program celelalte elemente fiind optionale. Pentru ca o
anumită funcţie să poată fi apelată e necesar ca ea să aibă
declarat prototipul dacă implementarea (definiţia) ei se află
după funcţia main (exemplul 1). Dacă funcţia principală se
află la sfârşitul fişierului atunci nu mai e necesar
prototipul funcţiei apelate ci doar implementarea ei (exemplul
2). Comparând structura unui program C cu structura unui
program PASCAL se observă nivelul de imbricare diferit. În
PASCAL apare o imbricare a procedurilor şi funcţiilor pe când
în C nu există o astfel de imbricare (rămâne la nivelul
fiecărei funcţii dacă e cazul).
PASCAL
C
...
Exemple:
1) double radical (double x) // calculeaza radacina patrata din x si
returneaza valoarea gasita
2) double radical_n (double x, int n) // calculeaza radacina de ordinul n din x
{ declaraţii
instrucţiuni
}
Şi pentru că autorii limbajului C consideră că un limbaj
de programare se învaţă mai repede scriind şi executând
programe căt mai timpuriu vom da un mic exemplu de funcţie.
4.4.1. EXPRESII
4.4.2. OPERANZI
42
Un operand în limbajul C poate fi una din următoarele
elemente:
- o constantă;
- o constantă simbolică;
- numele unei variabile simple;
- numele unui tablou;
- numele unei structuri;
- numele unei funcţii;
- referirea la elementul unui tablou (variabilă cu indici);
- referirea la elementul unei structuri;
- apelul unei funcţii;
- o expresie inclusă în paranteze rotunde.
4.4.3. OPERATORI
( ) [ ] . ->
- (unar) +(unar) *(unar) &(unar) ! ~ ++ --
(tip) sizeof
* / %
+ -
<< >>
< <= >= >
43
= = !=
&
^
|
&&
| |
? : (ternar)
= op= op poate fi: *(binar) / % +(binar) –
(binar) << >> & ^ |
,
Exemple:
int i,j,k;
float x,y;
double t[10];
// se dau cateva exemple de expresii folosind operatorii aritmetici
i*x+t[5];
-y+k;
i%j; // daca i=9 si j=4 atunci i%j are valoarea 1
i/j; // daca i=9 si j=4 atunci i/j are valoarea 2
x*-y; // - este operatorul unar deci avem x*(-y)
Exemple:
a= 2 şi b=-1
atunci
a= =b are valoarea 0;
a!=b are valoarea 1;
a*b!=a+b are valoarea 1;
&& 0 1 || 0 1
45
sau exclusiv 0 1
0 0 0 0
0 1 0 0 1
1 0 1 1
1 1 1 1 0
& 0 1 | 0 1
^ 0 1
0 0 0 0
0 1 0 0 1
1 0 1 1
1 1 1 1 0
Observaţii:
1o. Operanzii care nu ocupă un cuvânt (16 biţi) se extind la un
46
cuvânt. De exemplu expresia ~0 are ca rezultat un cuvânt cu
toţi biţi egali cu 1.
2o. Operatorii logici pe biţi se execută bit cu bit spre
deosebire de operatorii logici care se evaluează global. De
exemplu dacă x=2 i y=1 sunt variabile de tip int atunci:
x&&y are valoarea 1 pentru că ambii operanzi
sunt diferiţi de 0.
x&y are valoarea 0 conform
schemei de mai jos
0000 0000 0000 0010
0000 0000
0000 0001
& 0000 0000 0000 0000
Exemple:
1) Fie declaraţia:
int i;
atunci expresia i >> 8 & 255 are ca rezultat valoarea celui
mai semnificativ octet a lui i; i >> 8 deplasează octetul
mai semnificativ al lui i în poziţia mai puţin
semnificativă; se face apoi un ŞI logic pe biţi cu masca 255
care păstrează octetul mai puţin semnificativ.
47
4.4.3.6. Operatori de atribuire
vn =. . . =v1=v=expresie
op=
unde prin op se înţelege unul din operatorii binari aritmetici sau logici pe biţi, adică unul din
următorii:
% / * - + & ^ | << >>
Acest mod de construcţie se foloseşte pentru a compacta un anumit tip de atribuire. Astfel
expresia:
v op = expresie;
v = op expresie;
Exemple:
int i, j;
double x, y;
int v[10];
48
i=5;
j=10;
x=y=10.01;
i +=1; // echivalenta cu i=i+1 si cu i++
x*=3; // echivalenta cu x=x*3
j<<=10; // echivalenta cu j=j<<10
v[i]*=i // echivalenta cu v[i]=v[i]*i
x /= x-y // echivalenta cu x = x/(x-y)
Exemple:
int i,j;
double x,y;
int vector [5];
j=i++; // este echivalent cu j=i si i=i+1;
y=--x; // este echivalent cu x=x-1 si y=x;
i=++vector[j] // este echivalent cu vector[j]=vector[j]+1 si i=vector[j]
(tip) operand
Dacă vom converti operanzii i şi j spre tipul double se va obţine rezultatul corect adică 1.6.
49
Deci:
int i,j;
double y;
i=8; j=5;
y=(double) i / (double) j; // y are valoarea 1.6,
Construcţia (tip) este un operator unar prin care se explicitează conversia dorită. Are aceeaşi
prioritate ca restul operatorilor unari.
sizeof (data)
Exemple:
int i;
long l;
float f;
double d;
char c;
int itablou[5];
double dtablou[5];
sizeof (i) // are valoarea 2;
sizeof (l) // are valoarea 4;
sizeof (f) // are valoarea 4;
sizeof (d) // are valoarea 8;
sizeof (c) // are valoarea 1;
sizeof (itablou[1]) // are valoarea 2;
sizeof (dtablou[1]) // are valoarea 8;
sizeof (itablou) // are valoarea 10;
sizeof (dtablou) // are valoarea 40;
50
4.4.3.10. Regula conversiilor implicite
i-j/k nu int
a/b a spre double
b spre double double
x+y nu double
i+a a spre double
i spre double double
i-3.14 i spre double double
i+3 nu int
i+x i spre double double
i-c c spre int int
x+10 10 spre double double
p-10 10 spre unsigned unsigned
r*5 5 spre long long
(double)(i/j) se realizează împărţirea întreagă între
i şi j şi rezultatul se converteşte spre double
48
4.4.3.11. Operatori condiţionali
Operatorul “,” este folosit pentru gruparea mai multor expresii într-una singură.
Cu ajutorul acestui operator (care are prioritatea cea mai mică) se construiesc expresii de
forma:
exp1, exp2,. . ., expn
Această expresie are valoarea şi tipul ultimei expresii (deci a lui expn).
Exemplu:
k= (i=10, j=j+5; i+j)
Se execută pe rând cele două atribuiri de la stânga la dreapta din parantezele rotunde apoi se
face suma i+j şi în final se atribuie această sumă lui k.
4.5. INSTRUCŢIUNI
50
simple care la rândul lor pot fi descompuse în altele mai
simple şi aşa mai departe. În felul acesta se ajunge la o
descompunere arborescentă a problemei date în subprobleme mai
simple. Programarea subproblemelor devine o problemă mai
simplă şi fiecare subproblemă are o anumită independenţă faţă
de celelalte subprobleme. De asemenea, interfaţa ei cu
celelalte subprobleme este limitată şi bine precizată prin
procesul de descompunere a problemei iniţiale. De obicei,
programarea unei subprobleme, componentă a descompunerii
arborescente a problemei iniţiale, conduce la realizarea unui
număr relativ mic de proceduri (funcţii). Aceste funcţii pot
prelucra în comun anumite date. Unele dintre ele sunt
independente de funcţiile realizate pentru alte subprobleme
componente ale descompunerii arborescente. Altele realizează
chiar interfaţa cu subproblemele învecinate.
Despre funcţiile obţinute în urma programării unei
subprobleme se obişnuieşte să se spună că sunt înrudite. De
obicei, aceste funcţii, împreună cu datele pe care le
prelucrează, se păstrează într-un fişier şi se compilează
independent.
O colecţie de funcţii înrudite, împreună cu datele pe
care le prelucrează în comun formează un modul. În felul
acesta, problema iniţială se realizează printr-un program
alcătuit din module.
Programarea modulară are la bază elaborarea programelor
pe module.
O parte din datele utilizate în comun de funcţiile
modulului, sau chiar toate datele modulului, nu sunt necesare
şi în alte module. Aceste date pot fi protejate sau cum se mai
spune, ascunse în modul.
Limbajul C şi C++, permite ascunderea datelor în modul
folosind date care au clasa de memorie static. Mai mult, pot
fi declarate şi funcţiile ca statice şi atunci ele vor fi
ascunse în modul (nu pot fi apelate din afara modului).
Ascunderea funcţiilor în modul se face pentru acele funcţii
care nu se utilizează la realizarea interfeţei modulului cu
celelalte module. Ascunderea datelor şi funcţiilor în module
permite protejarea datelor şi preîntâmpină utilizarea eronată
a funcţiilor.
da
S1 C
nu
da
S2 S
C
S nu
.
Sn
52
În toate aceste tehnologii anterioare se urmăreşte mai
mult organizarea programului şi mai puţin rezolvarea cât mai
naturală a problemei. Programarea prin abstractizarea datelor
şi programarea orientată spre obiecte propun metodologii în
care conceptele deduse din analiza problemei să poată fi
reflectate cât mai fidel în program şi să se poată manevra cu
instanţieri ale acestor concepte cât mai natural. Se
realizează o mai mare fidelitate a programului faţă de
problemă. De exemplu dacă într-o problemă în care se
procesează numere complexe e nevoie să se lucreze într-o formă
cât mai apropiată cu forma matematică se poate introduce tipul
COMPLEX (tip care nu există în limbajele de programare) şi
apoi se pot declara variabile de acest tip. Mai mult ar trebui
să se poată face toate operaţiile matematice asupra datelor de
tip COMPLEX. În general un TAD (Tip Abstract de Date) are două
componente fundamentale:
- datele membru (reflectă reprezentarea tipului);
- funcţiile membru (reflectă comportamentul tipului).
Dreptunghi
Romb
P
53
ătrat
Instrucţiunea vidă se reduce la caracterul “;”. Ea nu are nici un efect. Adesea este nevoie
de ea la construcţii în care se cere prezenţa unei instrucţiuni, dar nu este necesar să se execute
nimic în punctul respectiv.
Exemplu:
Observaţii:
1o. După acolada inchisă a unei instrucţiuni compuse nu se pune
”;”.
2o. Corpul unei funcţii are aceeaşi structură ca şi
instrucţiunea compusă, deci o funcţie are formatul:
55
antetul funcţiei
instrucţiune compusă
4.5.5. INSTRUCŢIUNEA if
Formatul 2:
if (expresie) instructiune_1;
else instructiune_2;
Efectul:
1) se evaluează expresia din paranteze;
2) dacă valoarea expresiei este diferită de zero (deci conform
convenţiei are valoarea adevărat), atunci se execută
instructiune_1, altfel se execută instructiune_2; apoi în
ambele cazuri se trece la instrucţiunea următoare.
Observaţii:
1o. Se pot folosi instrucţiuni if imbricate, nivelul de
imbricare fiind oarecare (deci nu există o limitare a
numărului de imbricări).
2o. Pentru mai multe imbricări se foloseşte regula asocierii
if-lui cu else astfel:
un else se pune în corespondenţă cu primul if care se află
înaintea lui în textul sursă şi nu este inclus în
instrucţiunea care îl precede pe el şi nici nu îi corespunde
deja un else.
Exemple
56
}
Deci instructiune se execută repetat atâta timp cât expresia din paranteză este diferită de
zero. Se observă că dacă expresia are valoarea zero de la început, atunci instructiune nu se
execută niciodată.
Antetul ciclului while este construcţia while (expresie) iar instructiune formează corpul
ciclului. În cazul în care este necesar să se execute repetat mai multe instrucţiuni, se utilizează o
instrucţiune compusă formată din instrucţiunile respective.
Exemplu:
Vom crea un program care citeşte un întreg n şi scrie n!. Algoritmul în pseudocod este următorul:
Citeste n
f=1
i=2
CâtTimp i<=n execută
57
f=f*i;
i=i+1
SfârşitCâtTimp
Scrie n,f
Programul în C este:
#include<stdio.h>
void main (void)
{ int n,i;
double f;
f=1.0;
i=2;
printf(“\n dati n= “);
scanf(“%d”,&n);
while (i<=n)
{ f=f*i;
i++;
}
printf(“\nn=%d, iar n!=%g\n”,n,f);
}
Antetul ciclului este definit de for(exp1; exp2; exp3) iar instructiune formează corpul
ciclului. Prima expresie exp1 constituie partea de iniţializare a ciclului, iar exp3 este partea de
reiniţializare a ciclului. Condiţia de continuare a ciclului este exp 2. De obicei exp1 şi exp3
reprezintă atribuiri.
Efectul:
1) se execută secvenţa de iniţializare definită de expresia exp1;
2) se evaluează exp2; dacă exp2 are valoarea zero, atunci se iese din ciclu, adică se trece la
instrucţiunea următoare instrucţiunii for, altfel se execută instrucţiunea din corpul ciclului;
3) se execută apoi secvenţa de reiniţializare definită de exp3, apoi se reia secvenţa de la punctul
2).
Observaţii:
1o. Ca şi în cazul instrucţiunii while, instrucţiunea din corpul ciclului for poate să nu se execute
niciodată dacă exp2 are valoarea zero chiar la prima evaluare.
58
2o. Expresiile din antetul instrucţiunii for pot fi şi vide; totuşi caracterele “;” vor fi întotdeauna
prezente.
3o. Comparând instrucţiunile for şi while observăm că instrucţiunea for cu formatul anterior se
poate realiza cu secvenţa următoare folosind while:
exp1;
while (exp2)
{ instructiune;
exp3;
}
s=0;
for(i=0; i<n; i++) s=s+tab[i];
sau scrisă mai compact:
for (s=0, i=0; i<n; i++) s+=tab[i];
#include <stdio.h>
void main(void)
{ long n;
for (n=0; getchar()!=EOF; n++);
printf (“\nnumarul caracterelor citite =%ld\n”,n);
}
sau scrisă cu instrucţiunea while
#include <stdio.h>
void main(void)
{ long n=0;
while (getchar()!=EOF) n++;
printf (“\nnumarul caracterelor citite =%ld\n”,n);
}
Observaţii:
1o. Structura realizată de instrucţiunea do-while poate fi realizată printr-o secvenţă în care se
foloseşte instrucţiunea while astfel:
instructiune;
while (exp) instructiune;
o
2 . Se observă că în cazul instrucţiunii do-while, corpul ciclului se execută cel puţin odată, spre
deosebire de ciclurile while şi for unde corpul ciclului poate să nu se execute niciodată.
Exemplu:
Vom da un program care calculează rădăcina pătrată dintr-un număr real a>=0.
#include<stdio.h>
#define EPS 1e-10
void main (void)
{ double x1,x2,y,a;
clrscr(); // sterge ecranul
printf(“\ndati un numar real pozitiv a=”);
if (scanf(“%lf”,&a) !=1 || a<0)
printf (“numarul citit nu este pozitiv\n”);
else {
x2 = 1.0;
do { x1 = x2;
x2 = 0.5 *(x1+a/x1); // formula de iteratie
if ((y=x2-x1) < 0) y = -y;
}
while (y >= EPS);
printf (“radacina patrata din:%g este: %.2lf\n”,a,x2); // 2 zecimale
} //sfirsit else
}
switch (exp)
{ case c1: sir1
break;
case c2: sir2
break;
...
case cn: sirn
break;
60
default: sir
}
Observaţii:
1o. Ramura default nu este obligatorie. În lipsa ei, dacă valoarea expresiei nu coincide cu nici
una din constantele c1,. . . , cn, instrucţiunea switch respectivă nu are nici un efect.
2o.Construcţia break reprezintă o instrucţiune. Ea termină fiecare ramură de instrucţiuni
sir1, . . . , sirn, provocând saltul la instrucţiunea următoare instrucţiunii switch sau, cum se mai
spune, realizează ieşirea din instrucţiunea switch.
3o. Instrucţiunea break nu este obligatorie. În cazul în care este absentă, se execută secvenţial
următoarea ramură. De exemplu dacă avem secvenţa:
switch (exp)
{ case c1: sir1
case c2: sir2
}
ea se execută în felul următor:
- dacă valoarea expresiei este egală cu c1 se execută sir1 şi apoi sir2;
- dacă valoarea expresiei este egală cu c2 se execută sir2;
- daca valoarea expresiei difera de valorile c1 şi c2 instrucţiunea switch de mai sus nu
este efectivă, se trece la instrucţiunea următoare care urmează după switch.
- secvenţa de mai sus se putea realiza şi astfel:
if (exp = = c1)
{ sir1
sir2
}else if (exp = = c2) sir2
Exemplu:
Vom citi din fişierul de intrare construcţii de forma: op1 operator op2, unde op1 şi op2 sunt numere
întregi (operanzi întregi) iar operator este un operator aritmetic {“+”, “-“, “*”, “/”}. La ieşire se
va scrie valoarea expresiei citite. De exemplu dacă se citeşte secvenţa 100/3 se va afişa
rezultatul 33. Programul permite citirea şi evaluarea mai multor astfel de expresii, până la
întâlnirea sfârşitului de fişier.
#include <stdio.h>
61
void main (void)
{ int op1,op2,operator,rezultat,i;
while (( i=scanf(“%d %c %d”, &op1,&operator, &op2)) != EOF)
if (i = = 3 ) // ramura adevarat inseamna ca s-au citit 3 campuri corecte
{ switch (operator)
{ case ‘+’: rezultat = op1 + op2 ; // avem adunare
break;
case ‘-‘ : rezultat = op1 – op2; // avem scadere
break;
case ‘*’ : rezultat = op1 * op2; // avem inmultire
break;
case ‘/’ : // avem impartire intreaga
if (op2 = = 0)
{ printf (“divizor nul\n”);
rezultat = 0;
} else rezultat = op1 / op2;
break;
default : printf (“operator eronat\n”);
rezultat = 0;
} // sfarsit switch
printf (“%d %c %d %d\n”, op1, operator, op2, rezultat);
} else
printf (“expresie eronat\n”); // sfarsit if si while
}
De obicei instrucţiunea break se foloseşte pentru a ieşi dintr-un ciclu. Dacă există mai
multe cicluri imbricate instrucţiunea break va trece controlul la ciclul de nivel imediat superior
(deci imbricarea rămâne, nu se iese din toate ciclurile). O altă utilizare este în instrucţiunea
switch, după cum am observat în paragraful anterior.
Un alt exemplu de utilizare frecventă este ieşirea dintr-un ciclu infinit de forma:
for ( ; ; )
{. . .
if (exp) break;
...
}
Efectul:
1) în ciclurile while şi do-while ea realizează saltul la evaluarea expresiei care decide asupra
continuării ciclului;
2) în ciclul for ea realizează saltul la pasul de reiniţializare.
62
Observaţie:
1o. Instrucţiunea continue se utilizează numai în corpul unui ciclu, permiţând, după caz, să se
treacă la pasul următor al ciclului sau să se iasă din ciclu.
goto eticheta;
Efectul:
1) se realizează saltul la instrucţiunea prefixată de eticheta al cărei nume se află scris după
cuvântul cheie goto.
Observaţii:
1o. Dacă nu dorim să utilizăm valoarea returnată de funcţia respectivă, apelul se face printr-o
63
instrucţiune de apel.
2o. Dacă dorim să utilizăm valoarea returnată de funcţie, vom folosi apelul funcţiei drept operand
într-o expresie, operandul având formatul (*).
Exemple de apeluri de funcţii folosite până acum sunt apelurile funcţiilor standard printf,
scanf, getchar şi putchar. Funcţiile printf şi putchar au fost apelate prin instrucţiuni de apel,
valorile returnate de ele nefiind utilizate. În schimb funcţiile scanf şi getchar au fost apelate în
ambele moduri, atât prin instrucţiuni de apel, cât şi ca operanzi în diferite expresii.
O funcţie poate fi apelată dacă ea este definită în fişierul sursă înainte de a fi apelată.
După cum am prezentat în lecţia 1 nu întotdeauna este posibil acest lucru şi în astfel de cazuri
apelul funcţiei trebuie să fie precedat de prototipul ei.
Prototipul unei funcţii are ca scop să informeze compilatorul despre:
- tipul valorii returnate de funcţie;
- tipurile parametrilor.
În felul acesta, la apelul unei funcţii, compilatorul poate face teste cu privire la tipul
expresiilor care reprezintă parametrii efectivi, precum şi unele conversii necesare asupra valorii
returnate de funcţie.
Observaţii:
1o. Tipurile parametrilor pot să lipsească. În acest caz, compilatorul nu controlează tipurile
parametrilor efectivi, singura informaţie conţinută de prototip fiind tipul valorii returnate de
funcţia respectivă.
2o. Absenţa atât a prototipului unei funcţii, cât şi a definiţiei funcţiei înainte de a fi apelată este
posibilă; în acest caz se presupune că funcţia returnează o valoare de tip int.
3o. În practică se recomandă utilizarea prototipurilor pentru toate funcţiile înainte de a fi apelate.
În acest scop, ele vor fi scrise la începutul fişierelor sursă.
Formatele posibile ale unui prototip sunt:
64
prin valoare funcţia apelată nu poate modifica parametrii efectivi din funcţia apelantă, neavând
acces la ei. În cazul apelului prin referinţă, funcţia apelată, dispunând de adresele parametrilor
efectivi, îi poate modifica.
În limbajul C apelul se realizează implicit prin valoare. În cazul că un parametru este
numele unui tablou atunci transferul se realizează prin referinţă deoarece numele unui tablou este
un pointer şi conţine adresa primului element al tabloului. Transferul prin referinţă se realizează
cu ajutorul variabilelor de tip pointer şi cu ajutorul operatorului de adresă (&).
Primul format se utilizează când funcţia nu returnează o valoare, iar cel de-al doilea
când funcţia returnează o valoare. În acest ultim caz, funcţia returnează valoarea expresiei
specificate.
Observaţie:
1o. Când revenirea se face după execuţia ultimei instrucţiuni a funcţiei nu se returnează o valoare;
revenirea în acest caz, se face ca şi cum acolada închisă de la sfârşitul corpului funcţiei ar fi
precedată de instrucţiunea return.
Exemplu: vom da un exemplu de apel al funcţiei care determină rădacina pătratică dintr-un
număr nenegativ.
#include<stdio.h>
double radacina_2 (double) // prototipul functiei
Observaţie:
1o. Limbajul C dispune de o bibliotecă matematică în care sunt incluse o serie de funcţii pentru
calculul valorilor funcţiilor elementare. Există o funcţie numită sqrt (cu prototipul double sqrt
(double);). Fişierul care conţine biblioteca matematică se numeşte math.h şi trebuie inclus în
fişierul sursă de lucru dacă se doreşte utilizarea funcţiilor definite în el.
#include<stdio.h>
#include<conio.h>
void main(void)
{ long n,m,x;
int c;
printf ("\ndati un numar natural:");
scanf ("%ld",&n);
x=n;
m=0;
while (x > 0)
{ c = x % 10;
m = m*10+c;
x = x / 10;
}
if (n == m) printf ("numarul %ld este palindrom",n);
else printf ("numarul %ld nu este palindrom",n);
getch();
}
66