Instrucţiunea do … while


Are următoarea structură:
do
{
/* grup de instructiuni */
}
while (conditie);
Semnificaţia instrucţiunii este: se execută grupul de instrucţiuni cât timp condiţia este
adevărată. Părăsirea ciclării se poate face forţat de asemenea cu break.
Instrucţiunea do…while din C este echivalentă instrucţiunii repetitive repetă…până când
din pseudo-cod, deosebirea esenţială constă în faptul că la instrucţiunea din C ciclarea se opreşte
când condiţia devine falsă, pe când la instrucţiunea din pseudo-cod ciclarea se încheie când
condiţia devine adevărată. Cu alte cuvinte condiţia din instrucţiunea do…while este negaţia
condiţiei de la instrucţiunea repetă…până când.
Luăm ca exemplu sortarea crescătoare unui şir prin metoda bulelor (BubbleSort). Despre
tablouri de elemente (vectori, matrici) o să vorbim mai târziu. Ceea ce ne interesează acum,
pentru a înţelege exemplul de mai jos, este faptul că indicii vectorilor se dau între paranteze
pătrate [], iar în momentul declarării unui vector putem enumera elementele sale între acolade.
int ok, n=5, a[5]={4, 2, 5, 7, 0};
do
{
ok=1;
for (i=0;i<n-1;i++)
if (a[i]>a[i+1])
{
aux=a[i];
a[i]=a[i+1];
a[i+1]=aux;
ok=0;
}
}
while (!ok);

Instrucţiunea While.

Instrucţiunea While.


Instrucţiunea while are următoarea structură:

while (conditie)
{
/* grup de instructiuni */
}
Semnificaţia instrucţiunii este: cât timp condiţia este adevărată, se execută grupul de
instrucţiuni. Părăsirea ciclării se poate face forţat cu break.

Calcularea celui mai mare divizor comun a două numere întregi folosind instrucţiunea
while poate fi scrisă astfel:
long a,b,x,y,r;
printf("Dati doua numere întregi: ");
scanf("%ld%ld",&a,&b);
x=a; y=b;
while (y) { r=x%y; x=y; y=r; }
printf("Cmmdc(%ld,%ld)=%ld\n"),a,b,x);
printf("Cmmmc(%ld,%ld)=%ld\n"),a,b,a/x*b);

Instrucţiuni repetitive

Instrucţiunea for.

Instrucţiunea for.

În C, instrucţiunea repetitivă for este destul complexă. Ea are următoarea structură:
for (expresie_1; expresie_2; expresie_3)
{
/* grup de instructiuni */
}

Semnificaţia instrucţiunii este:
1) Se evaluează expresie 1. Această expresie conţine în general iniţializări de variabile.

2) Cât timp valoarea expresiei 2 este adevărată (nenulă), se execută grupul de
instrucţiuni. Această expresie reprezintă condiţia de oprire a ciclării.

3) După fiecare iteraţie se evaluează expresie 3. Această expresie conţine în general
actualizări ale unor variabile (incrementări, decrementări etc.).

Prezentăm câteva caracteristici ale instrucţiunii for:
1) Oricare dintre cele 3 expresii poate lipsi. Lipsa expresiei 2 este echivalentă cu valoarea 1
(de adevăr). Părăsirea ciclului for în această situaţie se poate face în general cu break.
2) În prima expresie pot apărea mai multe iniţializări, care se dau cu ajutorul operatorului
virgulă (vezi subcapitolul dedicat operatorilor). De asemenea, ultima expresie poate
conţine mai multe actualizări despărţite prin virgulă.
Ca aplicaţie pentru instrucţiunea for, calculăm suma primelor n numere întregi pozitive
(valoarea lui n este citită de la tastatură) şi cel mai mare divizor comun pentru două numere
întregi (preluate tot de la tastatură) folosind algoritmul lui Euclid:

long s,i,n,a,b,x,y;
printf("n="); scanf("%ld",&n);
for (s=0,i=0; i<n; i++) s+=i; /* Calculare: 1+2+...+n */
printf("Suma primelor %ld numere intregi pozitive este %ld\n",n,s);
printf("Dati doua numere intregi: ");
scanf("%ld%ld",&a,&b);
for (x=a,y=b; y; r=x%y,x=y,y=r); /* Calculare Cmmdc(a,b) */
printf("Cmmdc(%ld,%ld)=%ld\n"),a,b,x);
printf("Cmmmc(%ld,%ld)=%ld\n"),a,b,a/x*b);

Rezumat:Instriunea IF si Switch

În C avem două instrucţiuni de decizie: instrucţiunea if, care are una sau două ramuri
(ramura else poate lipsi) şi instrucţiunea switch (cu oricâte ramuri). Expresia după care se face
selecţia ramurii case trebuie să aibă o valoare întreagă. De asemenea, de reţinut este şi faptul că
în principiu, fiecare ramură a instrucţiunii switch se termină cu un apel break.

