Sunteți pe pagina 1din 23

09.11.

2016

Programarea Calculatoarelor si I. DECLARAŢII

Limbaje de Programare II. OPERATORI


II.1 Operatori aritmetici
II.2 Operatori logici și relaționali

CURS 5 II.3 Conversii între tipurile de date


II.4 Expresiile relaționale și logice
II.5 Operatorul unar cast
- suport de curs - CUPRINS II.6 Operatori de incrementare/decrementare
II.7 Operatori pe biți
II.8 Expresii și operatori de atribuire
II.9 Expresii condiționale
II.10 Prioritatea și ordinea evaluării
Declarații. Operatori. Controlul III. CONTROLUL EXECUŢIEI PROGRAMELOR
III.1 Instrucțiuni şi blocuri
execuției programelor III.2 Instrucțiunea if-else
III.3 Construcțiile else-if
III.4 Instrucțiunea switch
17:52 PCLP CURS 5 2

Declaraţii
• Toate variabilele trebuie declarate înainte de
utilizare,
 deși anumite declarații pot fi făcute implicit din
context.

• O declarație specifică tipul și conține o listă de una


I. DECLARAŢII sau mai multe variabile de acel tip, ca în exemplul
de mai jos:
int lower, upper, step;
char c, line[1000];
17:52 PCLP CURS 5 4

Declaraţii Iniţializarea la declarare


• Variabilele pot fi distribuite printre declarații în orice
mod. • O variabilă poate fi iniţializată la declararea ei.
• Lista anterioară poate fi scrisă şi astfel:
• Dacă numele variabilei este urmat de semnul egal
int lower;
int upper; şi de o expresie, expresia serveşte ca iniţializare.
int step;
char esc = '\\';
char c;
char line[1000];
int i = 0;
int limit = MAXLINE+1;
• Ultima formă ocupă mai mult spațiu, dar este float eps = 1.0e-5;
potrivită atunci când dorim să adăugăm comentarii la
fiecare declarație pentru modificări ulterioare.
17:52 PCLP CURS 5 5 17:52 PCLP CURS 5 6

PCLP CURS 5 1
09.11.2016

Iniţializarea la declarare Iniţializarea la declarare


• Dacă variabila nu este automată,
• Variabilele externe şi statice
 inițializarea este făcută numai o singură dată,
 sunt iniţializate implicit cu zero.
 conceptual înainte de pornirea execuției
programului,
• Variabilele automate pentru care nu există o
 iar inițializarea se va face cu o expresie constantă. iniţializare explicită
• O variabilă automată inițializată explicit este  au valori nedefinite (i.e. resturi de memorie).
inițializată de fiecare dată când se intră în funcția
sau blocul care o conținea;
inițializarea ei se poate face cu orice expresie.
17:52 PCLP CURS 5 7 17:52 PCLP CURS 5 8

Calificatorul const Calificatorul const


• Calificatorul const poate fi aplicat la declararea • Declaraţia const poate fi utilizată, de asemenea,
oricărei variabile pentru a preciza că funcţia nu va modifica acel
tablou furnizat ca argument:
 pentru a specifica că valoarea ei nu se va schimba.
int strlen(const char[]);
• Pentru un tablou, calificatorul const precizează
că elementele tabloului nu vor fi modificate.
const double e = 2.71828182845905;
const char msg[] = "warning: ";

17:52 PCLP CURS 5 9 17:52 PCLP CURS 5 10

#define LENGTH 10 #define WIDTH 5 #define NEWLINE '\n'


#define LENGTH 10 #define WIDTH 5 #define NEWLINE '\n'

Întrebare
• Calificatorul const declară variabile sau
constante?
• Calificatorul const poate fi aplicat la declararea
oricărei variabile pentru a specifica că valoarea ei nu
se va schimba.

• Pentru declararea constatelor folosim directiva II. OPERATORI


#define:
#define LUNGIME 10
#define LINIENOUA '\n'

17:52 PCLP CURS 5 11

PCLP CURS 5 2
09.11.2016

1. Operatori aritmetici An bisect


• Un an este bisect dacă este divizibil cu 4,
• Operatorii aritmetici binari sunt:
exceptând cazurile când este divizibil cu 100 fără a
+ - * / fi divizibil cu 400 (e.g. anii 2000 și 2016 sunt bisecți, în
operatorul modulo % schimb 2100 nu este bisect).

• Împărțirea întreagă trunchiază orice parte • Codul care afișează că un an este sau nu bisect:
fracționară. if ((an % 4 == 0 && an % 100 != 0) || an % 400 == 0)
• Expresia x % y printf("%d e bisect\n", an);
else
 furnizează restul împărțirii lui x lui la y și deci,
este zero când y îl împarte exact pe x. printf("%d nu e bisect\n", an);
17:52 PCLP CURS 5 13 17:52 PCLP CURS 5 14

• Operatorul % nu poate fi aplicat tipurilor de date float


sau double.
P
• Pentru operanzii negativi sunt dependente de mașină: Tabel cu prioritatea R
 direcția în care se trunchiază pentru operatorul / și asociativitatea
I
operatorilor din C
 semnul rezultatului pentru % S O
c R
• Operatorii binari + şi – au aceiași prioritate (precedență) a I
d T
 care este mai mică decât prioritatea operatorilor binari *,
Operatorii unari & (adresă), +, -, * e A
/ și %, care la rândul lor (indirectare pointer) au o prioritate
mai mare decât variantele lor binare T
au o prioritatea mai mică decât operatorii unari + și -.
E
() : apel de funcție
• Operatorii aritmetici se asociază de la stânga la dreapta A

17:52 PCLP CURS 5 15 17:52


PCLP CURS 5 16

Operatorii logici și relaționali


2. Operatorii logici și relaționali
• Operatorii relaționali au o prioritatea mai mică
decât operatorii aritmetici,
• Operatorii relaţionali sunt
 astfel încât o expresie precum:
> >= < <= i < lim-1
Ei au toţi aceiaşi prioritate.  este evaluată ca şi expresia:
i < (lim-1)
• Prioritatea imediat inferioară lor o au operatorii
• Expresiile conectate prin && sau || sunt evaluate
de egalitate:
de la stânga la dreapta și
== !=  evaluarea se oprește imediat ce rezultatul
adevărat sau fals este cunoscut.
17:52 PCLP CURS 5 17 17:52 PCLP CURS 5 18

PCLP CURS 5 3
09.11.2016

• Iată un ciclu folosit anterior în funcția getline:


Operatorii logici şi relaţionali
for (i=0; i < lim-1 && (c = getchar()) != '\n' && c != EOF; ++i)
s[i] = c;
Înaintea citirii unui nou caracter este necesar să verificăm • Prioritatea lui && este superioară celei a lui || şi
dacă mai există componente libere în tabloul s pentru a-l
 ambele au prioritate inferioară operatorilor
stoca,
 astfel că testul i < lim-1 trebuie realizat primul. relaţionali şi de egalitate,
