Sunteți pe pagina 1din 54

UI5.

Programare în limbajul C

Obiectivele unităţii de învăţare – pag 133


Instrucţiuni de control ale programului – pag 133
Test de autoevaluare – pag 157
Tablouri şi şiruri de caractere – pag 168
Test de autoevaluare – pag 177
Răspunsurile testelor de autoevaluare – pag 181
Lucrare de verificare – pag 182
Rezumat – pag 182
Bibliografie – pag 185

Obiectivele unităţii de învăţare

 Familiarizarea cu instrucţiunile de control ale


limbajului de programare C.
 Realizarea conexiunilor corecte între structurile
algoritmice fundamentale discutate în UI4 şi
implementările acestora în limbajul C care sunt
instrucţiunile de control.
 Abilitatea de a integra corect noţiunile teoretice în
practică prin scrierea de programe care rezolvă
diverse probleme elementare.

Durata: 10 ore

Instrucţiuni de control ale programului


În acest capitol se prezintă instrucţiunile de control ale unui
program C: instrucţiunea expresie, instrucţiunile de decizie (sau
de selecţie), instrucţiunile iterative (repetitive sau de ciclare) şi

133
instrucţiunile de salt. În situaţia în care sintaxa limbajului
impune utilizarea unei singure instrucţiuni, dar logica
programului cere folosirea unei secvenţe de instrucţiuni, secvenţa
de instrucţiuni se organizează ca o instrucţiune bloc (sau
instrucţiune compusă). O instrucţiune bloc începe cu { şi se
termină cu }.

Instrucţiuni expresie
Instrucţiunea expresie are forma generală:
expresie;

unde expresie are efect lateral (conţine o atribuire sau


reprezintă un apel de funcţie).
Secvenţa de program următoare conţine exemple de
instrucţiuni expresie:

. . .
x=(a+b)*c;
x+=2;
p++;
getch();

Instrucţiuni de decizie
INSTRUCTIUNEA IF
Forma generală a instrucţiunii if este:

if(expresie)
instructiune_1;
else
instructiune_2;

Efectul instrucţiunii este următorul: dacă expresie este


adevărată (diferită de zero) se execută instructiune_1 în caz
contrar (expresie este egala cu zero) se execută
instructiune_2. Figura 5.1 ilustrează modul de execuţie al
instrucţiunii if.

134
Fals expresie Adevărat

instrucţiune_2 instrucţiune_1

Figura 5.1. Modul de execuţie al instrucţiunii if

Exemplul 5.1
Programul calculează şi afişează radicalul dintr-un număr.
#include "stdio.h"
#include "conio.h"
#include "math.h"

void main(void)
{
float x,y;
printf("\n Introduceti x=");
scanf("%f",&x);
if (x<=0)
printf("\n Calcul imposibil");
else
{
y=sqrt(x);
printf("\n y=%f",y);
}
getch();
}

Observaţii:
 Sintaxa generală a instrucţiunii if cere pe ambele
alternative câte o instrucţiune. În situaţia în care pe o
alternativă sunt necesare mai multe instrucţiuni
acestea vor fi grupate cu ajutorul acoladelor într-o
instrucţiune bloc. Astfel, în exemplul de mai sus,
secvenţa

135
{
y=sqrt(x);
printf("\n y=%f",y);
}

este o instrucţiune bloc.


 Dacă alternativa else a instrucţiunii if este vidă atunci
se poate scrie:

if(expresie)
instructiune_1
else;

sau şi mai simplu

if(expresie)
instructiune;

formă cunoscută sub numele de if cu ramură vidă. Instrucţiunea


instructiune se execută numai dacă expresia este adevărată,
adică se execută condiţionat. Modul de execuţie al instrucţiunii if
cu ramură vidă este ilustrat în Figura 5.2.

Fals Adevărat
expresie

instrucţiune

Figura 5.2. Modul de execuţie al instrucţiunii if cu ramuă vidă