Instrucţiuni de decizie.

Instrucţiunea switch

Instrucţiunea switch.
*switch este o instrucţiune decizională multiplă (cu mai multe ramuri). Structura ei este
următoarea:
switch (expresie_intreaga)
{
case val1:
/* grupul de instructiuni 1 */
break;
case val2:
/* grupul de instructiuni 2 */
break;
/* .... */
case valn:
/* grupul de instructiuni n */
break;
default:
/* grupul de instructiuni n+1 */
}
Semnificaţia instrucţiunii este: Se evaluează expresia expresie_intreaga care trebuie sa
aibă o valoare întreagă. Avem următoarele situaţii:
 Dacă valoarea expresiei este egală cu val1, atunci se execută grupul de instrucţiuni 1.
 Dacă valoarea expresiei este egală cu val2, atunci se execută grupul de instrucţiuni 2.
…………….
 Dacă valoarea expresiei este egală cu val n, atunci se execută grupul de instrucţiuni n.
 Dacă valoarea obţinută în urma evaluării expresiei nu este egală cu nici una dintre
valorile val1, … , valn, atunci se execută grupul de instrucţiuni n+1.
Să facem câteva observaţii:
1) La instrucţiunea switch grupurile de instrucţiuni de pe ramuri nu trebuiesc
delimitate cu acolade. Nu este greşit însă dacă le delimităm totuşi cu acolade.
18
2) După fiecare grup de instrucţiuni punem în general instrucţiunea break. În lipsa
instrucţiunii break se execută şi instrucţiunile de pe ramurile de mai jos până la
sfârşitul instrucţiunii switch (inclusiv cele de pe ramura default) sau până se
întâlneşte primul break. Instrucţiunea break întrerupe execuţia instrucţiunii switch
şi a celor repetitive (for, while şi do ... while).
3) Ramura default poate lipsi.
4) Dacă există ramura default, nu este obligatoriu să fie ultima.
5) Valorile val1, val2, …, valn trebuie să fie constante întregi şi distincte două câte
două.
Spre exemplificare considerăm o secvenţă de program pentru calcularea într-un punct a
valorii unei funcţii f cu trei ramuri:

int x;
printf("Dati un numar întreg: ");
scanf("%d",&n);
printf("Valoarea functiei este f(%d)=",x);
switch (x)
{
case 0:
printf("-1"); break;
case 1:
printf("-2"); break;
default:
printf("%d",x+1); break;
}

Instrucţiunea if

Instrucţiunea if.
În C o instrucţiune de tipul dacă …atunci …altfel are următoarea structură:
if (conditie)
{
/* grupul de instructiuni 1 */
}
else
{
/* grupul de instructiuni 2 */
}
Semnificaţia instrucţiunii este: dacă este adevărată condiţia, atunci se execută grupul de
instrucţiuni 1, altfel se execută grupul de instrucţiuni 2. Ramura else poate lipsi.
17
Un grup de instrucţiuni în C se delimitează cu ajutorul acoladelor {}. Dacă un grup este
format dintr-o singură instrucţiune, atunci acoladele pot lipsi.

Dăm un exemplu ilustrativ pentru instrucţiunea if :



float x=2.2, y=4;
int a=25, b=85;
if (x>y) max=x; else max=y;
if (a)
{
printf("Restul impartirii este: %d\n",b%a);
printf("Catul impartirii este: %d",b/a);
}
else perror("Impartire prin 0!");

Funcţii de scriere şi citire în C (capitolul 3)

Rezumat: Printf si Scanf

Afişarea formatată a mesajelor pe ecran se face cu ajutorul funcţiei printf, iar preluarea
formatată a datelor de la tastatură se face folosind funcţia scanf. Pentru a utiliza aceste funcţii
trebuie să includem fişierul antet stdio.h.

Functia scanf

Funcţia scanf este folosită pentru preluarea formatată de la tastatură a valorilor pentru
variabile. Funcţia are următoarea structură:
scanf(const_sir_caractere, lista_adrese_var_citite);
constanta_sir_caractere este un string care conţine numai descriptorii de tip ai
variabilelor ce se citesc. Descriptorii sunt cei elementari pe care i-am prezentat mai sus (vezi
funcţia printf), adică: %c, %s, %d, %u, %ld, %lu, %x, %X, %o, %f, %e, %E, %g, %G, %lf, %le,
%lE, %lg, %lg, %Lf, %Le, %LE, %Lg, %LG, %p.