Dacă testul dă rezultat negativ nu trebuie să mergem să  astfel că expresii precum:
citim un alt caracter.
i < lim-1 && (c = getchar()) != '\n' && c != EOF
Similar este greşit să testăm cu EOF pe c înaintea apelului
funcției getchar deci  nu au nevoie de paranteze suplimentare.
apelul funcției getchar şi atribuirea valorii citite către c
trebuie realizate înainte de a testa pe c.
17:52 PCLP CURS 5 19 17:52 PCLP CURS 5 20

Operatorii logici şi relaţionali • Prin definiție, valoarea numerică a unei expresii


relaționale sau logice
 este 1 dacă expresia este adevărată şi
• Dar pentru că prioritatea operatorului != este
 0 dacă expresia este falsă.
mai mare decât prioritatea operatorului de
atribuire = • Operatorul unar de negaţie ! converteşte
 avem nevoie de paranteze pentru expresia:  un operand nenul în 0 şi
(c = getchar()) != '\n'  un operand 0 în 1.
 Operatorul ! este utilizat adesea în construcții de forma:
pentru a obţine rezultatul dorit al atribuirii valorii
citite de funcţia getchar variabilei c şi if ( !valid )
 pentru ca apoi valoarea acesteia să fie comparată care sunt preferate construcțiilor de genul:
cu '\n'. if ( valid == 0 )
17:52 PCLP CURS 5 21 17:52 PCLP CURS 5 22

3. Conversii între tipurile de date Conversii între tipurile de date


• Când un operator are operanzi de tipuri diferite,
 ei sunt convertiţi la un tip comun în conformitate • Expresiile fără sens, cum ar fi utilizarea unui
cu un număr mic de reguli. float ca indice al unui tablou, nu sunt permise.

• În general, singurele conversii automate sunt • Un char este un întreg mic,


acelea care
 astfel că tipul char poate fi utilizat în expresii
 convertesc un operand „îngust” într-unul „larg” aritmetice.
fără pierdere de informații, Această dă o flexibilitate considerabilă în anumite
 de exemplu, conversia unui întreg la un real virgulă moduri de transformări de caractere.
mobilă într-o expresie precum f + i.
17:52 PCLP CURS 5 23 17:52 PCLP CURS 5 24

PCLP CURS 5 4
09.11.2016

Exemplificare cu funcţia atoi, care converteşte un Alt exemplu de conversie de la char la int este
şir de cifre la echivalentul său numeric: funcţia lower, care converteşte un caracter din codul
ASCII la minusculă. Dacă caracterul nu este o literă
mare lower îl returnează nemodificat.
/* atoi: convert s to integer */
/* lower: convert c to lower case; ASCII only */
int atoi(char s[])
Expresia: s[i] - '0' furnizează int lower(int c)
{
valoarea numerică a caracterului {
int i, n;
stocat în s[i].
n = 0; if (c >= 'A' && c <= 'Z') Această funcție nu
for (i = 0; s[i] >= '0' && s[i] <= '9'; ++i) return c + 'a' - 'A'; lucrează corect pentru
else un alt set de caractere
n = 10 * n + (s[i] - '0');
în afara codului ASCII,
return n; return c; cum ar fi codul EBCDIC.
} }
17:52 PCLP CURS 5 25 17:52 PCLP CURS 5 26

Headerul standard <ctype.h> Conversia caracterelor la întregi


• Există o subtilitate la conversia caracterelor la întregi.
• Definește o familie de funcții care furnizează teste și
conversii independente de setul de caractere. • Limbajul nu specifică dacă variabilele tipului char
 De exemplu, funcția tolower este o substituție sunt
portabilă pentru funcția anterioară lower.  cantităţi cu semn sau
 Similar, testul:  fără semn.
c >= '0' && c <= '9'
 poate fi înlocuit cu: • Când un char este convertit la un int, poate
isdigit(c) produce vreodată un număr negativ?

• De acum înainte vom folosi funcțiile din headerul • Răspunsul variază de la maşină la maşină, reflectând
<ctype.h>. diferenţele în arhitectură.
17:52 PCLP CURS 5 27 17:52 PCLP CURS 5 28

Conversia caracterelor la întregi Conversia caracterelor la întregi


• Definiția limbajului C garantează
• Pe anumite maşini un char al cărui cel mai din
 că orice caracter din setul standard de caractere
stânga bit este 1 va fi convertit la un întreg negativ
(e.g. codul ASCII) afișabile standard nu este negativ,
 1 este extensia pentru semnul - de la  așa că aceste caractere vor fi totdeauna cantități
reprezentarea în complement faţă de 2. pozitive în expresiile în care apar.

• Pe altele, un char este promovat la un int • Dar modele de biți arbitrare stocate în variabile
caracter pot fi
 prin adăugarea de zerouri la stânga şi
 astfel el este totdeauna un număr pozitiv.  negative pe anumite mașini și
 pozitive pe altele.
17:52 PCLP CURS 5 29 17:52 PCLP CURS 5 30

PCLP CURS 5 5
09.11.2016

Conversia caracterelor la întregi 4. Expresiile relaționale și logice

• Pentru portabilitate este indicat să specificați • Expresiile relaționale ca


 signed sau  i > j şi

 unsigned • expresiile logice


 dacă trebuie să stocați în variabile de tipul char  conectate prin && şi ||
date  sunt definite să aibă
 care nu aparţin setului de caractere al mașinii (e.g.  valoarea 1 dacă sunt adevărate și
codului ASCII).  0 dacă sunt false.

17:52 PCLP CURS 5 31 17:52 PCLP CURS 5 32

Expresiile relaţionale şi logice Conversiile aritmetice implicite


• Atribuirea:
d = c >= '0' && c <= '9' • Conversiile aritmetice implicite funcţionează - în
mare parte - conform aşteptărilor.
 îi dă lui d valoarea 1, dacă c este o cifră, sau
 îi dă valoarea 0, dacă nu este o cifră. • În general, dacă un operator binar precum
+ *
• Totuși, funcțiile ca isdigit pot returna orice
valoare nenulă pentru adevărat.  are operanzi de tipuri diferite,
• În partea de test a unor instrucțiuni precum if,  tipul „inferior“ este promovat la tipul „superior“
while, for etc. înainte ca operaţia să înceapă.
 ”adevărat” înseamnă diferit de zero.  Rezultatul aparţine tipului superior.
17:52 PCLP CURS 5 33 17:52 PCLP CURS 5 34

Dacă nu există operanzi unsigned Set neoficial de reguli


Cu toate acestea, dacă nu există operanzi de tip
unsigned, următorul set neoficial de reguli este • Altfel, dacă unul dintre operanzi este de tip float,
de ajuns:  converteşte-l pe celălalt la tipul float.
• Dacă unul dintre operanzi este de tip long
• Altfel, converteşte tipurile char şi short
double,
 converteşte-l pe celălalt la tipul long double.  la tipul int.

• Altfel, dacă unul dintre operanzi este de tip • Apoi, dacă unul dintre operanzi este de tip long
double,  converteşte-l pe celălalt la tipul long.
 converteşte-l pe celălalt la tipul double.
17:52 PCLP CURS 5 35 17:52 PCLP CURS 5 36