136
Exemplul 5.2
Programul calculează maximul dintre două numere.
#include "stdio.h"
#include "conio.h"
void main(void)
{
float x,y,max;
printf("\n x=");
scanf("%f",&x);
printf("\n y=");
scanf("%f",&y);;
max=x;
if (max<y)
max=y;
printf("\n Maximul dintre x=%.2f si
y=%.2f este=%.2f",x,y,max);
getch();
}

Dacă în structura unei instrucţiuni if intervin alte


instrucţiuni if avem de a face cu o structură de instrucţiuni if
incluse sau imbricate. Forma generală a unei astfel de structuri
este următoarea:

if(expr1)
instr1;
else
if(expr2)
instr2;
else
. . . . . .
if(exprn)
instrn;
else
instrn+1

Efectul execuţiei unei instrucţiuni if imbricate este


următorul: dacă nu există i, i=1,...,n astfel încât expresia
expri să fie adevărată, se execută instrn+1, în caz contrar se
execută prima instrucţiune (considerând evaluarea de sus în jos),
instri pentru care expri este adevărată, iar restul
instrucţiunilor se ignoră.
Pentru n “mare“, folosind o aliniere strictă, se ajunge la o

137
structură cu adâncime mare (mult deplasată spre dreapta). Din
acest motiv se foloseşte de obicei forma:
if(expr1)
instructiune1;
else if(expr2)
instructiune2;
else if(expr3)
instructiune3;
. . . . . .
else
instructiunen+1;

numită şi scara if-else-if.

Exemplul 5.3
Programul citeşte coordonatele unui număr şi stabileşte în
ce cadran se află acesta.
#include "stdio.h"
#include "conio.h"

void main(void)
{
float x,y;
printf("\n abscisa x=");
scanf("%f",&x);
printf("\n ordonata y=");
scanf("%f",&y);
if (x>=0 && y>=0)
printf("\n Numarul apartine cadranului
I");
else if (x<0 && y>=0)
printf("\n Numarul apartine cadranului
II");
else if(x<0 && y<0)
printf("\n Numarul apartine cadranului
III");
else
printf("\n Numarul apartine cadranului
IV");
getch();
}

Ţinând cont că în limbajul C orice expresie diferită de zero


este adevărată, o secvenţă de genul

138
if(expr!=0)
instructiune;

este echivalentă cu
if(expr)
instructiune;

formă care va fi întotdeauna preferată.

✎ Care este diferenţa dintre structurile if şi if-else?


Cuvântul else se asociază întotdeauna cu cel mai apropiat if
incomplet care nu este deja asociat cu un else şi care este în
acelaşi bloc cu el. De exemplu, în secvenţa
if(x)
if(y)
printf(”\n x si y nenuli”);
else
printf(”\n x nul”);

alinierea şi mesajele sugereză asocierea lui else cu primul if. În


realitate, else se asociază cu cel de-al doilea if, fiind adecvată
alinierea
if(x)
if(y)
printf(”\n x si y nenuli”);
else
printf(”\n x nul”);

Dacă totuşi vrem să punem în practică prima intenţie putem


folosi una din formele echivalente:
a) if(x)
{
if(y)
printf(”\n x si y nenuli”);
}
else
printf(”\n x nul”);

b) if(x)
if(y)
printf(”\n x si y nenuli”);
else;
else
printf(”\n x nul”);

139
c) if(x&&y)
printf(”\n x si y nenuli”);
else
if(!x)
printf(”\n x nul”);

În ideea creerii unor programe „dense„ se pot scrie


construcţii de genul

if( (c=getch() ) == ’a’)


putch(’a’);
else
printf(”\n caracter diferit de a”);

unde expresia condiţională conţine o atribuire.


Construcţiile “dense” trebuie facute însă cu grijă, deoarece
este posibil să avem surprize neplăcute. Secvenţa de mai jos
x=y=7;
a=5;b=6;
if((x=a)(y=b))
printf(”\nx=%i si y=%i”,x,y);

va produce x=5, y=7 şi nu x=5, y=6 cum ne-am fi aşteptat.


Pentru ca expresia (x=a)(y=b) să fie adevărată este
suficient ca numai una din expresiile (x=a) sau (y=b) să fie
adevărată. Cu alte cuvinte, se execută atribuirea x=5, expresia
(x=5) ia valoarea adevărat, valoarea expresiei (y=b) nu mai are
importanţă şi deci atribuirea y=6 nu mai are loc.

OPERATORUL CONDIŢIONAL ? :
Operatorul condiţional ?: este un operator ternar, iar forma
sa generală este:
expr1?expr2:expr3;

Efectul execuţiei unei astfel de secvenţe este echivalent cu


efectul execuţiei secvenţei:
if expr1
expr2;
else
expr3;

140
În plus, expresia expr1 ? expr2 : expr3 va lua
valoarea expr2 sau expr3 după cum expr1 este adevărată sau
nu.

Exemplul 5.4
Programul afişează maximul dintre două numere a şi b
citite de la tastatură.
#include "stdio.h"
#include "conio.h"

void main(void)
{
int a,b;
printf("\n a=");
scanf("%i",&a);
printf("\n b=");
scanf("%i",&b);
printf("\n Maximul dintre a=%i si b=%i
este %i",a,b,a<b?b:a);
getch();
}

INSTRUCTIUNEA switch
Instrucţiunea switch permite selecţia unei alternative din
mai multe posibile într-o formă comodă şi elegantă.
Forma generală a instrucţiunii este:
switch(expresie)
{
case c1:secventa de instructiuni1;break;
case c2:secventa de instructiuni2;break;
. . . . . . . .
case cn:secventa de instructiunin;break;
default:secventa de instructiunin+1;break;
}
unde:
 expresie este expresia selectoare care trebuie să fie
de tip întreg;
 c1,c2,...,cn sunt constante de tip întreg distincte
între ele;
 default este o etichetă opţională;
 secvenţa instructiunii, pentru orice

141
i=1,...,n+1 se poate constitui sau nu într-un bloc
de instrucţiuni, poate să fie vidă sau nu;
 break este o instrucţiune care permite saltul la prima
instrucţiune aflată după structura switch. Prezenţa sa
este opţională.
 Efectul instrucţiunii este următorul:
 Dacă există un i astfel încât expresia selectoare este
egală cu ci, se execută secvenţa instructiunik,
k>=i până la primul break întâlnit sau până la
sfârşitul instrucţiunii switch.
 Dacă pentru orice i=1,...,n constantele ci sunt
diferite de expresia selectoare se execută
instructiunen+1, dacă există opţiunea default sau
se iese direct din switch, dacă aceasta lipseşte.

Exemplul 5.5
Programul citeşte una din literele a,A,m,M,p,P de la
tastatură şi afişează o listă de nume care încep cu una din aceste
litere, fără să ţină cont dacă litera este mare sau mică. Dacă se
tastează alt caracter se afişează un mesaj de eroare.
#include "stdio.h"
#include "conio.h"

void main(void)
{
printf("\n Tastati una din literele:
a,A,m,M,p,P ");
switch(getch())
{
case 'a':
case 'A':printf("\n Aurel,Ana,Andrei");
break;
case 'm':
case 'M':printf("\n Maria,Mihai,Marin");
break;
case 'p':
case 'P':printf("\n Paula,Petre,Pavel");
break;
default:printf("\n Ati tastat gresit !");
}
getch();
}

142
Observaţie. În programul de mai sus, indiferent dacă s-a
tastat a sau A se afişează aceeaşi listă de nume: Aurel, Ana,
Andrei. Explicaţia este următoarea. Dacă se tastează a se
“intră“ în switch, prin case 'a'. Secvenţa de prelucrări
corespunzătoare fiind vidă şi neântâlnindu-se nici o instrucţiune
break se trece şi se execută secvenţa de prelucrări
corespunzătoare constantei case 'A' (adică afişarea listei).
Deoarece secvenţa se încheie cu break se “iese“ din switch.
Analog se întâmplă şi cu grupurile de litere m,M şi p,P.

✎ Instrucţiunea switch este implementarea în limbajul C a


cărei structuri algoritmice fundamentale?

Instrucţiuni iterative
Instrucţiunile iterative (repetitive sau de ciclare) permit ca
una sau mai multe instrucţiuni să fie repetate. Numărul de iteraţii
depinde de îndeplinirea unei condiţii. Dacă testul asupra condiţiei
se face înaintea instrucţiunilor care se repetă, se spune că iteraţia
este cu test iniţial; în caz contrar iteraţia este cu test final.
În limbajul C există două instrucţiuni cu test iniţial, while şi
for şi o instrucţiune cu test final, do - while.

INSTRUCTIUNEA while
Forma generală a instrucţiunii while este:
while(conditie)
instructiune;
unde:
 conditie poate fi orice expresie;
 instructiune poate fi o instrucţiune simplă, vidă
sau o instrucţiune compusă (numită şi corpul
ciclului).
Efectul instrucţiunii este următorul: se execută
instructiune cât timp conditie este adevărată (diferită de
zero). Atunci când conditie devine falsă (egală cu zero),
execuţia programului continuă cu instrucţiunea imediat
următoare. Organigrama de mai jos ilustrează sugestiv modul de

143
lucru al instrucţiunii while.

Fals
condiţie

Adevărat
instrucţiune

Figura 5.3. Modul de lucru al instrucţiunii while

Observaţii:
 Dacă din start condiţia este falsă, instructiune nu
se execută niciodată.
 Ieşirea din ciclu se poate face normal (ca efect al
prelucrărilor din instructiune, atunci când după
un număr de paşi conditie devine falsă), anormal
(printr-o instrucţiune de salt care transferă execuţia
programului din interiorul ciclului în afara lui) sau
“niciodată“ (conditie rămâne mereu adevărată, şi
se obţine aşa zisa buclă eternă).
Prezentăm mai jos un exemplu de program unde apare
foarte naturală prezenţa testului iniţial în buclă şi deci folosirea
instrucţiunii while.

Exemplul 5.6
Calculul lungimii unui şir de caractere citit de la tastatură;
sfârşitul şirului este marcat de tasta Enter (caracterul ’\r’).
#include "stdio.h"
#include "conio.h"

void main(void)
{
int i=0;
printf("\n Tastati un sir:\n");
while (getche()!='\r')
i++;
printf("\n Lungimea sirului =%d",i);
getch();
}

144
INSTRUCTIUNEA for
În C, instrucţiunea for prezentă şi în alte limbaje, are
implementarea cea mai flexibilă. Ea depăşeşte cadrul tradiţional
în care este plasată de obicei: instrucţiune cu contor (variabilă
de control) recomandată spre a fi folosită ori de câte ori se
cunoaşte numărul de iteraţii.
Forma generală a instrucţiunii for este:
for(initializare;conditie;actualizare)
instructiune;

Semnificaţia tradiţională a celor trei componente este


următoarea:
 initializare este de regulă o instrucţiune de
atribuire folosită pentru iniţializarea contorului
ciclului;
 conditie este o expresie care determină sfârşitul
ciclului;
 actualizare se referă la felul în care se modifică
variabila contor.
Instrucţiunea for este echivalentă cu secvenţa de instrucţiuni
initializare
while(conditie)
{
instructiune
actualizare
}

De aici rezultă şi efectul execuţiei sale: se execută blocul


instructiune–actualizare cât timp conditia este
îndeplinită.

Exemplul 5.7
Programul realizează suma a n numere reale.
#include "stdio.h"
#include "conio.h"

void main(void)
{
float s=0,x;

145
int i,n;
printf("\n n=");
scanf("%i",&n);
for (i=0;i<n;i++)
{
printf("\n x=");
scanf("%f",&x);
s+=x;
}
printf("\n Suma este =%f",s);
getch();
}

Observaţii:
 Componenta initializare a instrucţiunii for
poate conţine atribuiri care nu se referă neapărat la
variabila contor. În exemplul de mai sus iniţializarea
variabilei s se poate face în componenta
initializare a ciclului for cu ajutorul
operatorului virgulă, astfel:

for(s=0,i=0;i<n;++i)
{
. . . . . .
}
. . . . . .

 Componenta actualizare a instrucţiunii for poate


să conţină mai multe variabile contor.
 Variabila contor nu trebuie să fie prezentă obligatoriu
în componenta conditie a unei instrucţiuni for.

Exemplul 5.8
Afişarea termenilor şirului lui Fibonacci mai mari ca 1 şi
mai mici ca un număr dat m. Şirul are forma 1, 1, 2, 3, 5,
8, …, adică primii doi termeni sunt egali cu 1, iar orice alt
termen se obţine ca sumă a celor doi termeni care-l preced.

#include "stdio.h"
#include "conio.h"

void main(void)
{

146
int a,b,c,m,i;
printf("\n Limita de afisare =");
scanf("%i",&m);
printf("\n Termenii sirului Fibonacci <
%i\n",m);
printf("\n 1 1 ");
for (i=3,a=b=1,c=2;c<m;i++)
{
printf("%i ",c);
a=b;b=c;
c=a+b;
}
getch();
}

Exemple:
 Dacă în programul precedent renunţăm la ideea de a
afişa numărul de ordine al termenilor putem folosi
secvenţa:
for(a=b=1,c=2;c<m;)
{
printf(”\n Termenul =%i”,c)
a=b;b=c;
c=a+b;
}

 Se observă absenţa componentei actualizare.


 Secvenţa de program
int i=50000;
for(;i;i--);

are ca efect introducerea unei temporizări egală cu timpul


necesar decrementării contorului i de la voloare 50000
la 0. Aici se observă absenţa componentei
initializare şi totodată ciclarea unei instrucţiunii
vide.
Oricare din componentele initializare, conditie,
actualizare ale instrucţiunii for poate să lipsească, însă
delimitatorii ; trebuie să fie prezenţi. Lipsa componentei
conditie este interpretată ca fiind echivalentă cu prezenţa unei
expresii condiţionale adevărate. Din acest motiv, secvenţa
for(;;);

147
creează un ciclu infinit sau o buclă eternă.

INSTRUCTIUNEA do-while
Este recomandabil să se folosească instrucţiunea do-while
când instrucţiunea care reprezintă corpul ciclului trebuie
executată cel puţin o dată.
Forma generală a acestei instrucţiuni este:
do
{
instructiuni
}
while(conditie);

Când corpul ciclului este format dintr-o singură


instructiune acoladele pot să lipsească. Totuşi, este
recomandabil să se păstreze chiar şi în această situaţie pentru a
distinge mai uşor o instrucţiune while care începe, de o
instrucţiune do-while care se termină.
Efectul instrucţiunii este următorul: se execută secvenţa de
instructiuni cât timp expresia condiţională conditie este
adevărată. Organigrama de mai jos ilustrează cu claritate modul
de execuţie al ciclului do-while.

instrucţiune

Adevărat
condiţie Fals

Figura 5.4. Modul de execuţie al instrucţiunii do-while

Observaţii:
 Datorită aşezării testului de condiţie după corpul
ciclului, este evident că grupul de instructiuni se
execută cel puţin o dată.
 Dacă în corpul ciclului nu se află instrucţiuni care să

148
conducă la o condiţie falsă după un număr finit de
ciclări (ieşire normală din ciclu) sau instrucţiuni de
salt din interiorul ciclului (ieşire anormală) se obţine
un ciclu infinit (buclă eternă).

Exemplul 5.9
Programul citeşte două numere a şi b de la tastatură şi
afişează suma lor. Procesul continuă cât timp la întrebarea
”Continuati?” se apasă una din tastele care conţin literele d
sau D.
#include "stdio.h"
#include "conio.h"

void main(void
{
float a,b;
char c;
do
{
printf("\n a=");
scanf("%f",&a);
printf("\n b=");
scanf("%f",&b);
printf("\n Suma a+b=%.2f",a+b);
printf("\n Continuati? (d/n) ");
c=getch();
}
while (c == 'D' || c == 'd');
}

Exemplul 5.10
Programul implementează un meniu simplu. Pentru două
numere citite de la tastatură se efectuează una din următorele
operaţii: suma, diferenţa produsul sau împărţirea (atunci când
este posibil) sau se iese din meniu.
#include "stdio.h"
#include "conio.h"

void main(void)
{
float a,b;
char ch;
printf("\n a=");scanf("%f",&a);
printf("\n b=");scanf("%f",&b);

149
printf("\n + Adunare");
printf("\n - Scadere");
printf("\n * Inmultire");
printf("\n / Impartire");
printf("\n r Renunta!");
printf("\n Introduceti optiunea dvs:");
do
{
ch=getchar();
switch(ch)
{
case '+' :printf("\n a+b=%.2f",a+b);
break;
case '-' :printf("\n a-b=%.2f",a-b);
break;
case '*' :printf("\n a*b=%.2f",a*b);
break;
case '/' :if (b)
printf("\n a/b=%.2f",a/b);
else
printf("\n Impartire
imposibila!"); break;
case 'r' :
case 'R' :exit(0);
}
}
while (ch!='+' && ch!='-' && ch!='*' && ch!='/');
getch();
}

Observaţie. Funcţia exit() provoacă întreruperea


programului şi revenirea în sistemul de operare. Funcţia are
forma generală:
void exit(int cod_retur);

De obicei, cod_retur are valoarea 0 la ieşire normală din


program şi o valoare diferită de 0 în caz contrar.

Exemplul 5.11
Programul calculează şi afişează radicalul dintr-un număr.
Noutatea faţă de Exemplul 5.1 este apariţia unei bucle iterative
de validare: ieşirea din buclă urmată de calculul radicalului se
face doar atunci când numărul citit de la tastatură este pozitiv.

150
#include "stdio.h"
#include "conio.h"
#include "math.h"

void main(void)
{
float x;
do
{
printf("\n x=");
scanf("\n %f",&x);
}
while (x<0);
printf("\n Radical din x=%.2f este
y=%.4f",x,sqrt(x));
getch();
}

✎ Scrieţi un program C care calculează suma primelor n


numere naturale folosind pe rând structurile for, while şi do-
while.

Cicluri imbricate (incluse)


Există posibilitatea ca o instrucţiune de ciclare să includă o
altă instrucţiune de ciclare; în acest caz se spune că ciclurile sunt
imbricate sau incluse.

Exemplul 5.12
Programul ilustrează folosirea ciclurilor imbricate:
#include "stdio.h"
#include "conio.h"

void main(void)
{
int i,j;
for (i=1;i<=5;i++)
{
for (j=1;j<=i;j++)
printf("%2d",j);
printf("\n");
};
getch();
}

151
Rezultatul execuţiei programului de mai sus este:
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5

Pentru o valoare a variabilei contor i, variabila contor j a


ciclului interior variază de i ori; se spune că indicele interior
variază mai repede ca indicele exterior.
Evident, o structură de cicluri incluse poate să conţină
oricare din instrucţiunile de ciclare permise în C. Iată un exemplu
de acest gen:

Exemplul 5.13
Programul rezolvă următoarea problemă: cât timp se
citeşte de la tastatură o valoare x diferită de zero se afişează
şirul de numere x, x+1, x+2, x+3, x+4. Acest proces
continuă sau se întrerupe la cerere.
#include "stdio.h"
#include "conio.h"
void main(void)
{
int x,i;
char ch;
do
{
printf("\n x=");
scanf("%i",&x);
while (x)
{
for (i=0;i<5;i++)
printf("%5d",x+i);
printf("\n x=");
scanf("%i",&x);
}
printf("\n Continuati ? (d/n)");
ch=getch();
}
while (ch == 'd' || ch == 'D');
}

152
Instrucţiuni de salt
În limbajul C există patru instrucţiuni care execută un salt
necondiţionat în program: break, continue, goto, return.
Instrucţiunea return se referă la revenirea din funcţia apelată la
punctul unde s-a făcut apelul.

INSTRUCTIUNEA break
După cum s-a văzut la prezentarea instrucţiunii switch,
instrucţiunea break poate încheia execuţia unei prelucrări case şi
forţa trecerea execuţiei la prima instrucţiune aflată după switch.
O altă situaţie unde instrucţiunea break îşi dovedeşte utilitatea
este atunci când se doreşte încheierea forţată a unui ciclu. În acest
caz întâlnirea instrucţiunii break în corpul ciclului determină
întreruperea ciclării şi trecerea controlului la prima instrucţiune
care urmează după ciclu.

Exemplul 5.14
Programul “extrage“ şi afişează cel mult 20 de numere
aleatoare folosind funcţia rand(). Dacă s-a “extras“ numărul 10
programul nu mai efectuează restul “extragerilor“.
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"

void main(void)
{
int i,x;
for (i=0;i<20;i++)
{
x=rand()%20+1;
printf("\n %i. S-a extras numarul
%i",i+1,x);
if (x==10) break;
}
getch();
}

Precizări. O instrucţiune break are efect numai asupra


ciclului cel mai interior în care se află. Aceeaşi precizare e
valabilă şi la instrucţiuni switch imbricate sau incluse în cicluri:
instrucţiunea break va afecta numai prima instrucţiune switch in

153
care se află, nu şi eventualele instrucţiuni switch sau de ciclare în
care ar putea fi inclusă prima.

Exemplul 5.15
Programul tipăreşte de 10 ori câte 7 numere extrase
aleator.
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"

void main(void)
{
int i,j;
for (i=0;i<10;i++)
{
printf("\n");
for (j=0;j<10;j++)
{
printf("%5d",rand()%10+1);
if (j>=7) break;
}
}
getch();
}

INSTRUCŢIUNEA continue
Instrucţiunea continue se foloseşte numai în corpul unui
ciclu; ea forţează execuţia următoarei iteraţii a ciclului,
omiţându-se instrucţiunile prezente între cele două iteraţii (locul
unde se află plasată în corpul ciclului şi sfârşitul acestuia).
Efectul instrucţiunii este următorul:
 Când continue este întâlnită într-un ciclu for se
continuă cu execuţia componentei de actualizare şi
apoi a testului condiţional.
 Când este întâlnită într-un while sau do-while, se
trece la execuţia expresiei condiţionale.

Exemplul 5.16
Programul citeşte de la tastatură 10 numere întregi
însumându-le doar pe cele strict pozitive.

154
#include "stdio.h"
#include "conio.h"

void main(void)
{
int i,x,s;
for (i=s=0;i<10;i++)
{
printf("\n x=");
scanf("%i",&x);
if (x<=0) continue;
s+=x;
}
printf("\n Suma este=%d",s);
getch();
}

INSTRUCTIUNEA goto
Forma generală a instrucţiunii goto este:
goto eticheta;
.
.
.
eticheta:instructiune;

unde eticheta este numele de identificare al instrucţiunii


instructiune.
Efectul execuţiei instrucţiunii goto este saltul necondiţionat
la instrucţiunea identificată prin eticheta. Saltul poate fi făcut
înainte sau după instrucţiunea goto. Folosirea frecventă a acestei
instrucţiuni în programe afectează claritatea acestora, îngreunând
înţelegerea lor. Ea poate fi însă evitată în orice situaţie utilizând
celelalte structuri de control din C. Dăm mai jos un exemplu tipic
de folosire a instrucţiunii goto: ieşirea forţată dintr-un ciclu sau
dintr-o instrucţiune switch.

Exemplul 5.17
Programul reprezintă altă implementare a Exemplului 5.10.
#include "stdio.h"
#include "conio.h"

155
void main(void)
{
float a,b;
char ch;
for(;;)
{
clrscr();
printf("\n a=");
scanf("%f",&a);
printf("\n b=");
scanf("%f",&b);
printf("\n + Adunare");
printf("\n - Scadere");
printf("\n * Inmultire");
printf("\n / Impartire");
printf("\n r Renunta");
printf("\n Introduceti optiunea
dvs:");
ch=getche();
switch (ch)
{
case '+' :printf("\n a+b=%.2f",a+b);
break;
case '-' :printf("\n a-b=%.2f",a-b);
break;
case '*' :printf("\n a*b=%.2f",a*b);
break;
case '/' :if (b)
printf("\n a/b=%.2f", a/b);
else
printf("\n Impartire
imposibila"); break;
case 'r' :
case 'R' :goto STOP;
}
getch();
}
STOP:printf("\n Am renuntat!");
getch();
}

156
� Test de autoevaluare
5.1. Secvenţa de program
int x=-3,y=7;
if (x>0)
printf(”\n x=%i”,x);
else
if (y)
printf(”\n y=%i”,y);
else
printf(”\n y=0”);

a. afişează y=7
b. este greşită deoarece o instrucţiune if conţine o altă
instrucţiune if
c. afişează x=-3
5.2. Secvenţa de program

if(x)
if(y)
y=3;
else
y=5;

este echivalentă cu

a. if(x)
if(y)
y=3;
else;
else
y=5;

b. if(x&&y)
y=3;
else
y=5;

c. if(x)
{
if(y)
y=3;

157
}
else
y=5;

d. nici una din secvenţele a, b, c

5.3. Secvenţa de program


int x=1,y=2;
if ((x=0)&&(y=4))
printf(”\n x=%i y=%i”,x,y);

a. afişează x=1 y=2


b. afişează x=0 y=4
c. nu afişează nimic deoarece printf() nu se execută
5.4. Secvenţa de program
if(x)
y=1/x;

a. este greşită
b. este echivalentă cu
if (x!=0)
y=1/x;

c. este chivalentă cu
if x!=0
y=1/x;

5.5. Secvenţa de program


if (x>=3)
y=sqrt(x-3);
else;

a. este greşită deoarece conţine semnul ; înainte de else


b. este greşită deoarece după else lipseşte o instrucţiune
c. este corectă şi este echivalentă cu secvenţa
if(x>=3)
y=sqrt(x-3);

158
5.6. Secvenţa de program

int x=3,y=6;
if (x>0)
printf(”\n x=%i”,x);
else
y=x+3;
printf(”\n y=%i”,y);

afişează
a. x=3
b. y=6
c. x=3
y=6
5.7. Secvenţa de program

int x=3,y=4;
printf(”\n %i”,x>y?x:y);

a. afişează 3
b. afişează 4
c. este greşită deoarece argumentul funcţiei printf()
este o expresie, nu o variabilă.
5.8. Secvenţa de program
char x=’a’;
switch(x)
{
case ’a’:printf(”\n amic”);
case ’A’:printf(”\n Amare”);
}

a. afişează amic
b. afişează Amare
c. afişează
amic
Amare
5.9. Secvenţa de program
int x=3;
if (x=4)

159
printf(”\n x=%i”,x);

a. este greşită
b. este corectă, dar nu afişează nimic
c. este corectă şi afişează valoarea 4
d. este corectă şi afişează valoarea 3
5.10. Secvenţa de program
char x=’a’;
switch(x)
{
case ’a’:printf(”\n amic”);break;
case ’A’:printf(”\n Amare”);
}

a. afişează amic
b. afişează Amare
c. afişează
amic
Amare
d. este greşită deoarece al doilea case nu se termină cu
break
5.11. Secvenţa de program
int i=3;
while(i)
i--;
printf(”%3i”,i);

a. afişează 2 1 0
b. conţine o buclă eternă
c. afişează 0
5.12. Secvenţa de program
int i=3;
while(i)
printf(”%3i”,i);
i--;

a. afişează valoarea 3 de 3 ori


b. afişează valoarea 3 de o infinitate de ori (buclă

160
eternă)
c. afişează 3 2 1
5.13. Secvenţa de program
int i=3;
while(i);
printf(”%3i”,i);
i--;

a. afişează valoarea 3 de 3 ori


b. afişează valoarea 3 de o infinitate de ori (buclă
eternă)
c. conţine o buclă eternă şi nu afişează nimic
d. afişează 3 2 1
5.14. Secvenţa de program
int i=3;
while(i)
{
printf(”%3i”,i);
i--;
}

a. afişează 3 2 1 0
b. afişează 3 2 1
c. conţine o buclă eternă
5.15. Secvenţa de program
int i=0;
while(i)
printf(”%3i”,i);

a. afişează valoarea 0
b. afişează valoarea 0 de o infinitate de ori (buclă
eternă)
c. nu afişează nimic
5.16. Secvenţa de program
int i=0;
for (;i<3;i++);
printf(”%3i”,i);

161
a. este greşită sintactic deoarece lipseşte componenta
de iniţializare a instrucţiunii for
b. afişează valorile 0 1 2 3
c. afişează valorile 0 1 2
d. afişeaza valoarea 3
e. conţine o buclă eternă afişându-se permanent
valoarea 0
f. conţine o buclă eternă şi nu afişează nimic
5.17. Secvenţa de program
int i,j;
for (i=1,j=10;i<=5;i++,j--)
printf(”\n %i %2i”,i,j);

a. este greşită deoarece instrucţiunea for conţine două


variabile contor i,j
b. este greşită deoarece componenta iniţializare a
instrucţiunii for conţine două iniţializări
c. este corectă şi afişează
1 10
2 9
3 8
4 7
5 6
5.18. Secvenţa de program
int i;
for (i=1;-3<=i&&i<1;i--)
printf(”\n%3i”,i);

a. nu afişează nimic
b. afişează 0 -1 -2 -3
c. conţine o buclă eternă
5.19. În secvenţa de program
int x=1,i;
for(i=1;x<=3;i++)
scanf(”%i”,&x);

162
a. funcţia scanf() se execută de 3 ori
b. funcţia scanf() se execută de o infinitate de ori
c. instrucţiunea for este greşită deoarece contorul i nu
se testează niciodată
d. se iese din buclă numai după ce s-a citit o valoare
x>3
5.20. Secvenţa de program
int i;
for(i=1,i<=3;i++)
printf(”%3i”,i)

a. este greşită
b. conţine o buclă eternă
c. afişează 1 2 3
5.21. Secvenţa de program
int i;
for (i=1,i<=3;i++)
printf(”%3i”,i)

a. conţine o instrucţiune for greşită sintactic


b. afişează 1 2 3
c. conţine o buclă for eternă
5.22. Secvenţa de program
for();

a. este o buclă for eternă


b. este greşită sintactic
c. apelează funcţia for()
5.23. Secvenţa de program
float x=-3.2;
do
scanf(”%f”,&x);
while (x>0);

a. citeşte x până când x>0


b. citeşte x cât timp x>0

163
c. este greşită deoarece funcţia scanf() nu este pusă
între acolade
d. nu execută nici o citire a lui x
5.24. Secvenţa de program

int j;
do
j=3;
while (j<=4);
{
printf(”%3i”,j);
j++;
}
a. afişează valoarea 3
b. afişează valorile 3 4
c. conţine o buclă do-while eternă
d. conţine o buclă while eternă
e. este greşită
5.25. Secvenţa de program
int i=1;
do
printf(”\n%i”,i);
i++;
while(i<=2);

a. afişează 1 2
b. este greşită deoarece instrucţiunile dintre do şi while
trebuie să fie cuprinse între acolade
5.26. Secvenţa de program
int i,j;
for(i=1;i<=2;i++)
for(j=1;j<=2;j++)
printf(”\n i=%i j=%i”,i,j);

a. afişează i=1 j=1


i=2 j=2
b. afişează i=1 j=1
i=1 j=2
i=2 j=1

164
i=2 j=2
c. afişează i=1 j=1
i=2 j=1
i=1 j=2
i=2 j=2
5.27. Secvenţa de program
int i,j;
for(i=1;i<=3;i++)
{
printf(”\n”);
for(j=1;j<=i;j++)
printf(”%3i”,j);
}
a. este greşită deoarece limitele de variaţie ale
contorului j depind de contorul i al primului ciclu
b. este corectă şi afişează
1
1 2
1 2 3
c. este corectă şi afişează
1 2 3
1 2
1
5.28. Secvenţa de program
int i;
for(i=1;i<=5;i++)
{
printf(”%3i”,i);
if(i==3)break;
}

a. este greşită deoarece instrucţiunea break se foloseşte


numai asociată cu switch
b. este corectă şi afişează 1 2 3
c. este corectă şi afişează 1 2 3 4 5
deoarece instrucţiunea break cuprinsă în corpul unui ciclu
for nu are nici un efect
5.29. Secvenţa de program
int i,j;
for(i=1;i-3;i++)
for(j=0;j-9;j++)

165
{
printf(”\n Sunt aici!”);
if (!j)break;
}
a. afişează mesajul Sunt aici! de 2 ori
b. afişează mesajul Sunt aici! de 30 ori
c. afişează mesajul Sunt aici! o dată
5.30. Secvenţa de program
int s,i;
for(s=0,i=10;i;i--)
{
s+=i;
if(i-5)continue;
}

a. calculează suma s=10+9+8+7+6+4+3+2+1


b. calculează suma s=10+9+8+7+6+5+4+3+2+1
c. calculează suma s=5
5.31. Secvenţa de program
int s,i;
for(s=0;i=10;i;i--)
{
if(i-5)continue;
s+=i;
}

a. calculează suma s=10+9+8+7+6+4+3+2+1


b. calculează suma s=10+9+8+7+6+5+4+3+2+1
c. calculează suma s=5
5.32. Secvenţa de program
int s,i;
for(s=0;i=10;i;i--)
{
if(i==5)continue;
s+=i;
}

a. calculează suma s=10+9+8+7+6+4+3+2+1


b. calculează suma s=10+9+8+7+6+5+4+3+2+1

166
c. calculează suma s=5
5.33. Secvenţa de program
int i=1;
while(i<3)
{
if!(i==2)continue;
printf(”%3i”,i);
i++;
}

a. afişează 1 şi intră într-o buclă eternă


b. afişează 1 2 3
c. afişează 1 3
5.34. Secvenţa de program
int i=1,s=0;
et1:if(i>10)
goto et2;
s+=i;
i++;
goto et1;
et2:printf(”\n s=%d”,s);

a. este greşită deoarece conţine salturi înapoi


b. este corectă şi realizează o iteraţie pentru calculul
primelor 10 numere naturale
c. este corectă şi este echivalentă cu secvenţa
int s,i;
for(s=0,i=1;i<11;i++)
s+=i;
printf(”\n s=%d”,s);

d. este corectă şi este echivalentă cu secvenţa


int i=1,s=0;
while(i<11)
{
s+=i;
i++;
}
printf(”\n s=%d”,s);

167
Tablouri şi şiruri de caractere
Notaţia indicială a variabilelor nu este nouă; ea a fost şi este
folosită în special de matematicieni ori de câte ori este nevoie ca
o prelucrare să fie exprimată cît mai sintetic. Este evident că
prelucrarea S=a+b+c+d+e+f arată mult mai puţin elegant decât
6
S   xi În ultimul caz cele şase variabile a,b,c,d,e,f au
i 1
fost redenumite x1,x2,...,x6; ele pot fi privite astfel drept
primele 6 componente ale vectorului x.
Tablourile reprezintă tocmai implementarea noţiunilor de
vector, matrice sau masiv multidimensional într-un limbaj de
nivel înalt. Ele reprezintă colecţii omogene de date (adică de
acelaşi tip), stocate în locaţii de memorie învecinate. Accesul la
oricare din elementele tabloului se face cu ajutorul indicilor.

Tablouri unidimensionale
Declaraţia unui tablou unidimensional se face după forma
generală:
tip nume_tablou[dim];
unde:
 tip reprezintă tipul de bază al elementelor indexate;
 dim reprezintă numărul de elemente ale tabloului;
 nume_tablou este un identificator reprezentând
numele tabloului.
Dimensiunea zonei continue alocate se calculează prin
relaţia
dimens_alloc=dim*sizeof(tip).

De exemplu, prin declaraţia


int a[100];
se vor aloca vectorului a, 100*2=200 de octeţi într-o zonă
continuă de memorie.

168
Observaţii:
 alocarea se face în timpul compilării;
 o dată făcută alocarea, în scopul măririi vitezei de
execuţie nu se mai face nici o verificare a
dimensiunii; gestionarea corectă a zonei de memorie
alocate cade, deci, exclusiv în sarcina
programatorului.
Referirea la un element al tabloului unidimensional se face
precizând numele tabloului urmat de o expresie întreagă între
paranteze drepte, adică
nume_tablou[expr]

Expresia expr poate lua valori întregi cuprinse în


intervalul[0,dim-1]. Astfel, în urma declaraţiei float
y[10]; vectorului y va avea 10 componente reale şi anume:
y[0] componenta_1
y[1] componenta_2
. . . . . . . .
y[9] componenta_10
Intenţia de a referi ultimul element al unui tablou sub forma
nume_tablou[dim] este o greşeală cu atât mai gravă, cu cât,
ţinând cont de observaţiile anterioare, ea nu este depistată de
compilator. De obicei expresiile întregi folosite pentru a accesa
componentele unui tablou sunt constante sau variabile simple
(indici).

Exemplul 5.18
Comutarea componentelor unui vector şi afişarea lor în
coloană.
#include "stdio.h"
#include "conio.h"

void main(void)
{
int x[50],i,n,c;

/* citirea elementelor vectorului */


printf("\n lungimea sirului n<50 este:");

169
scanf("%d",&n);
for (i=0;i<n;i++)
{
printf("\n x[%i]=",i);
scanf("%i",&x[i]);
}

/* comutarea elementelor */
for (i=0;i<n/2;i++)
{
c=x[i];
x[i]=x[n-1-i];
x[n-1-i]=c;
}

/* afisarea elementelor vectorului comutat */


for (i=0;i<n;i++)
printf("\n componenta x[%i] este
%i",i,x[i]);
getch();
}

Tablouri multidimensionale
Dacă elementele unui tablou unidimensional sunt la rîndul
lor tablouri unidimensionale obţinem un tablou bidimensional
sau o matrice. De exemplu, declaraţia:
int x[4][3];

se poate interpreta astfel: x este un tablou cu 4 elemente x[i],


i=0,1,2,3. Fiecare element x[i] cu i=0,1,2,3 este un
tablou cu 3 elemente întregi x[i][j] cu j=0,1,2.
Generalizând, un tablou multidimensional poate fi
considerat ca un tablou unidimensional care are ca elemente un
tablou cu restul de dimensiuni; declaraţia unui tablou cu
dimensiunile dim1,dim2,...,dimn are forma generală:
tip nume_tablou[dim1][dim2]...[dimn];
iar referirea la un element al tabloului se face prin:
nume_tablou[indice1][indice2]...[indicen],
unde indicei ia valori întregi în intervalul [0,dimi-1], pentru
i=1,2,...,n.

170
Observaţii:
 Referirea clasică la elementele unui tablou prin
separarea indicilor prin virgulă este incorectă în C şi
are semnificaţia rezultată din folosirea operatorului de
secvenţiere. De exemplu, considerând declaraţia de
mai sus, referirea x[i,j] este echivalentă cu x[j].
 Dimensiunea zonei continue de memorie alocate este
dată (în octeţi) de valoarea dim1*dim2*dim3*dimn*
*sizeof(tip).

Exemplul 5.19
Calculul şi afişarea sumei a două matrici a şi b de
dimensiune 4x3 citite de la tastatură.
#include "stdio.h"
#include "conio.h"

void main(void)
{
int a[10][10],b[10][10],c[10][10];
short i,j,m,n;

/*citirea dimensiunilor mtricilor a,b si c */


do
{
printf("\n m=");
scanf("%i",&m);
printf("\n n=");
scanf("%i",&n);
}
while (m<1 || m>10 || n<1 || n>10);

/* citirea elementelor matricilor a si b */


for (i=0;i<m;i++)
for (j=0;j<n;j++)
{
printf("\n a[%i][%i]=",i,j);
scanf("%i",&a[i][j]);
printf("\n b[%i][%i]=",i,j);
scanf("%i",&b[i][j]);
}

/* calculul matricii suma c=a+b */


for (i=0;i<m;i++)
for (j=0;j<n;j++)

171
c[i][j]=a[i][j]+b[i][j];

/* afisarea matricii suma c */


printf("\n matricea suma este:\n");
for (i=0;i<m;i++)
{
for (j=0;j<n;j++)
printf("%4i",c[i][j]);
printf("\n");
}
getch();
}

Iniţializarea tablourilor
Exemplele anterioare ne-au arătat cum se poate iniţializa un
tablou prin valori date de la tastatură. Există însă posibilitatea
iniţializării unui tablou printr-o definiţie de forma:
declaratie tablou={lista valori_initiale};

unde valori_initiale sunt expresii constante compatibile cu


tipul de bază al tabloului.
Exemple:
int vector[6]={-7,-2,95,21,5,-23};
float a[3][2]={1,2,3,4,5,6};
int b[3][2][2]={1,2,3,4,5,6,7,8,9,10,11,12};

În cel de-al doilea caz a fost iniţializată o matrice. Cum se


vor completa elementele matricii? Răspunsul este simplu: ”pe
linii”, adică se completează linia 0, apoi linia 1 şi în sfârşit linia
2. Matricea a va arăta astfel:
1 2
3 4
5 6
Pentru a sugera modul de iniţializare al tablourilor
multidimensionale se pot folosi acolade despărţitoare în interiorul
listei de valori. Astfel, matricea a se poate scrie mai sugestiv
int b[3][2]= {
{1, 2},
{3, 4},
{5, 6},
};

172
În general, iniţializarea elementelor unui tablou
multidimensional se face după regula “ultimul indice variază cel
mai rapid“, care este o generalizare a regulii de memorare “pe
linii“. Astfel, cele douăsprezece componente ale tabloului
b[3][2][2] vor fi iniţializate astfel:
b[0][0][0]=1
b[0][0][1]=2
b[0][1][0]=3
b[0][1][1]=4
b[1][0][0]=5
b[1][0][1]=6
b[1][1][0]=7
b[1][1][1]=8
b[2][0][0]=9
b[2][0][1]=10
b[2][1][0]=11
b[2][1][1]=12

Aceste reguli decurg din modul de liniarizare a unui tablou


în C: poziţiei i1*i2*...*in din tablou îi corespunde în forma
sa liniarizată (formă sub care i se va aloca memoria) poziţia k
dată de formula:
k=i1*dim2*...*dimn+i2*dim3*dimn+...+in-1*dimn+in.

De exemplu, în cazul unei matrici a[m][n] liniarizarea se


face după formula k=i*n+j.
Să notăm în cazul general cu dim produsul
dim1*dim2*...*dimn şi cu nval_in numărul constantelor din
lista de iniţializare.
 Dacă dim=nval_in iniţializarea tabloului decurge
normal după regula de mai sus.
 Dacă dim<nval_in se va produce o eroare, iar dacă
dim>nval_in restul de elemente sunt iniţializate cu
zero.
Se observă că formula de alocare nu depinde de prima
dimensiune a tabloului, fapt ce permite următoarele iniţializări
echivalente cu cele prezentate la începutul secţiunii:
int vector[]={-7,-2,95,21,5,-23};
float a[][2]={1,2,3,4,5,6};
int b[][2][2]={1,2,3,4,5,6,7,8,9,10,11,12};

173
Tablouri şi şiruri de caractere
În C nu există un tip special pentru definirea unui şir de
caractere. Şirurile de caractere se construiesc cu ajutorul
tablourilor unidimensionale.
Declaraţia unui şir cu numele, nume_sir de lungime
maxim dim-1 caractere se face sub forma:
char nume_sir[dim];

Sfârşitul unui şir este marcat de caracterul ’\0’; din acest


motiv, în declaratia şirului, dimensiunea tabloului trebuie să fie
cel puţin cu o unitate mai mare decât numărul de caractere al
şirului pe care vrem să-l memorăm.
De exemplu:
char sr[10];

conţine declaraţia şirului sr. Iniţializarea se poate face printr-o


definiţie a şirului sub forma:
char sr[10]=”aAbBcCdD”;

✎ Care este caracterul sr[3] din exemplu de mai sus?


Dacă numărul elementelor din şir este mai mare decât
dimensiunea şirului, caracterele în plus sunt ignorate, în caz
contrar restul elementelor este iniţializat cu zero (caracterul nul).
Dacă nu se precizează dimensiunea, se poate face
următoarea iniţializare:
char sr[]=”aAbBcCdD”;

care este echivalentă cu iniţializarea tabloului sr cu un şir de


caractere, adică
char sr[]={’a’,’A’,’b’,’B’,’c’,’C’,’d’,’D’,\0’};

Se observă prezenţa explicită a terminatorului de şir ’\0’.


Ultimele două variante rezervă şirului un număr de locaţii
egal cu numărul elementelor din şir plus o unitate
(corespunzătoare terminatorului ’\0’) şi este mai comodă,
deoarece nu precizează o limită maximă pentru numărul de
caractere, permiţând programatorului să evite numărarea

174
elementelor din şir.
Legătura dintre şiruri şi tablouri unidimensionale permite
referirea indexată la caracterele şirului. Folosind acest lucru, în
exemplul de mai jos se selectează şi afişează literele mici din
şirul sir.

Exemplul 2.10
Selectarea şi afişarea literelor mici dintr-un şir.
#include "stdio.h"
#include "conio.h"

void main(void)
{
int i;
char sir[]="aAbBcCdD";
printf("\n Sirul este: %s",sir);
printf("\n Literele mici din sir sunt: ");
for (i=0;sir[i];i+=2)
printf("%c",sir[i]);
getch();
}

Funcţii pentru prelucrarea şirurilor de caractere


Funcţii cu prototipul in “stdio.h”
Pentru operaţiile de intrare/ieşire cu şiruri se pot folosi
funcţiile scanf() respectiv printf() cu descriptorul de format %s.

Exemplul 5.21
Citirea a două şiruri sub forma nume prenume şi afişarea
lor sub forma prenume nume.
#include "stdio.h"
#include "conio.h"
void main(void)
{
char nume[25],prenume[25];
printf("\n Numele=");
scanf("%s",nume);
printf("\n Prenumele=");
scanf("%s",prenume);
printf("\n %s %s",prenume,nume);
getch();
}

175
Pentru citirea unui şir de la tastatură se poate folosi funcţia
gets() cu forma generală:
gets(sir_destinatie);

iar pentru afişarea unui şir pe ecran funcţia puts() cu forma


generală:
puts(sir).

Observaţie. Funcţia gets() transferă în sir_destinatie


toate caracterele până la apăsarea tastei Enter.

Funcţii cu prototipul în “string.h”


Fişierul ”string.h” conţine prototipurile funcţiilor
specializate pentru manipularea şirurilor de caractere. Iată câteva
dintre acestea:
 Funcţia strcpy() cu forma generală:
strcpy(sir_destinatie, sir_sursa);

copiază sir_sursa în sir_destinatie;


 Funcţia strcmp() cu forma generală:
int strcmp(sir1, sir2);

compară cele doua şiruri caracter cu caracter şi întoarce o


valoare:
<0 dacă sir1<sir2;
=0 dacă sir1=sir2;
>0 dacă sir1>sir2.
Comparaţia şirurilor se face lexicografic.
 Funcţia strlen() cu forma generală:
unsigned int strlen(sir);

întoarce numărul de elemente dintr-un şir;


 Funcţia strcat() cu forma generală:
char *strcat(sir1, sir2);

176
adaugă sir2 la sfârşitul şirului sir1 (concatenare).

Exemplul 5.22
Se citeşte de la tastatură un număr neprecizat de şiruri de
caractere. Citirea se termină când se întâlneşte şirul ”stop”.
Programul stabileste şirul “minim” (în sens lexicografic) şi îl
afişează împreună cu lungimea sa.
#include "stdio.h"
#include "conio.h"
#include "string.h"

void main(void)
{
char min[20],x[20];
printf("\n Introduceti siruri de caractere ! ");
printf("\n La sfarsit tastati STOP \n");

strcpy(min,gets(x));
while (strcmp(x,"stop"))
{
strcmp(min,x)<0 ? min : strcpy(min,x);
gets(x);
}
printf("\n Sirul minim este "); puts(min);
printf("\n si are lungimea %i",strlen(min));
getch();
}

� Test de autoevaluare

5.35. Declaraţia
float x[100];
înseamnă
a. rezervarea în memorie a 100 de locaţii la adrese
consecutive
b. rezervarea în memorie a 100de locaţii la adrese
întâmplătoare
c. rezervarea a 100 de octeţi pentru variabila reală x

177
5.36. Secvenţa de program
int x[m][n],m=3,n=2;

a. este corectă deoarece dimensiunile m şi n ale matricii


sunt cunoscute
b. este greşită deoarece m şi n trebuia să fie declaraţi
înainte de x
c. este greşită deoarece la declarare în main(),
dimensiunile unui tablou trebuie să fie constante şi nu
variabile
5.37. Secvenţa de program
int y[10];
y[10]=7;

a. atribuie componentei y[10] a tabloului y valoarea 7


b. este greşită deoarece componentele tabloului sunt y
[0],y[1],y[2],...,y[9]
c. este corectă deoarece componentele tabloului sunt
y[1],y[2],...,y[10]
5.38. În secvenţa de program
int x[3][2];
x[1,2]=5;

a. atribuirea x[1,2]=5 este echivalentă cu


x[1][2]=5
b. atribuirea x[1,2]=5 este corectă sintactic şi
înseamnă x[2]
5.39. Următoarele trei declaraţii ale tabloului x,
int x[6];
int x[3][2];
int x[2][3];

a. sunt echivalente
b. nu sunt echivalente
5.40. În urma iniţializării tabloului a
int a[3][2]={1,2,3,4,5,6};

178
componenta a[1][0] are valoarea
a. 2
b. 3
c. altă valoare decât decât 2 sau 3
5.41. Iniţializarea
int a[3][2]={1,2,3,4,5,6};
este echivalentă cu:
a. int a[3][2]={
{1,2},
{3,4},
{5,6},
};
b. int a[3][2]={
{1,4},
{2,5},
{3,6},
};

5.42. Iniţializarea
float x[2][3]={1,2,3,4,5,6};
este echivalentă cu
a. float x[][]={1,2,3,4,5,6};
b. float x[][3]={1,2,3,4,5,6};
c. float x[2][]={1,2,3,4,5,6};
5.43. Secvenţa de program
int x[10],i;
for(i=1;i<=10;i++)
scanf(”%d”,&x[i]);

a. este greşită sintactic


b. nu iniţializează toate componentele vectorului x
c. produce eroare la execuţie
5.44. Secvenţa de program
char x[]=”abc”;
este echivalentă cu:
a. iniţializarea char x[]={’a’,’b’,’c’};

179
b. iniţializarea char x[4]={’a’,’b’,’c’};
c. iniţializarea char x[]={’a’,’b’,’c’,’\0’};
5.45. Secvenţa de program
char x[]=”abcd”;
putch(x[1]);

a. afişează caracterul ’a’


b. afişează caracterul ’b’
c. este greşită deoarece elementele dintr-un şir nu se
pot referi indexat
5.46. Secvenţa de program
char x[20]=”abcd”;
printf(”\n Lungimea sirului=%i”,strlen(x));
afişează mesajul
a. Lungimea sirului=20
b. Lungimea sirului=4
c. Lungimea sirului=5
5.47. Secvenţa de program
char x[]= ”rac”;
char y[]= ”arc”;
printf(”%d”,strcmp(x,y));
afişează o valoare
a. egală cu zero
b. mai mică strict decât zero
c. mai mare strict decât zero
5.48. Secvenţa de program
char x[]=”ac”;
char y[]=”ar”;
strcat(x,y);
printf(”\n %s”,x);
afişează
a. acar
b. arac
5.49. În secvenţa de program
char x[20];

180
x=”Ploiesti”;
atribuirea
x=”Ploiesti”;

a. este greşită
b. este greşită, iar copierea şirului ”Ploiesti” în
variabila x se realizează prin strcpy(x,”Ploiesti”);
c. este corectă
5.50. Secvenţa de program
char x[20];
gets(x);
puts(x);
afişează acelaşi şir dacă înlocuim gets(x); cu:
a. gets(&x);
b. scanf(”%s”,&x);
c. scanf(”%s”,x);
5.51.În secvenţa de program
int i;
char x[20]=”xyzw”;
puts(x);
apelul
puts(x);

poate fi înlocuit cu:


a. printf(”\n %s”,x);
b. for(i=0;i<5;i++)
putch(x[i]);

Răspunsurile testelor de autoevaluare


5.1 a 5.2 d 5.3 c 5.4 b 5.5 c
5.6 c 5.7 b 5.8 c 5.9 c 5.10 a
5.11 c 5.12 b 5.13 c 5.14 b 5.15 c
5.16 d 5.17 c 5.18 a 5.19 d 5.20 a

181
5.21 a 5.22 b 5.23 b 5.24 c 5.25 b
5.26 b 5.27 b 5.28 b 5.29 a 5.30 b
5.31 c 5.32 a 5.33 a 5.34 b, c, d
5.35 a 5.36 c 5.37 b 5.38 b 5.39 b
5.40 b 5.41 a 5.42 b 5.43 b 5.44 c
5.45 b 5.46 b 5.47 c 5.48 a
5.49 a, b 5.50 a, b, c 5.51 a, b

Lucrare de verificare ...................................................✍

Realizaţi o prezentare a structurilor de control în limbajul C.


Scrieţi un program C care citeşte de la tastatură un vector de
numere întregi şi afişează media aritmetică a elementelor pare.
Scrieţi un program C care citeşte de la tastatură o matrice
nxn de numere întregi reprezentând durata transportului pe care
o înregistrează un autoturism între oraşele 1,2,…,n (este posibil
ca drumul de la oraşul i la oraşul j să dureze mai mult sau mai
puţin faţă de drumul de la j la i) şi afişează durata minimă a
drumurilor care pleacă din oraşul x citit la tastatură. Către ce oraş
duce drumul identificat?

Rezumat
Instrucţiunile de control ale limbajului C, care sunt
implementările, specifice limbajului, ale structurilor algoritmice
fundamentale discutate în UI4, sunt următoarele:
 instrucţiunea expresie
 instrucţiunile de decizie: if (if-else şi varianta if cu
ramură vidă) şi switch, la care se adaugă operatorul
condiţional ?:
 instrucţiunile iterative (repetitive sau de ciclare):
while, for şi do - while

182
 instrucţiunile de salt: break, continue, goto, return
Există posibilitatea ca o instrucţiune decizională să includă
o altă instrucţiune decizională şi ca o instrucţiune iterativă să
includă o altă instrucţiune iterativă; se spune în acest caz că
instrucţiunile sunt imbricate sau incluse.
Instrucţiunea break poate încheia execuţia unei prelucrări
case din instrucţiunea switch sau poate încheia forţat un ciclu.
Instrucţiunea continue, folosită numai în corpul unui ciclu,
forţează execuţia următoarei iteraţii a ciclului, omiţându-se
instrucţiunile prezente între cele două iteraţii (locul unde se află
plasată în corpul ciclului şi sfârşitul acestuia).
Instrucţiunea goto realizează un salt necondiţionat la o
instrucţiune identificată prin eticheta care urmează instrucţiunea
goto. Saltul poate fi făcut înainte sau înapoi.
Evident că în programe aceste instrucţiuni se pot combina şi
include unele în altele după cum cere algoritmul proiectat pentru
a rezolva o anume problemă.
Tablourile, acele structuri de date care reprezintă colecţii
omogene de date stocate în locaţii de memorie învecinate, sunt
implementările noţiunilor de vector (când există o singură
dimensiune), matrice (când se consideră două dimensiuni) sau
masiv multidimensional (când se consideră mai mult de două
dimensiuni) în limbajele de nivel înalt.
Un exemplu de vector, unul de matrice şi respectiv unul de
masiv multidimensional, declarate în C, sunt următoarele:
int v[50];
float a[10][20];
int t[2][2][6][10][3];

Accesul la oricare din elementele tabloului se face cu


ajutorul indicilor, care în C încep de la 0.
Dimensiunea zonei continue de memorie alocate este dată
(în octeţi) de valoarea
dim1*dim2*dim3*dimn*sizeof(tip).
unde dimi este dimensiunea i, iar tip este tipul de bază al
elementelor.
Alocarea spaţiului de memorie pentru elementele tabloului

183
se face în timpul compilării, iar dimensiunea acestui spaţiu nu
poate fi modificată pe parcursul execuţiei programului – un
tablou este un tip de dată alocat static. O dată făcută alocarea,
compilatorul nu mai face nici o verificare a dimensiunii şi prin
urmare gestionarea corectă a zonei de memorie alocate cade
exclusiv în sarcina programatorului.
Tablourile se pot iniţializa ca în exemplele:
int v[6]={-7,-2,95,21,5,-23};
float a[3][2]={1,2,3,4,5,6};

Iniţializarea elementelor tablourilor cu mai multe


dimensiuni se face după regula “ultimul indice variază cel mai
rapid“, care este o generalizare a regulii de memorare “pe linii“
întâlnite la matrici.
Pentru definirea unui şir de caractere, în C nu există un tip
special de date. Acestea se construiesc cu ajutorul tablourilor
unidimensionale, care se declară ca în exemplul
char sr[10];

Un şir memorat în variabila cu numele sr va putea avea


lungimea maximă 9, deoarece ultima poziţie, sr[9],este
ocupată cu caracterul sfârşit de şir, ’\0’.

Iniţializarea unui şir se poate face printr-o definiţie a şirului sub


forma:
char sr[10]=”aAbBcCdD”;

Funcţiile principale de prelucrare a şirurilor de caractere:


 funcţii de citire/scriere: scanf() şi printf() care
folosesc descriptorul de format %s, gets() şi puts()
 strcpy() care copiază un şir în alt şir
 strcmp() care compară lexicografic două şiruri
 strlen() care returnează lungimea unui şir
 strcat() care concatenează două şiruri

184
Bibliografie

1. Cristian Marinoiu, Programarea în limbajul C, Editura


Universităţii din Ploieşti, Ploieşti, 2000.
2. Brian Kernighan, Dennis Ritchie, The C programming Language,
Prentice Hall, 1988.
3. Herbert Schildt C: Manual complet, Editura Teora, Bucureşti,
1997.
 

185
Bibliografia cursului

1. Liviu Dumitraşcu, Monica Vlădoiu, Mihaela Oprea, Cristian


Marinoiu şi colectiv, Borland Pascal în 13 conversaţii cu CD,
capitolul 12, Structuri de date. Operaţii elementare, pag. 548-583,
Editura Universităţii din Ploieşti, 2001.
2. Luca-Dan Şerbănaţi, V. Cristea, Florica Moldoveanu, Valeriu
Iorga, Programarea sistematică în limbajele Pascal şi Fortran,
Editura Tehnică, Bucureşti, 1984.
3. Gheorghe Barbu, Ion Văduva, Mircea Boloşteanu, Bazele
Informaticii, Editura Tehnică, Bucureşti, 1997.
4. Dana Petcu, Calcul Paralel, Editura de Vest, Timişoara, 1994.
5. Tiberiu Popescu (coordonator). Dicţionar de Informatică, Editura
Ştiinţifică şi enciclopedică, Bucureşti, 1981.
6. A. Petrescu, N. Ţăpuş, T. Moisa, Gh. Rizescu, V. Hărăbor, N.
Mârşanu, Tr. Mihu, abc de calculatoare personale şi … nu doar atât
Vol.I, Ed. Tehnică, Bucureşti, 1990.
7. L. Livovschi, Bazele Informaticii, Editura Didactică şi Pedagogică,
Bucureşti, 1981.
8. Florin Păunescu, Analiza şi concepţia sistemelor de operare,
Editura Ştiinţifică şi Enciclopedică, Bucureşti, 1982.
9. Cr. Marinoiu, Programarea în limbajul C, Editura Universităţii
din Ploieşti, Ploieşti, 2000.
10. J. Glenn Brookshear, Introducere în Informatică, Ed. Teora,
Bucureşti, 1998.
11. Andrew Tanenbaum, Computer Networks, fourth edition,
Pearson Education International, 2003.

186

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