În exemplul următor apar câteva citiri de la tastatură:
# include <stdio.h>
void main()
{
int n;
float f;
char s[10]; /* sir de caractere */
scanf("%d%f%s",&n,&f,s);
printf("Am citit: %d, %f,%s",n,f,s);
}
Facem observaţia că prin &var se înţelege adresa la care se află reţinută în memorie
variabila var. În C valorile se returnează prin adresă prin intermediul parametrilor unei funcţii.
Variabila s este deja un pointer către zona de memorie în care se memorează un şir de
caractere, aşadar nu este necesar să punem semnul & (şi) în faţa lui s la citire. Dacă se pune
totuşi semnul & în faţa variabilei s la citire, nu se semnalează eroare nici măcar atenţionare,
“pleonasmele” în C în general sunt ignorate de compilator. Vom reveni cu mai multe explicaţii
când vom vorbi despre pointeri şi tablouri (şiruri).
Pentru funcţiile printf şi scanf există şi variantele pentru scriere, respectiv citire în/dintrun
string sau fişier text.
Numele funcţiilor pentru string-uri încep cu litera s (sprintf, respectiv sscanf) şi
funcţionează absolut la fel ca cele obişnuite numai că destinaţia scrierii, respectiv sursa citirii
este un string. În consecinţă mai apare un parametru suplimentar (variabila şir de caractere) în
faţa celor pe care îi au funcţiile printf şi scanf.
Numele funcţiilor de scriere şi citire pentru fişiere text încep cu litera f (fprintf, respectiv
fscanf). Aceste funcţii au un parametru suplimentar (variabila pointer către tipul FILE).
16
Asupra acestor funcţii o să revenim atunci când o să discutăm despre string-uri, respectiv
fişiere.
În Borland C pentru DOS există variantele cprintf, respectiv cscanf ale funcţiilor printf,
respectiv scanf pentru scriere şi citire formatată într-o fereastră text (creată cu funcţia window).
Facem observaţia că schimbarea culorii textului şi a fundalului pe care se afişează un text are
efect în cazul utilizării funcţiei cprintf, dar nu are efect atunci când se foloseşte funcţia printf. De
asemenea, pentru salt la începutul unei linii trebuie să punem pe lângă \n şi secvenţa escape \r, ca
să se revină la începutul rândului, ceea ce nu era necesar în cazul funcţiei printf, secvenţa escape
\n fiind suficientă.
Trebuie precizat faptul că funcţia printf nu ţine cont de marginile ferestrei text definite cu
window. Ca parametri, funcţia window primeşte cele 4 coordonate ecran text ale colţurilor
stânga-sus şi respectiv dreapta-jos ale ferestrei.

Funcţia printf .

Funcţia printf.

Funcţia printf este folosită pentru afişarea formatată a unui mesaj pe ecranul monitorului.
Ea are următoare structură:
printf(constanta_sir_de_caractere, lista_expresii);
Funcţia printf afişează pe ecranul monitorului constanta_sir_de_caractere în care toţi
descriptorii de format se în locuiesc cu valorile expresiilor, înlocuirea făcându-se de la stânga
spre dreapta.
Dăm un exemplu:
# include <stdio.h>
void main()
{
int n=10;
float x=5.71;
printf("Un nr. intreg: %d si un nr. real: %f\n",n,x);
}
În C, în momentul declarării variabilelor, ele pot fi şi iniţializate (aşa cum am procedat în
exemplul de mai sus pentru n şi x).
%d şi %f sunt specificatori (descriptori) de format pentru tipurile de date int şi respectiv
float. Descriptorii specifică faptul că în locul în care se află în şirul de caractere ce se afişează pe
ecran vor apărea valori de tipul indicat, valori ce vor fi luate din lista de expresii aflată după şirul
de caractere. În exemplul nostru lista de expresii este alcătuită din valorile n şi x.
Înlocuirea descriptorilor în constanta de tip şir de caractere (primul parametru al funcţiei
printf) se face de la stânga spre dreapta. În exemplul de mai sus %d va fi înlocuit cu valoarea
reţinută în variabila n, adică 10, iar %f se înlocuieşte cu valoarea lui x, adică 5.71.
Dacă tipurile expresiilor ce se înlocuiesc nu corespund cu descriptorii de format, sau dacă
numărul descriptorilor nu este egal cu cel al expresiilor ce se înlocuiesc, nu se semnalează
eroare, nici măcar atenţionare la compilare, dar afişarea va fi eronată!
Dăm în continuare lista cu descriptorii de format sau descriptorii de tip, cum se mai
numesc:
%c – caracter (char)
%s – şir de caractere încheiat cu caracterul ‘\0’ (string)
%d – întreg cu semn (int)
%u – întreg fără semn (unsigned int)
%ld – întreg lung (pe 4 octeţi) cu semn (long)
%lu – întreg lung (pe 4 octeţi) fără semn (unsigned long)
%x – întreg în baza 16 fără semn (int) (cifrele în hexazecimal pentru 10, 11, 12, 13, 14, 15
sunt litere mici, adică a, b, c, d, e şi f)
%X – la fel ca %x, numai ca cifrele în hexazecimal pentru sunt litere mari
%o – întreg în baza 8 fără semn (int)
%f – real pe 6 octeţi (float), notaţie zecimală (fără exponent)
%e – real pe 6 octeţi (float), notaţie exponenţială, ştiinţifică (litera e de la exponent este mică)
%E – la fel ca %e, numai că pentru litera de la exponent este mare
%g – real pe 6 octeţi (float), notaţie zecimală sau exponenţială, care este mai scurtă, iar dacă
se afişează exponenţial, atunci litera de la exponent este e