PCLP CURS 5 6
09.11.2016

float sau double Conversie cu operanzi unsigned


• Să observăm că tipurile float într-o expresie nu • Regulile de conversie sunt mai complicate atunci
sunt automat convertite la double. când sunt implicați operanzi unsigned.
• Problema este dată de faptul că comparațiile între
• În general, funcţiile matematice ca cele conținute valorile cu semn și fără semn sunt dependente de
în <math.h> utilizează dubla precizie. mașină,
• Motivul principal pentru care utilizăm float este  deoarece ele depind de mărimile diferitelor tipuri
întregi.
 a salva spațiu de stocare pentru tablourile mari
 De exemplul, să presupunem că
 a salva timp pe mașinile unde aritmetica în dublă  tipul int este pe 16 biți și
precizie este scumpă.  tipul long este pe 32 de biți.
17:52 PCLP CURS 5 37 17:52 PCLP CURS 5 38

Conversie cu operanzi unsigned Întrebare


• Atunci -1L < 1U, • Ce afişează programul următor?
 deoarece 1U, care este un unsigned int,
 este promovat la signed long.

• În schimb, -1L > 1UL


 deoarece -1L
este promovat la unsigned long (primul bit din
stânga cu valoarea 1, care era asociat cu semnul – -
în reprezentarea în cod complement față de 2 -
devine o cifră a numărului)
și astfel -1L apare ca un număr pozitiv mare.
17:52 PCLP CURS 5 39 17:52 PCLP CURS 5 40

Explicaţi afişarea programului următor Conversii la atribuire


• Conversii se fac şi în timpul atribuirilor.
• Valoarea din partea dreaptă este convertită la
tipul din stânga,
 care este și tipul rezultatului.

• Un caracter este convertit la un întreg.


• Întregii mai lungi sunt convertiți la întregi mai
scurți sau
 la char eliminând biții în exces.
17:52 PCLP CURS 5 41 17:52 PCLP CURS 5 42

PCLP CURS 5 7
09.11.2016

Conversii la atribuire Explicaţi afişarea


• Astfel în secvența de cod:
programului
int i;
char c;
i = c;
c = i;
 valoarea lui c este neschimbată fie că lucrăm cu
valori cu semn sau nu.

• Totuși dacă inversăm ordinea celor două atribuiri


putem pierde informație.
17:52 PCLP CURS 5 43 17:52 PCLP CURS 5 44

Conversii: float, int, double Conversii la apelul funcţiilor


• Deoarece argumentul din apelul unei funcții este o
• Dacă x este float și i este int, atunci atât
expresie,
 x = i cât și  conversia de tip apare când argumentele sunt trecute
 i = x implică efectuarea de conversii. funcțiilor.
• În absenţa prototipului funcției
• Conversia tipului float la int determină
 char şi short devin int,
trunchierea oricărei părţi fracționare.
 float devine double.
• Când un double este convertit la float, • Acesta este motivul pentru se recomandă să
 depinde de implementare dacă valoarea este  declarăm tipul argumentelor funcțiilor int și double
rotunjită sau trunchiată.  chiar și atunci când funcția este apelată cu char și float
17:52 PCLP CURS 5 45 17:52 PCLP CURS 5 46

5. Operatorul unar cast Operatorul cast


• Putem forța conversiile explicite de tip în orice
expresie cu operatorul unar numit cast. • De exemplu, funcția de bibliotecă sqrt din <math.h>
• În construcția  așteaptă un argument de tip double şi
(nume-tip) expresie  va furniza un rezultat eronat dacă îi transmitem
 expresie este convertită la tipul precizat pe baza altceva.
regulilor discutate deja.
• Operatorului cast acționează ca și cum expresie este • Astfel, dacă n este un întreg, putem scrie:
atribuită unei variabile de tipul nume-tip, sqrt((double) n)
 variabilă care apoi este utilizată în locul întregii  pentru a converti valoarea lui n la double înainte
construcții (nume-tip) expresie. de a o transmite lui sqrt.
17:52 PCLP CURS 5 47 17:52 PCLP CURS 5 48

PCLP CURS 5 8
09.11.2016

Operatorul cast Operatorul cast


• Să observăm că operatorul cast produce o
valoare pentru n, de tipul specificat; • Astfel, având prototipul funcţiei sqrt:
 variabila n, în sine, nu este alterată. double sqrt(double);
• Prioritatea operatorului cast este precizată în apelul
tabelul anterior, unde apare notat (type). root2 = sqrt(2)
• Dacă argumentele funcției sunt declarate în  forţează întregul 2 la valoarea 2.0 de tipul
prototipul funcției, așa cum este normal să fie, double
 declarația cauzează forțarea automată a oricărui
 fără să fie nevoie de nici un cast.
argument la tipul specificat la apelul funcției.
17:52 PCLP CURS 5 49 17:52 PCLP CURS 5 50

• Biblioteca standard include o implementare portabilă a


unui generator de numere pseudo-aleatoare (rand) și o
funcției pentru inițializarea sămânţei (srand); /* srand: set seed for rand() */
prima funcție (rand) ilustrează utilizarea unui cast.
void srand(unsigned int seed)
unsigned long int next = 1;
{
/* rand: return pseudo-random integer on 0..32767 */
next = seed;
int rand(void)
{ }
next = next * 1103515245 + 12345;
return (unsigned int)(next/65536) % 32768;
}
17:52 PCLP CURS 5 51 17:52 PCLP CURS 5 52

6. Operatorii de incrementare/decrementare Operatorii de incrementare/decrementare

• Limbajul C furnizează doi operatori pentru


incrementarea și decrementarea variabilelor. • Aspectul neobișnuit este că ++ şi –- pot fi utilizați
fie
 Operatorul de incrementare ++ adună 1 la
operandul căruia i se aplică,  ca operatori prefixați (înaintea variabilei, ca în
++n), sau
 Operatorul de decrementare –- scade 1.
 ca operatori postfixaţi (după variabilă: n++).
• Frecvent utilizăm ++ ca să incrementăm variabile,
ca în: • În ambele cazuri efectul este incrementarea lui n.
if ( c == '\n' )
++nl;
17:52 PCLP CURS 5 53 17:52 PCLP CURS 5 54

PCLP CURS 5 9
09.11.2016

Operatorii de incrementare/decrementare Operatorii de incrementare/decrementare


• ++n incrementează pe n înainte ca valoarea lui să • Dacă n este 5, atunci
fie utilizată, x = n++ ;
• n++ incrementează pe n după ce valoarea lui a  atribuie lui x valoarea 5, dar
fost utilizată. x = ++n ;

• Aceasta înseamnă că în contextul în care se  atribuie lui x valoarea 6.


urmărește numai incrementarea lui n,  în ambele cazuri n devine 6.
 oricare construcție poate fi folosită, • Operatorii de incrementare şi decrementare se pot
• Dar există și contexte în care ++n şi n++ furnizează aplica numai la variabile
două valori distincte.  o expresia ca (i+j)++ este ilegală.
17:52 PCLP CURS 5 55 17:52 PCLP CURS 5 56

