Documente Academic
Documente Profesional
Documente Cultură
1. Noţiunea de subprogram
Prin subprogram se înţelege un ansamblu alcătuit din tipuri de date, variabile şi instrucţiuni
scrise în vederea unei anumite prelucrări (calcule, citiri, scrieri) şi care poate fi utilizat (rulat) doar dacă
este apelat de un program sau de un alt subprogram.
Subprogramul este cea mai mică unitate de program care poate fi compilată separat.
Exemplu: Se citeşte un vector cu n componente numere întregi. Se cere să se tipărească vectorul
sortat.
Această problemă se rezolvă clasic, utilizând funcţia main în care se vor realiza toate
prelucrările necesare pentru rezolvarea problemei:
- citeşte dimensiunea vectorului n
- citeşte elementele vectorului
- sortează vectorul utilizând unul din algoritmii cunoscuţi
- afişează vectorul sortat
De această dată vom încerca să rezolvăm problema utilizând tehnica programării modularizate,
adică ”spărgând” problema în subprobleme mai mici care vor fi rezolvate, fiecare, de câte un
subprogram. În limbajul C, toate subprogramele sunt de tip funcţie, inclusiv main(), care este prima
funcţie care se execută la lansarea în execuţie a unui program. În acest caz, programul ar arăta astfel:
- apelează funcţia care citeşte dimensiunea şi elementele vectorului
- apelează funcţia care sortează vectorul
- apelează funcţia care afişează vectorul
Cele tri funcţii vor fi apelate din main(). Utilizând acestă metodă, vom obţine următoarea structură de
program:
funcţia main()
În structura modulară de mai sus am notat cu v vectorul supus prelucrării, iar cu n dimensiunea
lui, adică numărul de elemente.
În general, o problemă complexă se rezolvă mai uşor dacă o descompunem în altele mai
simple; şansele de a greşi la scrierea unui subprogram sunt mai mici decât acelea de a greşi la scrierea
unui program mare. Acesta din urmă rezultă din asamblarea subprogramelor la care se adaugă,
eventual, câteva linii scrise în programul principal. Avantajele utilizării subprpogramelor sunt:
- reutilizarea codului : o dată scris, un subprogram poate fi utilizat de mai multe programe
- elaborarea algoritmilor prin descompunerea problemei în altele mai simple; în acest fel putem
rezolva mai uşor problema, eventual prin colaborarea unei echipe de programatori
- reducerea numărului de erori care pot apărea la scrierea programelor
- depistarea cu uşurinţă a erorilor : verificăm subprogramele, apoi modul în care le-am asamblat
2.1 Generalităţi
În esenţă, o funcţie are structura:
antet
instrucţiune compusă
a) Anteul conţine mai multe informaţii importante necesare compilatorului şi anume: numele
funcţiei, lista parametrilor formali, tipul rezultatului.
Structura antetului este:
2
Încheierea unei funcţii se poate face în mai multe moduri, după tipul rezultatului returnat de
funcţie.
În cazul funcţiilor de tip void (care nu returnează rezultat) încheierea funcţiilor se poate face în
două moduri şi anume:
- la încheierea instrucţiunii compuse care formează corpul funcţiei (încheiere normală)
Exemplu: funcţia următoare afişează elementele vectorului v cu n elemente întregi
void afisare1(int n,int v[])
{
int i;
for(i=1;i<=n;i++)
cout<<v[i]<<” “;
cout<<“\n”;
}
Evident, acestă funcţie se încheie în momentul în care se întâlneşte acolada închisă care încheie
corpul funcţiei.
- la întâlnirea instrucţiunii return; (încheiere forţată)
Exemplu: funcţia următoare afişează doar primele elemente impare dintr-un vector v cu n elemente
întregi. La întâlnirea primei valori pare, execuţia funcţiei se încheie şi se revine în modulul apelator
(care a făcut apelul).
void afisare2(int n,int v[])
{
int i;
for(i=1;i<=n;i++)
if(v[i]%2)
cout<<v[i]<<” “;
else
return;
cout<<“\n”;
}
Dacă vectorul v=(1,-9,13,19,5,-23), funcţia va afişa toate valorile şi se va încheia normal. Dacă vectorul
v=(9,-17,21,6,11,24,9), funcţia va afişa valorile 9,-17,21 şi se va încheia forţat cu return pentru v[4]=6.
3
În cazul funcţiilor care returnează un rezultat, indiferent de natura acestuia, corpul funcţiei
trebuie să conţină cel puţin o instrucţiune de forma return expresie; prin care se returnează
rezultatul calculat de funcţie, şi în care expresie trebuie să fie de acelaşi tip cu tipul funcţiei sau să
poată fi convertit implicit către acesta.
Exemplu: următoarea funcţie verifică dacă numărul întreg x este prim sau nu returnând 1 în caz
afirmativ şi 0 în caz contrar.
int Prim(int x)
{
int d;
if(x==2) return 1;
if(!(x%2)) return 0;
for(d=3;d<=sqrt(x);d+=2)
if(!(x%d)) return 0;
return 1;
}
Evident, funcţia foloseşte algoritmul cunoscut de verificare a primalităţii unui număr întreg, având patru
instrucţiuni return care tratează toate cazurile posibile: x=2, x par diferit de 2, x impar compus, x impar
prim.
Apelul unei funcţii se poate face din main() sau dintr-o altă funcţie. Apelul se poate face de
sine stător sau din interiorul unei expresii.
În cazul funcţiilor de tip void, apelul acestora nu se poate face decât de sine stătător cu o
instrucţiune de apel de forma nume_funcţie(listă-parametri-efectivi); unde lista-
parametrilor-efectivi este lista valorilor concrete cu care se apelează funcţia, şi este desigur vidă
dacă şi lista parametrilor formali este vidă. Spre exemplu, funcţia de afişare a elementelor unui vector
se poate apela din main() cu instrucţiunea afisare1(n,a); unde a este tabloul efectiv ale cărui
elemente se vor afişa.
În cazul funcţiilor care returnează un rezultat acestea se pot apela direct dintr-o expresie, caz
în care mai întâi se apelează funcţia şi apoi rezultatul returnat de aceasta este folosit pentru evaluarea
expresiei. Spre exemplu, următoarea secvenţă de program foloseşte funcţia Prim() descrisă anterior
pentru a afişa elementele prime dintr-un vector a cu n elemente întregi.
for(i=1;i<=n;i++)
if(Prim(a[i])) cout<<“%d “,a[i]);
Apelul funcţiei Prim() se face din condiţia instrucţiunii if (expresie logică). Desigur, dacă dorim, putem
neglija rezultatul returnat de o funcţie şi să o apelăm de sine stătător. Spre exemplu, deşi funcţiile
scanf(), printf(), getch() şi nu numai, returnează rezultate de tip int, uzual le apelăm de sine stătător şi
nu folosim rezultatul pe care îl returnează.
Până în prezent am declarat variabile doar în corpul funcţiilor, inclusiv în cel al funcţiei main().
Variabilele astfel declarate se numesc locale. Sistemul de operare alocă fiecărui program trei zone
distincte în memoria internă a calculatorului, în care se găsesc memorate variabilele programului. Harta
simplificată a memoriei interne este prezentată în continuare:
segment de date
segment de stivă
heap
Segmentul de date este folosit pentru stocarea codului programului aflat în execuţie şi pentru
variabilele care sunt folosite de către acesta pe toată durata execuţiei. Codul unui program se încarcă
în segmentul de date numai în moţmentul în care acesta este lansat în execuţie, această operaţie
realizându-se de către o componentă a sistemului de operare numită încărcător (loader). Reamintim că
una din principalele sarcini ale sistemului de operare este gestionarea resurselor fizice şi logice ale unui
sistem de calcul, cele mai importante resurse fiind memoria RAM şi timpul de lucru al procesorului.
Evident, în momentul în carte execuţia programului se încheie, sistemul dealocă memoria din
segmentul de date, programul şi toate variabilele acestuia devenind inaccesibile.
Segmentul de stivă este utilizat pentru a realiza transferul parametrilor la apelul
subprogramelor şi pentru a controla execuţia programului în cazul lucrului cu subprograme. În
4
momentul în care este apelată o funcţie (un subprogram), controlul programului este cedat acesteia.
Funcţia se execută instrucţiune cu instrucţiune până la încheierea normală sau forţată a acesteia. În
acest moment controlul programului revine modulului care a făcut apelul (funcţia main() sau orice altă
funcţie). Pentru ca această revenire să se facă corect, pe stivă se salvează, în momentul apelului,
adresa de revenire (spre exemplu, adresa instrucţiunii imediat următoare instrucţiunii de apel) şi
contextul din care s-a făcut apelul, adică valorile tuturor variabilelor locale modulului apelator. În
momentul în care execuţia funcţiei se încheie, se recuperează de pe stivă aceste informaţii în ordine
inversă, adică se reface contextul din care s-a făcut apelul şi se află adresa de revenire. În acest fel,
execuţia modului apelator va continua corect după execuţia apelului funcţiei. În absenţa segmentului de
stivă nu ar fi posibilă implementarea lucrului cu subprograme. În continuare vom vedea că stiva are şi
alte destinaţii extrem de importante.
Zona heap se numeşte şi zonă de accumulare a variabilelor dinamice şi se foloseşte pentru
alocarea variabilelor dinamice, create la cererea expresă a programatorului, în timpul execuţiei unui
program prin apelul funcţiei malloc(), de exemplu, sau prin utilizarea operatorului new.
De asemenea, în limbajul C, există posibilitatea ca variabilele să fie memorate într-un anumit
registru al microprocesorului. În acest caz, timpul de acces la astfel de variabile este foarte mic, deci se
pot obţine programe optimizate. Numărul variabilelor care pot fi memorate în regiştrii interni este însă
redus.
În general o variabilă se caracterizează prin patru atribute şi anume:
- clasa de memorare
- vizibilitatea
- durata de viaţă
- tipul variabilei, singurul studiat până în acest moment
Clasa de memorare precizează locul unde este memorată variabila respectivă. O variabilă
poate fi memorată în segmentul de date, în cel de stivă, în heap sau într-un registru al
microprocesorului.
Vizibilitatea precizează liniile textului sursă din care variabila respectivă poate fi accesată.
Astfel avem:
- vizibilitate la nivel de bloc (instrucţiune compusă)
- vizibilitate la nivel de fişier, în cazul în care programul ocupă doar un singur fişier sursă (singurul
caz tratat momentan)
- vizibilitate la nivel de clasă, legată de programarea orientată pe obiecte, facilitate specifică în C++
Durata de viaţă reprezintă timpul în care variabila respectivă are alocat spaţiu în memoria
internă (deci există efectiv). Astfel avem:
- durată statică, conform căreia variabila are alocat spaţiu în tot timpul execuţiei programului
- durată locală, conform căreia variabila are alocat spaţiu în timpul în care se execută înstrucţiunile
blocului respectiv (blocul care conţine declaraţia variabilei)
- durată dinamică, caz în care alocarea şi dealocarea spaţiului necesar variabilei respective se face
explicit de către programator, în timpul execuţiei programului, prin folosirea unor operatori şi funcţii
speciale (de exemplu, new, malloc() etc.)
În limbajul C/C++ variabilele pot fi împărţite în trei mari categorii: locale, globale şi dinamice.
Aceste variabile sunt declarate în corpul funcţiilor, mai precis, pot fi declarate în orice bloc
(instrucţiune compusă) al acestora.
Observaţie: Variabilele declarate în funcţia main() sunt tot variabile locale, deci sunt vizibile numai în
această funcţie.
În exemplul următor, variabila a este declarată în corpul funcţiei t(), iar variabila b este
declarată în corpul funcţiei main():
void t()
{
int a=3;
cout<<a+2;
}
void main()
{
int b=4;
cout<<b--; t();
}
{
a=5; // referă variabila globală a
f();
cout<<a; ; // tipăreşte a=5
}
Observaţie: În cazul în care, într-un anumit bloc sunt vizibile (se pot accesa) mai multe variabile cu
acelaşi nume, dar cu domenii de vizibilitate diferite, se accesează variabila cu vizibilitatea cea mai
mică. Este cazul variabilei a din blocul interior funcţiei func() pentru care se consideră cea mai mică
vizibilitate (cea de bloc) şi se tipăreşte valoarea 3.
Observaţie: Durata de viaţă a unei variabile locale poate fi modificată folosind atributul static, astfel
încât, deşi respectiva variabilă nu este recunoscută în afara funcţiei, ea nu moare odată cu revenirea
dintr-un apel. Cu alte cuvinte, apeluri succesive vor regăsi, fiecare, valoarea lăsată de apelul anterior.
Exemplu: În urma execuţiei programului următor, variabila m va avea valoarea 3, deoarece cele două
apeluri succesive ale funcţiei f() vor returna valorile 1, respectiv 2, variabila locală a având atributul
static.
#include<iostream.h>
int f()
{
static int a=1;
return a++;
}
void main()
{
int m;
m=f()+f();
cout<<m;
}
7
Se utilizează atunci când suntem interesaţi ca subprogramul să lucreze cu acea valoare, dar să
nu poată modifica parametrul efectiv corespunzător din blocul apelator.
Se pot transmite prin valoare:
1. Valorile reţinute de variabile. În acest caz parametrii efectivi trebuie să fie numele
variabilelor. Exemplu:
void test(int n)
{
n++;
8
Se observă că, în momentul apelului funcţiei test(), pe stivă sunt alocate două variabile cu acelaşi
nume n. Prima variabilă este variabila locală funcţiei main() care se salvează pe stivă în momentul
apelului pentru a putea reface contextul funcţiei main() după încheierea apelului. A doua variabilă
este parametrul formal tip valoare n, vizibil numai în funcţia test() şi iniţializat în momentul apelului
cu valoarea 7. Indiferent ce valori primeşte acest n în corpul funcţiei test(), după încheierea
execuţiei acestei funcţii, spaţiul său este dealocat din stivă, adică variabila respectivă este distrusă.
Din acest motiv, după execuţia funcţiei test(), conţinutul stivei este cel din dreapta. Se reface
contextul din care s-a lansat apelul funcţiei test(), adică se recuperează din stivă valoarea variabilei
locale n=7 şi adresa de revenire, adică adresa instrucţiunii printf.
2. Expresii. În acest caz, parametrii efectivi sunt expresii, care pot conţine şi funcţii şi care mai
întâi se evaluează. Exemplu:
#include<iostream.h>
#include<math.h>
void test(int n)
{
cout<<”n=”<<n;
}
void main()
{
test(5); // se va tipări 5
test(7+(int)sqrt(45)); // se va tipări 13
}
În funcţie se crează o variabilă numită n, reţinută pe stivă, care la primul apel va primi valoarea
5 şi la al doilea apel valoarea 13. La ieşirea din funcţie conţinutul acestei variabile se pierde.
Transmiterea parametrilor prin valoare se utilizează când nu dorim ca subprogramul apelat să poată
modifica parametrii efectivi de apel. Acesta este modul implicit de transmitere a parametrilor în limbajul
C. Dacă nu ar exista decât transmiterea prin valoare, ar fi imposibil să modificăm valoarea anumitor
valori care sunt declarate în blocul apelator. Acest lucru este totuşi posibil dacă lucrăm cu variabile de
tip pointer, care, aşa cum ştim deja, conţin adresele de memorie ale altor variabile din program. Având
acces la locaţia de memorie a unei variabile (prin adresa ei), îi putem desigur modifica conţinutul.
Funcţia următoare realizează interschimbarea valorilor a două variabile din programul principal. Pentru
9
a putea face acest lucru, funcţia primeşte adresele de memorie ale celor două variabile, adică doi
pointeri.
#include<iostream.h>
void schimba(int *x,int *y)
{ int aux;
aux=*x;
*x=*y;
*y=aux;
}
void main()
{ int a=7, b=12;
schimba(&a,&b);
cout<<“a=”<<a<<”\t b=”<<b; // tipăreşte a=12, b=7
}
Se observă că parametrii formali sunt doi pointeri la întreg care în momentul apelului primesc ca valori
adresa variabilei a, respectiv b (obţinute prin aplicarea operatorului &). În limbajul C acesta este
singurul mod prin care se pot transmite parametrii prin adresă, deci modifica de către un subprogram
apelat. Pentru exemplul anterior, evoluţia stivei este:
Când membrul unei structuri este transmis unei funcţii, ceea ce se transmite funcţiei este de
fapt valoarea acelui membru. Ca atare, se transmite doar o variabilă. Fie structura următoare:
struct info
{
char x;
int y;
float z;
char s[10];
}set;
Iată exemple de transmitere ale fiecărui membru către o funcţie:
func(set.x); // transmite valoarea caracter a lui x
11
Observaţie: Poate fi tip al unei funcţii orice tip de dată cu excepţia tablourilor. Dacă ţinem neapărat,
există posibilitatea ca funcţia să întoarcă tablouri, dacă acestea sunt înglobate în tipuri declarate cu
struct, aşa cum se arată în exemplul următor:
#include<iostream.h>
struct MAT{
float matrice[6][8];
};
MAT citire(int m,int n)
{
MAT a;
int i,j;
for(i=0;i<m;i++)
for(j=0;j<n;j++) cin>>a.matrice[i][j]);
12
return a;
}
void main()
{
int i,j;
MAT mtr=citire(3,2);
for(i=0;i<3;i++)
{
for(j=0;j<2;j++) cout<<mtr.matrice[i][j]<<” ”;
cout<<“\n”;
}
}
În limbajul C++ există un tip special de date care permite ca o variabilă să fie identificată prin
mai multe nume, tip numit referinţă. Aparent, programul lucrează cu mai multe variabile, dar de fapt toţi
identificatorii respectivi referă aceeaşi locaţie de memorie. Declararea unei variabile de tip referinţă se
face cu sintaxa:
tip& nume variabilă=valoare de iniţializare;
În programul următor, variabila x este o referinţă pentru variabila y. Ele au aceeaşi valoare şi aceeaşi
adresă de memorie, dar poartă nume diferite.
#include<iostream.h>
void main()
{
int x=7;int& y=x; // sau int x=7, &y=a;
cout<<“x=”<<x<<“ si are adresa “<<&x<<endl;
cout<<“y=”<<y<<“ si are adresa “<<&y<<endl;
}
În cazul subprogramelor, parametrii sunt transmişi prin referinţă atunci când ne interesează ca la
revenirea din subprogram variabila transmisă să reţină valoarea stabilită în timpul execuţiei
subprogramului.
În cazul transmiterii prin referinţă parametrii formali trebuie să fie referinţe la variabile. În acest
caz subprogramul având acces la adresa de memorie a parametrului efectiv corespunzător, îl poate
modifica.
Exemplu: Programul următor interschimbă valorile a două variabile transmise prin referinţă.
#include<iostream.h>
void schimba(int &a, int &b)
{
int aux=a; a=b; b=aux;
}
void main()
{
int x=7, y=5;
schimba(x,y);
cout<<” x=”<<x<<”\ty=”<<y;
}
Concluzii:
a) În momentul în care într-un subprogram este întâlnită instrucţiunea de apel a unui alt subprogram,
controlul execuţiei este cedat subprogramului apelat şi pe stivă se depun, în ordine:
- adresa de revenire din subprogramul apelat
- valorile variabilelor locale subprogramului apelator (contextul din care s-a făcut apelul)
- valorile parametrilor transmişi prin valoare
b) Revenirea din subprogramul apelat se face fie la întâlnirea instrucţiunii return, fie la întâlnirea
acoladei care încheie instrucţiunea compusă a subprogramului apelat
c) La încheierea execuţiei subprogramului apelat se recuperează din stivă, în ordine, valorile
variabilelor locale subprogramului apelator şi adresa de revenire, adică se reface contextul din care s-a
făcut apelul.
13
Observaţie: În prototipul unei funcţii se poate omite numele parametrilor formali, precizându-se numai
tipul acestora. Spre exemplu, este corect un prototip de forma float func(int, int&); care declară o
funcţie cu rezultat de tip float si doi parametri, unul valoare de tip int şi unul referinţă la int.
În C++ este o practică uzuală să se scrie mai întâi prototipurile tuturor funcţiilor utilizate în
program, fără funcţia main(), iar după funcţia main() să fie definite aceste funcţii. În acest fel, orice
funcţie, mai puţin main(), poate fi apelată din oricare alta.
parametru şi aşa mai departe. De regulă, parametrii ficşi conţin informaţii despre cei variabili (numărul
lor, în unele cazuri tipul lor).
În exemplul următor, funcţia f are un număr neprecizat de parametri, aspect semnalat prin
prezenţa celor trei puncte după parametrul fix n în antetul funcţiei. Accesarea parametrilor actuali în
momentul apelului se bazează pe faptul că parametrii se memorează la adrese consecutive în stivă.
Astfel, se pleacă de la adresa ultimului parametru fix, în acest exemplu &n. Valoarea &n+1 reprezintă
adresa următorului parametru, adică a primului parametru variabil, &n+2 este adresa celui de-al doilea
parametru variabil etc. În felul acesta, valorile care vor apărea la apel după parametrii ficşi vor putea fi
accesaţi printr-un calcul obişnuit de adrese şi funcţia va returna maximul dintre elementele vectorului x,
adică 23.
#include<iostream.h>
int f(int n,…)
{
int *x=&n+1, m=x[0], j;
for(j=1;j<n;j++)
x[j]>m? m=x[j]: m=m;
return m;
}
void main()
{
cout<<f(4,12,11,23,2);
}
Un alt aspect important referitor la funcţiile limbajului C este posibilitatea de a iniţializa
parametrii formali ai unei funcţii direct în antetul acesteia. În acestă situaţii, la apelul funcţiei pot să
lipsească unul sau mai mulţi parametri actuali, chiar toţi parametrii. În cazul în care la apel lipseşte un
parametru actual, compilatorul va folosi în funcţie valoarea cu care a fost iniţializat la declarare
parametrul formal aferent.
Exemplu: Programul următor este corect şi va afişa valorile m=6, n=15, p=34 şi q=52.
#include<iostream.h>
int f(int a=1,int b=2,int c=3)
{
return a+b+c;
}
void main()
{
int m,n,p,q;
m=f();
n=f(10);
p=f(12,19);
q=f(11,23,18);
cout<<m << ” ”<<n<<” ”p<<” ”q;
}
{
int a,b;
scanf(“%d %d”,&a,&b);
if(a>=b) calcul(a,b,ma);
else if(a>0 && b>0)
calcul(a,b,mg);
}
În acest exemplu, funcţia calcul are un antet mai deosebit. Primii doi parametri sunt doi întregi
x şi y. Al treilea parametru, float (*f)(int,int) , reprezintă un pointer către o funcţie f. Această
funcţie f are la rândul ei doi parametri de tipul int. Nu este necesar să se precizeze numele acestor
parametri, ci doar tipul lor. Instrucţiunea cout<<“%.1f”,f(x,y)); din corpul funcţiei f afişează
valoarea întoarsă de funcţie. În funcţia main() se fac apelurile: calcul(a,b,ma);, respectiv
calcul(a,b,mg);. La apel, al treilea parametru din antet (pointerul la funcţie), este înlocuit cu
numele unei funcţii, ma, respectiv, mg. Aceste funcţii au fost scrise anterior. Spre exemplu, dacă se
citesc valorile a=7 şi b=6, identificatorul f este înlocuit cu ma, se calculează media aritmetică a
parametrilor x şi y şi se tipăreşte valoarea 6.5. Dacă se citeşte a=2 şi b=8, identificatorul f se
înlocuieşte cu mg, se calculează media geometrică a parametrilor x şi y şi se tipăreşte valoarea 4.
}
void citire(int& n, int x[])
{
int i;
cout<<“n="); scanf("%d",&n);
for(i=0;i<n;i++)
{
cout<<“el[„<<i<<”]=";
cin>>x[i];
}
}
int cmmdc(int a,int b)
{
while(a!=b)
if(a>b) a-=b;
else b-=a;
return a;
}
Exemplul 4: Să se scrie o funcţie care citeşte o matrice cu elemente numere întregi dintr-un fişier text
cu numele f.in. Pe prima linie a fişierului se găsesc două valori separate prin spaţii care reprezintă
numărul de linii şi, respectiv, de coloane (m şi n). Următoarele m linii ale fişierului conţin, în ordine,
elementele aflate pe fiecare linie a matricei. Matricea astfel obţinută va fi tipărită în main().
Funcţia de citire a matricii va primi ca parametri de intrare referinţe la variabilele m şi n şi
adresa tabloului citit, care are cel mult 10 linii şi 10 coloane.
#include<fstream.h>
void citire(int& m,int& n,int a[10][10])
{
int i,j;
FILE *f;
f=fopen("f.in","rt");
fscanf(f,"%d %d",&m,&n);
for(i=0;i<m;i++)
for(j=0;j<n;j++)
fscanf(f,"%d",&a[i][j]);
fclose(f);
}
void main()
{
int m,n,a[10][10],i,j;
citire(m,n,a);
cout<<“\n\t Matricea citita este:\n");
for(i=0;i<m;i++)
{
for(j=0;j<n;j++) cout<<a[i][j]<< “ ",;
cout<<“\n";
}
}