%G – real pe 6 octeţi (float), notaţie zecimală sau exponenţială, care este mai scurtă, iar dacă
se afişează exponenţial, atunci litera de la exponent este E
%lf – real pe 8 octeţi (double), notaţie zecimală
%le – real pe 8 octeţi (double), notaţie exponenţială (litera exponent e este mică)
%lE – la fel ca la %le, numai litera exponent E este mare
%lg – real pe 8 octeţi (double), notaţie zecimală sau exponenţială, care e mai scurtă, dacă e
cazul se foloseşte literă mică pentru exponent
%lG – real pe 8 octeţi (double), notaţie zecimală sau exponenţială, care e mai scurtă, dacă e
cazul se foloseşte literă mare pentru exponent
%Lf – real pe 10 octeţi (long double), notaţie zecimală
%Le – real pe 10 octeţi (long double), notaţie exponenţială (litera de la exponent este mică,
adică e)
%LE – real pe 10 octeţi (long double), notaţie exponenţială (litera de la exponent este mare,
adică E)
%Lg – real pe 10 octeţi (long double), notaţie zecimală sau exponenţială, care este mai scurtă,
literă mică pentru exponent
%LG – real pe 10 octeţi (long double), notaţie zecimală sau exponenţială, care este mai scurtă,
literă mare pentru exponent
%p – adresa în hexazecimal (pentru pointeri).
La afişarea folosind funcţia printf se pot face formatări suplimentare, pornind de la un
descriptor elementar. Formatările se referă la numărul de caractere pe care se face afişarea unei
valori, tipul alinierii, caracterele ce se completează în locurile libere (spaţii, zerouri) etc. Dăm în
acest sens câteva exemple:
%50s realizează afişarea unui string pe 50 caractere cu aliniere la dreapta, iar %-50s face
acelaşi lucru, dar cu aliniere la stânga. De obicei string-urile se aliniază la stânga.
%4d realizează afişarea unui număr întreg pe 4 caractere cu aliniere la dreapta, iar %-4d
face acelaşi lucru, dar cu liniere la stânga. De obicei valorile numerice se aliniază la dreapta.
%10.2f realizează afişarea unui număr real pe 10 caractere cu 2 cifre exacte după virgulă,
cu aliniere la dreapta, iar %-10.2f face acelaşi lucru, dar cu aliniere la stânga.
%010.2f realizează afişarea unui număr real pe 10 caractere cu 2 cifre exacte după
virgulă, cu aliniere la dreapta, iar spaţiile goale (din faţa numărului) se completează cu zerouri.
De exemplu, numărul 1.4 se va afişa sub forma 0000001.40. Dacă nu se pune 0 în faţa lui 10.2f,
atunci în loc de zerouri se completează implicit spaţii.
În programul de mai sus (afişarea unui întreg şi a unui număr real), după afişarea pe ecran
a mesajului, se sare la începutul liniei următoare, deoarece şirul s-a încheiat cu \n. Combinaţia de
caractere \n este una dintre aşa numitele secvenţe escape.
Lista secvenţelor escape recunoscute de limbajul C este:
\n – salt la linie nouă (nu neapărat la începutul lui)
\r – salt la început de rând
\t – deplasare la dreapta (tab)
\b – deplasare la stânga cu un caracter (backspace)
\f – trecere pe linia următoare (formfeed)
\’ – apostrof
\” – ghilimele
\\ – backslash

\xcc – afişarea unui caracter având codul ASCII în hexazecimal dat de cele două cifre de
după \x (fiecare c reprezintă o cifră în baza 16). De exemplu, \x4A este caracterul cu codul ASCII
4A(16) = 74(10), adică litera J.
Este bine de reţinut faptul că într-un şir constant de caractere, semnul \ (backslash)
trebuie dublat. Asta se întâmplă mai ales când este vorba de căi de fişiere. De asemenea, semnele
“ (ghilimele) şi ‘ (apostrof) trebuiesc precedate de semnul \ (backslash).
În C pentru a trimite un mesaj în fluxul standard de erori stderror folosim funcţia perror,
în loc de printf. Mesajul de eroare ajunge tot pe ecranul monitorului, dar pe altă cale. Datorită
faptului că funcţia perror nu suportă formatare aşa cum face printf, în exemplele pe care o să le
dăm în această carte vom folosi funcţia printf pentru afişarea mesajelor de eroare.