Operatorii de incrementare/decrementare Să considerăm funcţia squeeze(s,c), care îndepărtează


toate apariţiile caracterului c din şirul s.
• Într-un context în care nicio valoare nu este dorită, void squeeze(char s[], int c)
{ /* squeeze: delete all c from s */
ci doar efectul de incrementare, ca în:
int i, j;
if (c == '\n')
for (i = j = 0; s[i] != '\0'; i++)
nl++;
if (s[i] != c)
 este indiferentă utilizarea operatorului s[j++] = s[i];
 prefixat sau s[j] = '\0';
}
 postfixat. De fiecare dată când apare un caracter s[i] care nu este c
(s[i] != c) el este copiat în s în poziția curentă a lui j și
• Dar sunt situații unde unul sau altul dintre ei este numai atunci j este incrementat pentru a fi pregătit pentru
poziția în care va fi plasat următorul caracter diferit de c.
apelat cu un rol specific.
17:52 PCLP CURS 5 57 17:52 PCLP CURS 5 58

/* getline: read a line into s, return length */


if (s[i] != c)
int getline(char s[],int lim)
s[j++] = s[i]; {
int c, i;
este perfect echivalent cu:
for (i=0; i < lim-1 && (c=getchar())!=EOF && c!='\n'; ++i)
if (s[i] != c) { s[i] = c;
s[j] = s[i]; if (c == '\n') { Îl putem înlocui printr-un
s[i] = c; cod mai compact:
j++; if (c == '\n')
++i;
} } s[i++] = c;

s[i] = '\0';
• Un exemplu de construcție similară am întâlnit
return i;
anterior la funcția getline (vezi în continuare). }
17:52 PCLP CURS 5 59 17:52 PCLP CURS 5 60

PCLP CURS 5 10
09.11.2016

Funcția standard strcat(s,t) /* strcat: concatenate t to end of s; s must be big enough */


void strcat(char s[], char t[])
{
• Să considerăm funcția standard strcat(s,t), int i, j;
 care concatenează șirul t la finalul șirului s. i = j = 0;
while (s[i] != '\0‘) /* find end of s */
• strcat presupune că există suficient spațiu în s, i++;
pentru a memora alipirea celor două şiruri. while ((s[i++] = t[j++]) != '\0‘)
; /* copy t */
• Așa cum este scrisă în continuare strcat nu }
Pentru că fiecare caracter este copiat din t în s,
returnează nicio valoare; operatorul de incrementare postfixat ++ este aplicat
 în schimb versiunea din biblioteca standard atât indexului i cât şi indexului j pentru a fi siguri că ei
s-au poziționat corect pentru următorul pas al ciclului.
returnează un pointer la șirul rezultat.
17:52 PCLP CURS 5 61 17:52 PCLP CURS 5 62

7. Operatori pe biți Operatorul &


• C furnizează 6 operatori pentru manipularea biților; • este operatorul ŞI logic pe biţi.
 ei pot fi aplicați numai la operanzi întregi,
 adică la tipurile char, short, int şi long • El este asociativ şi expresiile care conţin
 fie că sunt cu semn sau nu. operatorul & pot fi rearanjate.
& operatorul ŞI logic pe biţi
• Rezultatul este funcţia logică ŞI pe biţi aplicată
| operatorul SAU (SAU-inclusiv) logic pe biți
operanzilor săi.
^ operatorul XOR (SAU-exclusiv) logic pe biți & 0 1
<< deplasare la stânga • Tabelul de adevăr asociat este:
>> deplasare la dreapta
0 0 0
~ complement față de unu (operator unar) 1 0 1
17:52 PCLP CURS 5 63 17:52 PCLP CURS 5 64

Exemple cu operatorul ŞI pe biți & Găsirea ultimilor biți


10101010 & Operatorul ŞI pe biţi & este
• În baza 10, dacă dorim să aflăm ultima cifră a unui număr
adesea utilizat pentru a masca o
11001100 întreg n,
anumită mulţime de biţi, de
 folosim expresia n%10,
--------------- exemplu:  dacă dorim ultimele două cifre: n%100 ș.a.m.d.,
10001000 n = n & 0177;
 în general, dacă dorim ultimele c cifre din n calculăm
177(8) = 1 111 111(2) restul împărțirii lui n la 10c.
• pune pe zero toţi biţii lui n,
• afară de ultimii 7 de ordin inferior • Lucrurile se petrec la fel și în baza 2:
n: bbbbbbbbbbbbbbbb &
masca: 0000000001111111  dacă dorim ultimele c cifre din n calculăm restul împărțirii
 ultimii 7 biţi din dreapta din n,
---------------------------- lui n la 2c.
care rămân neschimbați. n: 000000000bbbbbbb  Exemplu: n%16 furnizează ultimii 4 biți din reprezentarea
Astfel putem afla valoarea ultimilor 7 biți din n. internă a lui n.
17:52 PCLP CURS 5 65 17:52 PCLP CURS 5 66

PCLP CURS 5 11
09.11.2016

Întrebare Testarea valorii unui bit


• n = 0313(8) = 11001011(2). Se cere să se • n = 0313(8) = 11001011(2). Să se afle
seteze bitul 3 din n la valoarea 0 folosind valoarea bitului 2 și valoarea bitului 3.
operatorul & și o variabilă masca, astfel: • Folosim două măști, masca1 = 00000100 și
n = n & masca;
masca2 = 00001000 .
• Care este valoarea variabilei masca intern (în baza if( n & masca1) if( n & masca2)
2) și în baza 8? printf(1); printf(1);
else else
masca va avea toți biții 1, mai puțin bitul 3 care e 0. printf(0); printf(0);
n: 11001011 & n: 11001011 & n: 11001011 &
masca = 11110111(2) = 0367(8) masca: 11110111 masca1: 00000100 masca2: 00001000
-------------- -------------- --------------
n: 11000011 n&masca1: 00000000 n&masca2: 00001000
17:52 PCLP CURS 5 67 17:52 PCLP CURS 5 68

Operatorul | Exemple cu operatorul SAU pe biți |


• Operatorul | este operatorul SAU logic pe biți.
10101010 |
• El este asociativ și expresiile care-l conţin pot fi 11001100
rearanjate. ---------------- • Operatorul SAU pe biţi | este
utilizat pentru a pune biţii pe unu:
• Rezultatul este funcția logică SAU pe biți aplicată 11101110
operanzilor săi. x = x | SET_ON;
| 0 1
• Tabelul de adevăr asociat este: • pune pe 1 în x
0 0 1
 biţii care au valoarea 1 în SET_ON.
1 1 1
17:52 PCLP CURS 5 69 17:52 PCLP CURS 5 70

Întrebare Operatorul ^
• x = 0313(8) = 11001011(2). Se cere să se • Operatorul ^ este operatorul XOR logic pe biţi.
seteze bitul 2 din x la valoarea 1 folosind
operatorul | și o variabilă SET_ON, astfel: • El este asociativ şi expresiile care-l conţin pot fi
x = x | SET_ON; rearanjate.
• Care este valoarea variabilei SET_ON intern (în • Rezultatul este funcţia logică XOR pe biţi aplicată
baza 2) și în baza 8? operanzilor săi.
^ 0 1
SET_ON are toți biții 0, mai puțin bitul 2, care e 1 • Tabelul de adevăr asociat este:
SET_ON = 00000100(2) = 04(8)
x: 11001011 | 0 0 1
SET_ON: 00000100

x:
--------------
11001111
1 1 0
17:52 PCLP CURS 5 71 17:52 PCLP CURS 5 72

PCLP CURS 5 12
09.11.2016

Confuzie
Exemplu cu operatorul XOR pe biți ^
• Nu trebuie să confundăm
01010101 ^  operatorii pe biți & și |
01100110  cu operatorii logici && și ||.
• Operatorul XOR pe biţi ^
----------------  pune 1 în fiecare poziţie de bit • De exemplu, dacă x este 1 și y este 2,
00110011 unde operanzii au biţi de valori  atunci 1(10) = 0000 0001(2)
diferite şi x & y este zero
 pune 0 în fiecare poziţie unde  în timp ce 2(10) = 0000 0010(2)
operanzii au biţi de aceiaşi
x && y este unu.
valoare. 1 = Adevărat
2 = Adevărat
17:52 PCLP CURS 5 73 17:52 PCLP CURS 5 74

Operatorii de deplasare pe biţi << >> Exemplu cu operatorul <<


• Deplasează la stânga sau la dreapta biții • Dacă dorim să poziționăm pe 1 bitul b din
operandului din stânga operatorului variabila întreagă n folosim construcția:
 cu un număr de poziții dat de operandul din
• n = n | (1 << b)
dreapta care trebuie să nu fie negativ.
• Astfel • Exemplu: n = 0313(8) = 11001011(2), b = 4
x << 3
1: 00000001 << n: 11001011 |
deplasează valoarea lui x cu 3 poziții spre stânga b: 4 1<<b: 00010000
 completând biții rămași liberi cu zero. -------------- --------------
1<<b: 00010000 n: 11011011
 Acest lucru este echivalent cu înmulțirea cu 23.
17:52 PCLP CURS 5 75 17:52 PCLP CURS 5 76

Întrebare Găsirea valorii ultimilor biți


• Fie n și b două numere întregi. Scrieți secvența de cod care • Pentru găsirea valorii ultimilor b biți din reprezentarea
determină valoarea bitului b din n. internă a unui număr întreg n
Indicație: folosim testul n & ( 1 << b ).  care este egal cu restul împărțirii lui n la 2b

if( n & ( 1 << b ) ) • folosim expresia:


1: 00000001 <<
printf(1); b: 4 n & ((1 << b) – 1)
else --------------
• Exemplu: n = 11001011, b = 4
printf(0); 1<<b: 00010000

n: 11001011 & 1: 00000001 << 1<<b: 00010000 - n: 11001011 &


• Exemplu: b: 4 1 (1<<b)-1: 00001111
1<<b: 00010000
n = 11001011, b = 4 -------------- -------------- -------------- --------------
n & ( 1 << b ): 00000000 1<<b: 00010000 (1<<b)-1: 00001111 n&((1<<b)-1 ): 00001011

17:52 PCLP CURS 5 77 17:52 PCLP CURS 5 78

PCLP CURS 5 13
09.11.2016

Deplasarea spre dreapta >> Exemplu


• Deplasarea spre dreapta a unei cantităţi unsigned int a = 2 << 1;
 totdeauna completează biţii rămaşi liberi cu zero.
Poziţie 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
• Deplasarea spre dreapta a unei cantităţi signed va 2= 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0
completa
 pe unele maşini biţii rămaşi liberi cu bitul de semn • Deplasarea biților cu o poziție spre stânga va
(deplasare aritmetică), determina următorul rezultat:
 iar pe alte maşini cu 0 (deplasare logică). Poziţie 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Deplasarea spre dreapta cu n poziții este echivalentă cu împărțirea la 2n. 2 << 1 = 0 0 0 0 0 0 0 0 0 0 0 0 0 1 0 0

17:52 PCLP CURS 5 79 17:52 PCLP CURS 5 80

Operatorul unar ~ x = x & ~077


• Operatorul unar ~ (tilda) este operatorul pentru • x & ~077 este independentă de lungimea
complement față de unu. cuvintelor din memoria calculatorului și
• El convertește fiecare bit 1 la 0 și invers.  este preferabilă altor variante, să zicem lui
x & 0177700
• El este un operator logic pe biți. De exemplu:  care presupune că x este o cantitate memorată pe
x = x & ~077 16 biți.
Poziţie 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 • Forma portabilă nu presupune nici un cost
Biţi 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 = 077 suplimentar,
Biţi 1 1 1 1 1 1 1 1 1 1 0 0 0 0 0 0 = ~077
 deoarece ~077 este o expresie constantă care
setează ultimii 6 biți ai lui x la zero. poate fi evaluată la momentul compilării.
17:52 PCLP CURS 5 81 17:52 PCLP CURS 5 82

3 biţi începând din poziţia 4


Ilustrare cu getbits(x,p,n) Poziţie 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Biţi 0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 x = 077 = 63(10)
• Funcţia getbits(x,p,n) returnează (aliniați la Biţi 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 1 getbits(x,4,3) = 07

dreapta) o /* getbits: get n bits from position p */


 secvenţă de n biţi din x care încep la poziţia p. unsigned getbits(unsigned x, int p, int n)
{
• Vom presupune că return (x >> (p+1-n)) & ~(~0 << n);
}
 cel mai puțin semnificativ bit din x (cel mai din • Expresia x >> (p+1-n) mută secvenţa dorită la marginea
dreapta) este în poziția 0 și că din dreapta a cuvântului.
 n și p sunt valori pozitive. • ~0 este format numai din biţi egali cu 1 (1111111111111111)
• deplasându-l la stânga cu n poziţii, cu expresia ~0<<n, se pun
• De exemplu, getbits(x,4,3) numai zerouri în cei mai din dreapta n biţi; (1111111111111000)
 returnează cei 3 biţi din poziţiile 4, 3 şi 2, aliniaţi la • complementând acest rezultat cu ~ se creează o mască numai
dreapta. cu 1 în cei mai din dreapta n biţi. (0000000000000111)
17:52 PCLP CURS 5 83 17:52 PCLP CURS 5 84

PCLP CURS 5 14
09.11.2016

8. Expresii și operatori de atribuire Expresii și operatori de atribuire


• O expresie precum:
i = i + 2 • Cei mai mulți operatori binari
 în care variabila din partea stângă mai apare încă o  adică operatori precum cel de adunare + care au
dată în dreapta, un operand în stânga și unul în dreapta
 poate fi scrisă într-o formă condensată astfel:  au un operator de atribuire corespunzător
i += 2
op=
• Operatorul  unde op este unul dintre operatorii:
+=
+ - * / % << >> & ^ |
 este un operator de atribuire.
17:52 PCLP CURS 5 85 17:52 PCLP CURS 5 86

Expresii şi operatori de atribuire Expresii şi operatori de atribuire

• Dacă expr1 şi expr2 sunt expresii, atunci • Să observăm parantezele din jurul expresiei expr2
atribuirea:
• În atribuirea de mai jos:
expr1 op = expr2 x *= y + 1
 este echivalentă cu:
 este echivalentă cu atribuirea:
expr1 = (expr1) op (expr2) x = x * (y + 1)
 exceptând faptul că expr1 este calculată o singură
 şi nicidecum cu atribuirea:
dată.
x = x * y + 1
17:52 PCLP CURS 5 87 17:52 PCLP CURS 5 88

Exemplu: funcţia bitcount Expresii şi operatori de atribuire


• Contorizează numărul de biţi 1 din întregul furnizat ca
• În afara conciziei,
argument.
/* bitcount: count 1 bits in x */
 ei corespund mai bine modului cum gândeşte
int bitcount(unsigned x) omul.
{  zicem „adună 2 la i” sau „incrementează pe i cu 2”
Declarând argumentul x ca fiind de tip unsigned
int b; ne asigurăm că la deplasarea spre dreapta,  nu zicem „ia-l pe i, adună-i 2, apoi pune rezultatul
înapoi în i”.
for ( b = 0; x != 0; x >>= 1 )
if ( x & 01 ) • Astfel expresia
biţii rămaşi liberi se vor umple cu zerouri
b++; şi nu cu bitul de semn (asta în funcţie de
i += 2
return b; maşina pe care rulează programul).  este preferabilă lui
} i = i + 2
17:52 PCLP CURS 5 89 17:52 PCLP CURS 5 90

PCLP CURS 5 15
09.11.2016

Expresii şi operatori de atribuire Valoarea instrucţiunii de atribuire


• Instrucțiunea de atribuire are o valoare ce poate
• Pentru expresii complicate precum: apare în expresii:
yyval[yypv[p3+p4] + yypv[p1]] += 2 while ((c = getchar()) != EOF) ...

 operatorul de atribuire face codul mai uşor de • Ceilalți operatori de atribuire (+=, -= etc.) pot apărea
înţeles, și ei în expresii
 deoarece cititorul nu o să stea să verifice dacă cele  deși acest lucru este mai puțin frecvent.
două expresii lungi sunt la fel,
• În toate expresiile de acest gen:
 sau să se întrebe de ce nu sunt.
 tipul de dată al expresiei de atribuire este
• Un operator de atribuire ajută compilatorul să tipul operandului din stânga
producă un cod eficient.  valoarea este valoarea de după atribuire.
17:52 PCLP CURS 5 91 17:52 PCLP CURS 5 92

9. Expresii condiționale Expresii condiţionale


if (a > b) • În expresia
z = a; expr1 ? expr2 : expr3
else
z = b;  expresia expr1 este evaluată prima.
• atribuie lui z cea mai mare valoare dintre a și b.  dacă este nenulă (i.e. adevărată), este evaluată expr2
 și aceasta este valoarea expresiei condiționale.
• Expresia condițională scrisă cu operatorul ternar
 altfel, este evaluată expr3
?:  și aceasta este valoarea expresiei condiționale.
 furnizează o variantă pentru a scrie secvența de
cod de mai sus și alte construcții similare. • Numai una dintre expr2 sau expr3 este evaluată.
17:52 PCLP CURS 5 93 17:52 PCLP CURS 5 94

Expresii condiţionale • Dacă f este float, iar n este int, atunci expresia:
• Astfel pentru a atribui lui z cea mai mare valoare (n > 0) ? f : n
dintre a și b, vom scrie:  este de tip float indiferent că n e pozitiv sau nu
z = (a > b) ? a : b; /* z = max(a, b) */ • Parantezele nu sunt necesare în jurul primei expresii
(expr1) a unei expresii condiționale,
• Expresia condițională este într-adevăr o expresie și  deoarece prioritatea operatorului ?: este foarte
poate fi utilizată în orice loc unde poate să apară scăzută, exact deasupra atribuirii.
orice altă expresie.
• Cu toate acestea ele sunt recomandate
• Dacă expr2 și expr3 sunt de tipuri diferite,  fac partea de condiție a expresiei condiționale mai lizibilă
 tipul rezultatului este determinat de regulile de
• Expresia condițională adesea conduce la un cod succint.
conversie discutate anterior.
17:52 PCLP CURS 5 95 17:52 PCLP CURS 5 96

PCLP CURS 5 16
09.11.2016

• Ciclul de mai jos afișează primele n elemente ale unui Exemplu ilustrativ
tablou, Chiar dacă pare complicat este mai
 10 pe linie, compact decât echivalentul cu if-else
 fiecare coloană separată de un blank,
 iar fiecare linie (inclusiv ultima) terminată cu newline.
for ( i = 0; i < n; ++i)
printf("%6d%c", a[i],
(i%10 == 9 || i == n-1) ? '\n' : ' ');
• O linie nouă este afişată
 după fiecare al 10-lea element şi totodată
 după al n-lea.
• Toate celelalte elemente sunt urmate de un blank.
17:52 PCLP CURS 5 97 17:52 PCLP CURS 5 98

10. Prioritatea și ordinea evaluării


• Tabelul cu prioritatea şi asociativitatea operatorilor
P
din C Tabel cu prioritatea R
și asociativitatea
 rezumă regulile pentru prioritatea (precedența) și operatorilor din C
I
asociativitatea tuturor operatorilor, S O
c R
 inclusiv a acelora pe care nu i-am discutat încă.
a I
d
• Operatorii de pe aceiași linie au aceiași prioritate Operatorii unari & (adresă), +, -, *
T
e A
 liniile sunt în ordinea descrescătoare a priorității, (indirectare pointer) au o prioritate
mai mare decât variantele lor binare T
E
 de exemplu *, / și % au toți aceiași prioritate, () : apel de funcție
A
care este mai mare decât a operatorilor binari + și -
17:52 PCLP CURS 5 99 17:52
PCLP CURS 5 100

• Operatorul () se referă la apelul de funcţie.


• Să observăm că prioritatea
• Operatorii -> şi . sunt utilizaţi pentru a accesa  operatorilor logici pe biţi &, ^ şi |
câmpurile (membrii) structurilor
 este plasată sub == şi !=
 aceşti operatori îi vom discuta la capitolul Structuri
 împreună cu operatorul sizeof care determină
mărimea unui obiect • Aceasta implică deci că expresii de testare a biților
ca cea de mai jos:
• În capitolul despre Pointeri vom discuta operatorii
 * : indirectarea printr-un pointer şi if ((x & MASK) == 0) ...
 & : adresa unui obiect
 trebuie să folosească parantezele
• în capitolul despre Controlul execuției programelor
 pentru a da rezultate corecte.
vom discuta operatorul virgulă ,
17:52 PCLP CURS 5 101 17:52 PCLP CURS 5 102

PCLP CURS 5 17
09.11.2016

• C – ca multe limbaje – nu specifică ordinea în care • Similar, ordinea în care argumentele funcţiei sunt
operanzii unui operator sunt evaluați (excepție fac &&, evaluate nu este specificată,
||, ?: și ‘,‘).  astfel că instrucţiunea
• De exemplu, într-o instrucțiune ca: printf("%d %d\n", ++n, power(2, n)); /* Wrong */

x = f() + g(); poate produce rezultate diferite


 f poate fi evaluat înaintea lui g sau viceversa:  pe compilatoare diferite,
 astfel că dacă fie f fie g modifică o variabilă depinzând de faptul că n este incrementat sau nu
externă de care cealaltă funcție depinde,  înainte ca funcţia power să fie apelată.
 x poate depinde de ordinea evaluării.
• Soluția este să scriem:
 Un motiv în plus ca rezultatele intermediare să fie
memorate în variabile temporare (automate) pentru a ne ++n;
asigura că prelucrările se desfășoară așa cum dorim. printf("%d %d\n", n, power(2, n));
17:52 PCLP CURS 5 103 17:52 PCLP CURS 5 104

Efecte colaterale • În orice expresie care implică efecte colaterale


 pot exista dependențe subtile asupra ordinii în care
 Apelurile de funcţii, sunt actualizate variabilele care intră în alcătuirea
 instrucţiunile de atribuire şi expresiei.

 operatorii de incrementare şi decrementare • O situație nefericită tipică este dată de:


 produc „efecte colaterale” a[i] = i++;
 anumite variabile sunt modificate ca o consecință a
 Întrebarea este dacă indicele
evaluării unei expresii.
este valoarea veche a lui i sau cea nouă.
• Iată două exemple:
• Compilatoarele pot interpreta această atribuire în
x = y = y++; moduri diferite și să genereze diferite răspunsuri în
i = i++; funcție de interpretarea lor.
17:52 PCLP CURS 5 105 17:52 PCLP CURS 5 106

Concluzia

• Standardul lasă în mod intenționat


nespecificate multe astfel de chestiuni.

• Concluzia este:
 să nu scriem cod care depinde de ordinea
evaluării. III. CONTROLUL EXECUŢIEI
PROGRAMELOR

17:52 PCLP CURS 5 107

PCLP CURS 5 18
09.11.2016

1. Instrucţiuni şi blocuri
Control flow • O expresie precum
 x = 0 sau i++ sau printf(...)
devine o instrucţiune atunci când este
• Într-un limbaj de programare, controlul execuţiei  urmată de caracterul punct şi virgulă “;”, ca în:
programului (control flow) x = 0;
i++;
 specifică ordinea în care sunt efectuate calculele. printf(...);

• În C, caracterul punct şi virgulă este un terminator de


instrucţiune,
 mai degrabă decât un separator
 așa cum se întâmplă în alte limbaje, precum Pascal.
17:52 PCLP CURS 5 109 17:52 PCLP CURS 5 110

• Acoladele { şi } sunt utilizate pentru a grupa 2. Instrucţiunea if-else


declaraţii şi instrucţiuni
• Instrucţiunea if-else este utilizată pentru a exprima
 într-o instrucţiune compusă, sau BLOC,
decizii. Formal sintaxa ei este:
 astfel că ele sunt echivalente – din punct de vedere if (expresie)
sintactic – cu o singură instrucţiune. partea de else
instrucţiune1 este opţională
• Acoladele care mărginesc instrucţiunile unei funcţii else
sunt exemplul cel mai banal, instrucţiune2
 dar acoladele grupează mai multe instrucţiuni
• Prima dată este evaluată expresie
 după un if, else, while sau for.
 dacă este adevărată (i.e. dacă expresie are o valoare
• Variabilele pot fi declarate în interiorul oricărui bloc . nenulă), este executată instrucţiune1.
• Nu se pune punct şi virgulă după acolada dreapta de  dacă este falsă (i.e. dacă expresie este zero) şi dacă
închidere a unui bloc. există parte de else se execută instrucţiune2.
17:52 PCLP CURS 5 111 17:52 PCLP CURS 5 112

Instrucţiunea if-else • Deoarece partea de else a unui if-else este


opţională,
• Deoarece if testează valoarea numerică a unei
expresii,  există o anumită ambiguitate în situaţiile când un
else este omis dintr-o secvenţă de if-uri imbricate.
 sunt posibile anumite simplificări ale codului.
• Aceasta se rezolvă asociind pe else cu cel mai
• Cea mai evidentă este scrierea: apropiat if fără else situat înaintea lui.
if (expresie) if (n > 0)
în loc de: • De exemplu, în:
if (a > b)
if (expresie != 0) else se asociază cu if-ul z = a;
else
• Uneori acest lucru este clar şi normal interior, aşa cum se vede şi z = b;
din indentare.
 alteori poate fi mai greu de înţeles.
17:52 PCLP CURS 5 113 17:52 PCLP CURS 5 114

PCLP CURS 5 19
09.11.2016

Folosiţi acoladele • Ambiguitatea este periculoasă în situații ca:


if (n > 0) Indentarea arată fără
for (i = 0; i < n; i++) echivoc ceea ce doriţi,
• Dacă nu reușiți, folosiți acoladele pentru a if (s[i] > 0) { dar compilatorul nu va
forța asocierea dorită. înţelege această dorinţă
printf("...");
şi va asocia pe else cu
return i;
if (n > 0) { if-ul interior.
}
if (a > b) else /* WRONG */
printf("error -- n is negative\n");
z = a;
} • Acest tip de bug (eroare software) este greu de
else detectat;
 cel mai bine este să folosiți acolade atunci când lucrați
z = b;
cu if-uri imbricate.
17:52 PCLP CURS 5 115 17:52 PCLP CURS 5 116

• Să observăm că există un punct şi virgulă după 3. Construcţiile else-if


z=a • Construcţia:
în: if (expresie) Apare atât de des încât
if (a > b) instrucţiune merită o discuţie separată.
z = a; else if (expresie)
else instrucţiune
z = b; else if (expresie) • Această secvenţă de
• Aceasta deoarece, din punct de vedere instrucţiune instrucţiuni if
gramatical, după if urmează o instrucţiune şi else if (expresie)
 reprezintă modul cel
instrucţiune
 o instrucţiune expresie ca ”z = a;” este mai general de a scrie
else
totdeauna încheiată cu punct şi virgulă. o decizie multiplă.
instrucţiune
17:52 PCLP CURS 5 117 17:52 PCLP CURS 5 118

• Expresiile sunt evaluate în ordine. • Dacă nu există nici o acțiune explicită de făcut,
• Dacă o expresie este adevărată, atunci partea
else
 instrucţiunea asociată cu ea este executată şi aceasta instrucţiune
încheie întreaga construcţie.
 poate să lipsească,
• Codul fiecărei instrucţiuni este reprezentat  sau poate fi utilizată pentru verificarea erorilor
 fie de o singură instrucţiune,  pentru a captura o condiţie „imposibilă”.
 fie de un grup de instrucţiuni grupate între acolade.
• Pentru a ilustra o decizie triplă, prezentăm în
• Ultimul else se referă la cazul în care nu s-a intrat pe continuare o funcţie de căutare binară
niciuna din ramurile anterioare  care decide dacă o valoare particulară x apare în
 adică nici o expresie nu a fost adevărată. tabloul sortat crescător v.
17:52 PCLP CURS 5 119 17:52 PCLP CURS 5 120

PCLP CURS 5 20
09.11.2016

Căutarea binară
• Funcţia returnează poziţia
Exemplu: n = 5, x = 3,
 un număr între 0 şi n-1 v = (-1, 2, 3, 9, 11)
dacă x apare în v şi => 2

 -1 0 1 2 3 4
dacă nu apare. -1 2 3 9 11

Algoritm de CĂUTARE BINARĂ • Căutarea binară compară mai întâi valoarea de


intrare x
 cu elementul din mijloc al tabloului v.
17:52 PCLP CURS 5 122

Căutarea binară int binsearch(int x, int v[], int n)


{ /* binsearch: find x in v[0] <= v[1] <= ... <= v[n-1] */
• Dacă x este mai mic decât valoarea din mijloc int low, high, mid;
Decizia triplă fundamentală
 căutarea se focalizează pe jumătatea din stânga (a low = 0; este dacă x
high = n - 1;
valorilor mai mici) tabloului,  este mai mic decât,
while (low <= high) {  mai mare decât sau
 altfel pe jumătatea din dreapta (a valorilor mai mari). mid = (low + high)/2;  egal cu
if (x < v[mid]) elementul din mijloc v[mid]
• În continuare se compară x cu elementul din mijloc al high = mid - 1;
• la fiecare pas al ciclului
jumătăţii selectate. else if (x > v[mid])
while.
low = mid + 1;
• Acest proces de divizare a domeniului de căutare în else /* found match */
două continuă până când: return mid;
 fie valoarea s-a găsit }
return -1; /* no match */
 fie domeniul a fost epuizat. }
17:52 PCLP CURS 5 123 17:52 PCLP CURS 5 124

switch (expresie) {
4. Instrucţiunea switch
case expresie-constantă: instrucţiuni
• Instrucţiunea switch este o decizie multiplă specială
case expresie-constantă: instrucţiuni
 ea determină transferul controlului unei instrucţiuni
sau unui bloc de instrucţiuni dintr-un şir de instrucţiuni default: instrucţiuni
 în funcţie de valoarea unei expresii. }

• switch testează dacă o expresie se potriveşte cu


• Fiecare instrucţiune din corpul instrucţiunii switch
poate fi etichetată cu una sau mai multe prefixe
 una dintr-un număr de expresii-constante, case astfel:
 determinând transferul controlului instrucţiunii (sau  case expresie-constantă:
blocului de instrucţiuni) asociat expresiei-constante
unde expresie-constantă trebuie să fie de tipul int şi
întregi alese.
poate fi o constantă sau o expresie constantă.
17:52 PCLP CURS 5 125 17:52 PCLP CURS 5 126

PCLP CURS 5 21
09.11.2016

• Poate exista, de asemenea, cel mult o instrucţiune • Dacă nici o expresie-constantă din nici un case nu
etichetată cu: este egală cu valoarea expresiei şi dacă există un
default: prefix default,
• Când o instrucţiune switch se execută, se  atunci se execută instrucţiunea de după default,
evaluează expresia din paranteze şi  altfel nici o instrucţiune din switch nu se execută.
 valoarea ei se compară cu fiecare expresie-
constantă din fiecare case. • Toate expresie-constantă din fiecare case trebuie să
fie diferite între ele.
• Dacă se găseşte o expresie-constantă din case
egală cu valoarea expresiei, • Ramura etichetată cu default, se execută
 atunci execuţia începe cu instrucţiunea care  dacă niciuna din case-urile existente nu este
urmează după case-ul respectiv. satisfăcută.
17:52 PCLP CURS 5 127 17:52 PCLP CURS 5 128

• Ramura default este opţională. #include <stdio.h>


• Dacă default nu există şi nici un case nu se int main() /* count digits, white space, others */

potriveşte {
int c, i, nwhite, nother, ndigit[10];
 atunci instrucţiunea switch nu face nimic.
nwhite = nother = 0;
• Ramurile case şi default pot apărea în orice for (i = 0; i < 10; i++)
ordine. ndigit[i] = 0;
while ((c = getchar()) != EOF) {
• Reluăm un program scris anterior prin care switch (c) {
număram apariţiile fiecărei cifre, a spaţiilor albe şi a case '0': case '1': case '2': case '3':
tuturor celorlalte caractere case '4': case '5': case '6': case '7':
case '8': case '9':
 înlocuind secvenţa if ... else if ... else cu ndigit[c-'0']++;
instrucţiunea switch break;
17:52 PCLP CURS 5 129 17:52 PCLP CURS 5 130

case ' ': case '\n': case '\t': • Instrucţiunea break determină o ieşire imediată din
nwhite++; switch.
break;
default: • Deoarece case-urile servesc doar ca etichete
nother++;  după ce codul unui case este efectuat, execuţia
break; continuă cu următorul case
} /* end switch */
 dacă nu se precizează explicit ieşirea din switch.
} /* end while */
printf("digits ="); • Pentru ieşirea din switch se folosesc
for (i = 0; i < 10; i++)
printf(" %d", ndigit[i]);
 instrucţiunile break sau return.
printf(", white space = %d, other = %d\n",
• O instrucţiune break poate fi utilizată de asemenea
nwhite, nother);
return 0;
pentru a forţa o ieşire imediată
}  din ciclurile while, for şi do aşa cum vom vedea.
17:52 PCLP CURS 5 131 17:52 PCLP CURS 5 132

PCLP CURS 5 22
09.11.2016

• Alunecarea de la un case la altul • Continuarea execuţiei de la un case la altul


 în absenţa unui break sau return  nu este o chestiune robustă la actualizări ale
are avantaje şi dezavantaje. codului,
• Avantajul este dat de faptul că se pot ataşa mai  fiind predispusă la dezintegrare când programul se
multe case-uri la o singură acţiune modifică.
 vezi cazul cifrelor din programul anterior
• Cu excepţia mai multor etichete case pentru un
• În mod normal, fiecare case trebuie să se singur calcul,
termine cu un break,  continuarea execuţiei programului cu următorul
 pentru a evita continuarea execuţiei programului case trebuie utilizată moderat şi însoţită de
cu următorul case. comentarii.
17:52 PCLP CURS 5 133 17:52 PCLP CURS 5 134

• Ca o indicaţie de programare puneţi un break BIBLIOGRAFIE


după ultima etichetă case
 în programul nostru după default [1] Kernighan, B., Ritchie, D., The C Programming
Language, ediția a II-a, Ed. Prentice Hall, 1988.
 chiar dacă nu este necesar din punct de vedere
logic.

• Ulterior la modificarea programului, când un alt


case va fi adăugat la finalul instrucţiunii
switch,
 acest stil de programare defensivă vă va salva de
posibile erori.
17:52 PCLP CURS 5 135 17:52 PCLP CURS 5 136

PCLP CURS 5 23

S-ar putea să vă placă și