Tipuri de date (Cap 2)

Mai jos aveti prezentat cuprinsul capitolului Tipuri de date in c

Lectia 1 - Tipuri de date
Lectia 2 - Operatori numere intregi.
Lectia 3 - Operatori numere reale.

Structura unui program in C (Cap 1)

Tipuri reale de date(Curs3)


2.4. Operatorii C pentru valori reale
Pentru tipurile reale de date în C sunt definiţi operatorii:
- Operatorul de atribuire =.
- Operatorii aritmetici binari: + (adunare), - (scădere), * (înmulţire), / (împărţire).
- Operatorii aritmetici binari combinaţi cu atribuire +=, -=, *=, /=.
- Operatorii relaţionali, not şi de incrementare, respectiv decrementare
funcţionează şi pentru valori reale.
2.5. Alţi operatori în C
Operatorii logici: && (şi), || (sau), ! (not). Dăm un exemplu de expresie logică: (a &&
!(b%2) && (a>b || b<=0)).
Operatorul ?: este singurul operator ternar (funcţionează cu trei operanzi) din C şi se
foloseşte astfel: var = (expresie_logică) ? val1:val2 cu semnificaţia: se evaluează
expresie_logică, dacă expresia are valoare de adevărat (diferită de 0), atunci variabila var ia
valoarea val1, altfel var primeşte valoarea val2.
Operatorul [] este pentru acces la elementul unui vector. De exemplu, a[1] reprezintă al
doilea element al şirului a, deoarece în C indicii vectorilor încep cu 0. Este interesant faptul că în
C dacă scriem 1[a] înseamnă acelaşi lucru !
12
Operatorul () este folosit pentru a realiza o conversie de tip (exemplu: (float)n
converteşte valoarea din variabila n la tipul float, dacă acest lucru este posibil).
Operatorul sizeof dă dimensiunea în octeţi pe care o ocupă în memorie valoarea
rezultată în urma evaluării unei expresii. De exemplu, expresia sizeof 1+2.5 are valoarea 6,
deoarece rezultatul expresiei 1+2.5 este o valoare de tip float, care se reprezintă în memorie pe 6
octeţi. În C există şi funcţia sizeof(tip) care returnează numărul de octeţi necesari pentru stocarea
în memorie a unei valori de tipul tip. De exemplu, sizeof(short) returnează valoarea 2.
Operatorul , (virgulă) se aplică între două expresii care se evaluează după regula: se
evaluează întâi prima expresie şi apoi a doua (cea din dreapta), rezultatul returnat de operator
fiind valoarea ultimei expresii. De exemplu, expresia x = 2, x – 4 are valoarea –2. De obicei, o
expresie în care apare operatorul virgulă se pune între paranteze pentru eliminarea eventualelor
ambiguităţi. Dacă folosim de mai multe ori operatorul virgulă: expr1, expr2, … , exprn, atunci
execuţia se face de la stânga spre dreapta. De exemplu, expresia x=1, x+4, x*2 are valoarea 2, iar
expresia x=1, x+=4, x*2 are valoarea 10.

Operatorii din C pentru valori întregi (Curs 2)

    Operatorul = (egal) este folosit pentru atribuirea valorii unei expresii întregi unei
variabile întregi:
i = expresie;
Operatorul returnează valoarea atribuită variabilei i, valoare rezultată în urma evaluării
expresiei şi conversiei la tipul variabilei i, în cazul nostru fiind vorba de tipul int. Astfel, de
exemplu i = 1 + sqrt(2) este o expresie care are valoarea 2.
Pentru tipurile întregi de date sunt definiţi operatorii aritmetici binari: + (adunare), -
(scădere), * (înmulţire), / (câtul împărţirii), % (restul împărţirii), +=, -=, *=, /=, %=, unde
expresia x += y este echivalentă cu x = x+y.
Operatori aritmetici unari definiţi pentru tipurile întregi de date sunt: ++ şi --. Ei
realizează incrementarea, respectiv decrementarea unei variabile întregi. Astfel, x++ este
echivalent cu x = x+1, iar x-- cu x = x-1. Cei doi operatori unari se folosesc sub două forme:
x++, x--, adică forma postincrementare, respectiv postdecrementare, iar ++x, --x sunt sub forma
preincrementare, respectiv predecrementare. Să explicăm acum care este diferenţa dintre cele
două forme de utilizare a operatorului de incrementare.
Presupunem că variabila y reţine valoarea 1. Pentru o expresie de forma x = ++y, întâi se
incrementează y şi apoi noua valoare a lui y se atribuie lui x şi, în consecinţă, x devine 2. Dacă
operatorul ++ se foloseşte în forma postincrementată, adică x = y++, atunci lui x întâi i se
atribuie valoarea variabilei y şi abia după aceea se face incrementarea lui y. În această situaţie
variabila x va fi iniţializată cu valoarea 1. Operatorul de decrementare -- funcţionează în mod
similar ca şi ++, tot sub două forme, predecrementare şi postdecrementare.
Operatorii relaţionali sunt: < (mai mic), <= (mai mic sau egal), > (mai mare), >= (mai
mare sau egal), == (egalitate), != (diferit). Cu alte cuvinte, cu ajutorul acestor operatori, două
valori întregi se pot compara.
Operatorul ! (semnul exclamării) aplicat unei valori numerice are efectul not, adică din
punct de vedere boolean îi schimbă valoarea (din False în True, respectiv din True în False).
Astfel, !x are valoare 0 dacă şi numai dacă x este nenul.
Operatori la nivel de bit aplicabili numai pe valori întregi sunt: & (şi pe biţi), | (sau pe
biţi), ^ (sau exclusiv), >> (shift-are biţi la dreapta), << (shift-are biţi la stânga), ~ (not pe biţi).
Pentru a înţelege cum funcţionează aceşti operatori dăm următorul exemplu:
Fie a şi b două variabile întregi pe un octet, a reprezentat pe biţi este (1,0,1,1,0,1,1,1) şi b
= (0,1,1,1,0,0,1,0).
11
Avem: a & b = (0,0,1,1,0,0,1,0), a | b = (1,1,1,1,0,1,1,1), a ^ b = (1,1,0,0,0,1,0,1), a >> 1
= (0,1,0,1,1,0,1,1), a << 1 = (0,1,1,0,1,1,1,0), ~a = (0,1,0,0,1,0,0,0).
Facem observaţia că dacă a este întreg cu semn (de tip char), atunci a >> 1 =
(1,1,0,1,1,0,1,1), deoarece cel mai semnificativ bit (cel mai stânga) reprezintă semnul numărului
întreg şi în consecinţă după shift-are la dreapta rămâne tot 1 (corespunzător semnului minus). Să
observăm că shift-area cu n biţi a unei valori întregi este echivalentă cu o împărţire la 2n. În cazul
exemplului nostru a >> 1 este echivalent cu a = a / 2.
Pentru operatorii pe biţi avem şi variantele combinate cu atribuire: &=, |=, ^=, <<=, >>=,
unde x &= y este echivalent cu x = x & y etc.

Tipuri numerice de date (Curs1)

Ne propunem să facem cunoştiinţă cu tipurile numerice de date ale limbajului C, modul
lor de reprezentare în memorie, domeniul de valori, operatorii specifici acestor tipuri de date
precum şi cu alţi operatori pe care îi întâlnim în C.
În C şi C++ avem două categorii de tipuri numerice de date: tipuri întregi şi reale. Cu cele
două clase de tipuri numerice se lucrează diferit (la nivel de procesor). Reprezentarea informaţiei
în memorie este diferită, avem operatori diferiţi.
2.1. Tipuri întregi de date
În tabelul de mai jos sunt prezentate tipurile numerice întregi cu semn (signed) şi fără
semn (unsigned) din C. Facem observaţia că numărul de octeţi pe care se reprezintă în memorie
valorile întregi şi implicit domeniile de valori din tabelul următor sunt cele pentru Windows, mai
exact, cele din Visual C:


Denumire tip   |   Număr octeţi     |     Domeniu de valori
(signed) char              1                         -128 la 128
unsigned char             1                               0 la 255
enum                          2                      -32.768 la 32.767
short (signed) (int)        2                           0 la 65.535
short unsigned (int)      2                    -32.768 la 32.767
(signed) int                   4                   -2.147.483.648 la 2.147.483.647
unsigned int                 4                       0 la 4.294.967.295
(signed) long                4                  -2.147.483.648 la 2.147.483.647
unsigned long              4                       0 la 4.294.967.295



Să facem câteva observaţii:
i. În Visual C tipul enum coincide cu tipul short int, iar tipul int coincide cu long.
10
ii. Tot ceea ce apare între paranteze rotunde în tabelul de mai sus este opţional.
iii. Tipurile numerice de date au o dublă utilizare în C şi C++: pentru valori numerice
(numere) şi pentru valori booleene. Astfel, o valoare numerică nenulă (întreagă
sau reală) corespunde în C/C++ valorii booleene de adevărat (true), iar o valoare
numerică nulă corespunde valorii booleene de fals (false)
iv. Tipurile char şi unsigned char în C şi C++ au o triplă întrebuinţare: pentru valori
întregi pe un octet, pentru valori booleene şi pentru caractere. Valoarea întreagă
de tip char reprezintă codul ASCII al unui caracter. Astfel, constanta de tip char
‘a’ reprezintă valoarea întreagă 97, care este de fapt codul ASCII al caracterului a.
Cu alte cuvinte, în C ‘a’ este acelaşi lucru cu 97 !
v. În Visual C pentru caractere Unicode este definit tipul wchar_t pe doi octeţi

Funcţia main (Curs 5)


  În orice program C/C++ trebuie să existe o unică funcţie main (principală), din interiorul
căreia începe execuţia aplicaţiei.
Pentru a înţelege mai bine modul de definire al funcţiei main vom prezenta pe scurt
câteva generalităţi legate de modul de definire al unei funcţii oarecare.
În C şi C++ nu există proceduri, ci numai funcţii. În definiţia unei funcţii tipul returnat se
pune înaintea numelui funcţiei. Dacă în momentul definirii funcţiei se omite tipul returnat, nu
este greşit şi se consideră implicit tipul returnat ca fiind int. O funcţie care are ca tip returnat void
(vid) se apelează ca o procedură. Dacă o funcţie nu are parametri, după nume se pun paranteze
rotunde sau se pune cuvântul rezervat void între paranteze rotunde în momentul definirii ei.
Funcţia main poate avea ca tip returnat void sau int (care se pune înaintea cuvântului
main). Dacă tipul returnat este int, atunci în interiorul funcţiei main pot apărea instrucţiuni de
forma return val_int care au ca efect întreruperea execuţiei programului şi returnarea către
sistemul de operare a valorii întregi val_int. În această situaţie, ultima instrucţiune din funcţia
main este de obicei return 0, ceea ce înseamnă că programul s-a terminat cu succes. Dacă apare
vreo eroare pe parcursul execuţiei programului care nu poate fi tratată (memorie insuficientă,
8
imposibilitate de deschide a unui fişier etc.), programul se părăseşte în general cu o instrucţiune
de forma return val_int, unde val_int este o valoare întreagă nenulă. Astfel, semnalăm sistemului
de operare faptul că execuţia programului s-a încheiat cu insucces (cu eroare).
Funcţia main poate să nu aibă nici un parametru, sau poate avea 2 parametri. Dacă funcţia
main are doi parametri, atunci primul este de tip int şi reţine numărul de parametri în linie de
comandă cu care s-a executat programul, iar al doilea este un şir de string-uri, în care sunt
memoraţi parametrii de apel în linie de comandă. În primul string (pe poziţia 0 în vector) se
reţine numele executabilului (al aplicaţiei), după care urmează parametrii de apel în linie de
comandă.
Presupunem că avem programul C test care are următoarea funcţie main:
void main(int narg,char argv *arg[])
{
/* .... */
}
Apelăm programul test în linie de comandă cu doi parametri:
test param1 param2
În această situaţie, în funcţia main a programului test vom avea:
– narg va avea valoarea 3
– arg[0] va fi “test.exe”
– arg[1] va fi “param1”
– arg[2] va fi “param2”.
Asupra modului de definire şi descriere a funcţiilor o să revenim.
Rezumat
Înaintea funcţiei main pot apărea niciuna, una sau mai multe secţiuni de tipul:
- includeri. Pot fi incluse în general fişiere antet (cu extensia .h), dar pot apărea şi fişiere cu
extensia .c sau .cpp. Aceste fişiere conţin în general antete (definiţii) de funcţii, definiţii de
tipuri de date şi constante, macrocomenzi, dar pot apărea şi implementări de funcţii, variabile
globale etc.
- definiţii de macrocomenzi. Macrocomanda reprezintă o generalizare a conceptului de
constantă. O macrocomandă este o expresie constantă. Fiecare apel de macrocomandă este
înlocuit la compilare cu corpul macrocomenzii. O macrocomandă se descrie după #define.
- definiţii de tipuri de date. Unui tip nou de date definit de programator i se poate da un nume
folosind declaraţia care incepe cu cuvântul rezervat typedef.
- declaraţii de variabile.
- definiţii de constante globale. Constantele în C se definesc după cuvântul rezervat const. O
constantă obişnuită poate fi definită şi ca o macrocomandă.
- definiţii sau/şi descrieri de funcţii. Funcţiile programului C se declară deasupra funcţiei
main şi se implementează după funcţia main, sau se descriu în întregime deasupra funcţiei
main.
9
Funcţia main poate avea ca tip returnat tipul void sau tipul int. Funcţia main poate să nu
aibă nici argumente sau poate avea două argumente de apel, argumente care memorează
parametrii de apel în linie de comandă ai aplicaţiei.


Teme:
1. Folosind operatorul ?: (vezi subcapitolul 2.5) scrieţi o macrocomandă pentru maximul dintre
două numere.
2. Scrieţi o macromandă pentru maximul dintre trei valori.
3. Folosind prima macrocomandă scrieţi o macromandă pentru maximul dintre patru valori.
4. Ce trebuie să conţină parametrii narg şi argv pentru o aplicaţie care ar calcula media
aritmetică în linie de comandă a oricâtor valori reale ?

Asocieri de nume unor tipuri de date(Curs 4)

             Asocieri de nume unor tipuri de date
În C putem asocia un nume unui tip de date cu ajutorul cuvântului rezervat typedef astfel:
typedef tip_de_date nume_asociat;
Dăm în continuare două exemple ilustrative:
typedef int intreg;
typedef struct nume_structura nume_structura;
Tipului numeric int i se asociază numele intreg. După această asignare, putem folosi
cuvântul intreg, în loc de int.
În al doilea exemplu tipului de date de tip structură struct nume_structura (care trebuie să
existe anterior definit) i se asociază denumirea nume_structura (fără struct). Acest lucru este des
folosit în C pentru simplificarea scrierii tipului structură. Această asociere nu este necesară în
C++, unde tipul struct nume_structura poate fi folosit şi fără cuvântul struct, fără o definire
prealabilă cu typedef.
Asocierile de nume unor tipuri de date se pot face atât în exteriorul, cât şi în interiorul
funcţiilor.

Constante. Macrocomenzi.(Curs 3)

În C o constantă obişnuită se poate defini folosind cuvântul rezervat const astfel:
const tip_date c=expresie_constanta;
Dacă lipseşte tipul de date de la definirea unor constante, se consideră implicit tipul int.
Iată şi câteva exemple:
const int x=1+4;
const a=1,b=2*2; /* tot constante intregi ! */
const double pi=3.14159
Macrocomanda reprezintă o generalizare a conceptului de constantă, în sensul că putem
defini expresii constante, care se înlocuiesc în codul executabil în momentul compilării.
Definirea unei macrocomenzi începe cu semnul # (diez) urmat de cuvântul define.
Dăm câteva exemple de macrocomenzi:
# define N 100
# define PI 3.14159
# define suma(x,y) x+y
# define alipire(a,b) (a##b)
Primele două macrocomenzi definesc constante obişnuite, N este o constantă de tip
întreg, iar PI este una de tip real.
Ultimele două macrocomenzi de mai sus definesc câte o expresie constantă. Într-un
program care cunoaşte a treia macrocomandă, un apel de forma suma(1.7, a) se va înlocui la
compilare cu 1.7+a. Înlocuirea se face în fiecare loc în care este apelată macrocomanda. De
aceea, macrocomanda poate fi considerată o generalizare a conceptului de constantă, deşi apelul
ei seamănă cu cel al unei funcţii.
Comportamentul macrocomenzilor poate conduce la erori de programare pentru cei care
nu cunosc modul lor de funcţionare. De exemplu, valoarea expresiei suma(1,2)*5 este 11 şi nu
15, deoarece înlocuirea directă a apelului suma(1,2) la compilare cu 1+2 conduce la expresia
1+2*5, care are evident valoarea 11 şi nu la expresia (1+2)*5 cu valoarea 15.
În exemplul de mai sus la ultima macrocomandă s-a folosit operatorul ## care alipeşte
(concatenează) doi tokeni. Astfel, un apel de forma alipire(x,yz) se înlocuieşte cu xyz, care poate
fi o variabilă, numele unei funcţii etc.
Este important de observat că datorită comportamentului diferit de cel al funcţiilor,
macrocomenzile sunt contraindicate pentru a fi folosite prea des într-un program, deoarece
fiecare apel de macrocomandă se înlocuieşte în memorie cu corpul macrocomenzii, ceea ce
7
conduce la mărirea codului executabil. În concluzie, când se lucrează cu macrocomenzi codul C
sau C++ se poate reduce ca lungime, dar codul în formă compilată poate creşte.
Frumuseţea macrocomenzilor constă în faptul că nu lucrează cu tipuri de date prestabilite.
Astfel, în exemplul de mai sus macrocomanda suma va putea fi folosită pentru orice tip de date,
atâta timp cât între x si y se poate aplica operatorul +. Din cauză că la definire nu se specifică
tipul de date al parametrilor, macrocomenzile pot fi văzute ca un rudiment de programare
generică oferit de limbajul C.
În limbajul C++ pot fi scrise funcţii şi clase şablon pentru care unul sau mai multe tipuri
de date sunt nespecificate, identificarea acestor tipuri făcându-se în momentul compilării
programului. Şabloanele reprezintă un suposuport pentru programare generică în adevăratul sens al
cuvântului. Asupra şabloanelor vom reveni.