Sunteți pe pagina 1din 12

Valeriu Iorga

Programare n C / C++

9. Functii (2) 9.1. Mecanisme de transfer ale parametrilor. n limbajele de programare exist dou mecanisme principale de transfer ale parametrilor: transferul prin valoare i transferul prin referin. n C parametrii se transfer numai prin valoare- aceasta nseamn c parametrii actuali sunt copiai n zona de memorie rezervat pentru parametrii formali. Modificarea parametrilor formali se va reflecta asupra copiilor parametrilor actuali i nu afecteaz parametrii actuali, adic parametrii actuali nu pot fi modificai ! Astfel funcia: void schimb(int a, int b) { int c=a; a=b; b=c; } nu produce interschimbul parametrilor actuali x i y din funcia main(): void main(void) { int x=10,y=15; printf(%d\t%d\n, x, y); schimb(x, y); printf(%d\t%d\n, x, y); } Se afieaz: 10 15 10 15 Stiva funciei apelante x y
10 15

Stiva funciei apelate

10

1 3 2 c

15

n cazul transferului prin referin, pentru modificarea parametrilor actuali, funciei i se transmit nu valorile parametrilor actuali, ci adresele lor. Forma corect a funciei schimb() obinut prin simularea transferului prin referin cu pointeri este: void schimb(int *a, int *b) { int c; c = *a; *a = *b; *b = c; } void main(void) { int x=10,y=15; printf(%d\t%d\n, x, y);

Valeriu Iorga schimb(&x, &y); printf(%d\t%d\n, x, y); } Stiva funciei apelante ntreg x C y ntreg b a ntreg pointer Stiva funciei apelate pointer

Programare n C / C++

In consecin, pentru a transmite un rezultat prin lista de parametri (adic pentru a modifica un parametru) va trebui s declarm parametrul formal ca pointer. Tablourile sunt transmise ntotdeauna prin referin, adic un parametru formal tablou reprezint o adres (un pointer) i anume adresa de nceput a tabloului. n C++ a fost introdus transferul parametrilor prin referin, ceea ce simplific n mod considerabil scrierea. Un parametru formal transmis prin referin este specificat prin: tip&. Funcia schimb() se definete n acest caz astfel: void schimb(int &a, int &b) { int c; c = a; a = b; b = c; } void main(void) { int x=10,y=15; printf(%d\t%d\n, x, y); schimb(x, y); printf(%d\t%d\n, x, y); } 9.2. Funcii care ntorc pointeri. Funcia strcpy() ntoarce adresa irului destinaie: char *strcpy(char *d, char *s) { char *p=d; while (*p++=*s++) ; return d; } Aceasta ne permite ca simultan cu copierea s calculm lungimea irului copiat: n=strlen((strcpy)d,s)); Dac funcia ntoarce adresa unei variabile locale, atunci aceasta trebuie s fie n mod obligatoriu n clasa static. De asemeni nu trebuiesc ntoarse adrese ale unor parametri, deoarece acetia sunt transmii prin stiv.

Valeriu Iorga 9.3. Pointeri la funcii.

Programare n C / C++

Numele unei funcii reprezint adresa de memorie la care ncepe funcia. Numele functiei este, de fapt, un pointer la funcie. Se poate stabili o coresponden ntre variabile i funcii prin intermediul pointerilor la funcii. Ca i variabilele, aceti pointeri: pot primi ca valori funcii; pot fi transmii ca parametrii altor funcii pot fi intori ca rezultate de ctre funcii La declararea unui pointer ctre o funcie trebuiesc precizate toate informaiile despre funcie, adic:

tipul funciei numrul de parametri

tipul parametrilor care ne vor permite s apelm indirect funcia prin intermediul pointerului. Declararea unui pointer la o funcie se face prin: tip (*pf)(list_parametri_formali); Dac nu s-ar folosi paranteze, ar fi vorba de o funcie care ntoarce un pointer. Apelul unei funcii prin intermediul unui pointer are forma: (*pf)(list_parametri_actuali); Este permis i apelul fr indirectare: pf(list_parametri_actuali); Este posibil s creem un tablou de pointeri la funcii; apelarea funciilor, n acest caz, se face prin referirea la componentele tabloului. De exemplu, iniializarea unui tablou cu pointeri cu funciile matematice uzuale se face prin: double (*tabfun[])(double) = {sin, cos, tan, exp, log}; Pentru a calcula rdcina de ordinul 5 din e este suficient atribuirea: y = (*tabfun[3])(0.2); Numele unei funcii fiind un pointer ctre funcie, poate fi folosit ca parametru n apeluri de funcii. n acest mod putem transmite n lista de parametri a unei funcii numele altei funcii. De exemplu, o funcie care calculeaz integrala definit: I =
b

f(x) dx
a

va avea prototipul: double integrala(double, double, double(*)(double)); Definii o funcie pentru calculul unei integrale definite prin metoda trapezelor,cu un numr fixat n de puncte de diviziune: f (a) + f (b) n 1 b a = h + f (a + ih) cu h = 2 n i=1 a Folosii apoi aceast funcie pentru calculul unei integrale definite cu o precizie dat . Aceast precizie este atins n momentul n care diferena ntre dou integrale, calculate cu n, respectiv 2n puncte de diviziune este inferioar lui

f(x)dx

#include <math.h> double sinxp();

Valeriu Iorga double trapez(double,double,int,double(*)()); double a=0.0, b=1.0, eps=1E-6; int N=10; void main(void) { int n=N; double In,I2n,vabs; In=trapez(a,b,n,sinxp); do { n*=2; I2n=trapez(a,b,n,sinxp); if((vabs=In-I2n)<0) vabs=-vabs; In=I2n; } while(vabs > eps); printf(%6.2lf\n, I2n); } double trapez(double a,double b,int n,double(*f)()) { double h,s; int i; h=(b-a)/n; for(s=0.0,i=1;i<n;i++) s+=(*f)(a+i*h); s+=((*f)(a)+(*f)(b))/2.0; s*=h; return s; } 9.4. Declaratii complexe.

Programare n C / C++

O declaratie complex este o combinaie de pointeri, tablouri si functii. In acest scop se folosesc atributele: () functie [] tablou * - pointer care pot genera urmatoarele combinatii: * () funcie ce returneaz un pointer (*)() pointer la o funcie * [] - tablou de pointeri (*) [] pointer la tablou [ ] [] tablou bidimensional Exist i combinaii incorecte, provenite din faptul c n C nu este permis declararea: - unui tablou de funcii - unei funcii ce returneaz un tablou. Acestea sunt: ( ) [ ] funcie ce returneaz un tablou [ ] ( ) tablou de funcii ( ) ( ) funcie ce returneaz o funcie Pentru a interpreta o declaraie complex vom inlocui atributele prin urmtoarele abloane text: Atribut () [n] * Sablon text functia returneaz tablou de n pointer la

Descifrarea unei declaraii complexe se face aplicnd regula dreapta stnga, care presupune urmtorii pai: se incepe cu identificatorul

Valeriu Iorga

Programare n C / C++

se caut n dreapta identificatorului un atribut dac nu exist, se caut n partea stang se substituie atributul cu ablonul text corespunztor se continu substituia dreapta-stnga se oprete procesul la ntlnirea tipului datei. De exemplu: int (* a[10]) ( ); tablou de 10 pointeri la funcii ce returneaz int double (*(*pf)())[3][4]; pointer la o funcie ce returneaz un pointer la un tablou cu 3 linii si 4 coloane de double

In loc de a construi declaraii complexe, se prefer, pentru creterea claritii, s definim progresiv noi tipuri folosind typedef. Reamintim c declaraia typedef asociaz un nume unei definiri de tip: typedef <definire de tip> identificator; Exemple: typedef char *SIR; /*tipul SIR=sir de caractere*/ typedef float VECTOR[10];/*tipul VECTOR=tablou de 10float*/ typedef float MATRICE[10][10];/*tipul MATRICE= tablou de 10x10 float */ typedef double (*PFADRD)(double);/*tipul PFADRD=pointer la functie de argument double si rezultat double */ Vom putea folosi aceste tipuri noi n definirea de variabile: SIR s1, s2; VECTOR b, x; MATRICE a; PFADRD pf1; 10. Tablouri i pointeri (2). 10.1. Alocarea dinamic a memoriei. Utilizatorul poate solicita n timpul execuiei programului alocarea unei zone de memorie. Aceast zon de memorie poate fi eliberat, n momentul n care nu mai este necesar. Alocarea i eliberarea de memorie la execuie permite gestionarea optim a memoriei. Biblioteca standard ofer 4 funcii, avnd prototipurile n <alloc.h> i <stdlib.h>. Acestea sunt: void *malloc(unsigned n); Funcia aloc un bloc de memorie de n octei. Funcia ntoarce un pointer la nceputul zonei alocate. n caz c cererea de alocare nu poate fi satisfcut, funcia returneaz NULL. void *calloc(unsigned nelem, unsigned dim); Aloc nelem*dim octei de memorie (nelem blocuri formate din dim octei fiecare). ntoarce un pointer la nceputul zonei alocate sau NULL.Memoria alocat este iniializat cu zerouri. void free(void *p); Funcia elibereaz o zon de memorie indicat de p, alocat n prealabil prin malloc() sau calloc().

Valeriu Iorga void *realloc(void *p, unsigned dim);

Programare n C / C++

Modific dimensiunea spaiului alocat prin pointerul p, la dim. Funcia ntoarce adresa zonei de memorie realocate, iar pointerul p va adresa zona realocat.

dac dimensiunea blocului realocat este mai mic dect a blocului iniial, p nu se modific, iar funcia va ntoarce valoarea lui p. dac dim==0 zona adresat de p va fi eliberat i funcia ntoarce NULL. dac p==NULL, funcia aloc o zon de dim octei (echivalent cu malloc()).

Funciile de alocare ntorc pointeri generici (void*) la zone de memorie, n timp ce utilizatorul aloc memorie ce pstreaz informaii de un anumit tip. Pentru a putea accesa memoria alocat, indirect, prin intermediul pointerului, acesta va trebui s fie un pointer cu tip, ceea ce impune conversia explicit (prin cast) a pointerului ntors de funcia de alocare ntr-un pointer cu tip. De exemplu, pentru a aloca un vector de ntregi, avnd n elemente vom folosi: int *p: if (p=(int*)malloc(n*sizeof(int))==NULL) { printf(Memorie insuficienta\n); exit(1); } Funciile care ntorc pointeri sunt utile n alocarea de spaiu pentru variabile dinamice. Variabilele dinamice sunt alocate n momentul execuiei, nu au nume i sunt accesate prin pointeri. Un constructor este o funcie care aloc spaiu n mod dinamic pentru o variabil i ntoarce un pointer la spaiul rezervat. Un destructor este o funcie care primete un pointer la o zon alocat dinamic i elibereaz aceast zon. O funcie util, strdup() salveaz un ir de caractere ntr-o zon alocat dinamic i ntoarce un pointer la acea zon sau NULL. char *strdup(char *s) { char *p; p=(char*) malloc(strlen(s)+1); if (p!=NULL) strcpy(p,s); return p; } Exemplul 29: Citii de la intrarea standard un ir de caractere de lungime necunoscut ntr-un vector alocat dinamic. Alocarea de memorie se va face progresiv, n incremente de lungime INC, dup citirea a INC caractere se face o realocare. char *citire() { char *p, *q; int n; unsigned dim=INC; p=q=(char*)malloc(dim); for(n=1; (*p=getchar())!=\n &&*p!=EOF; n++) { if(n%INC==0) { dim+=INC; p=q=realloc(q,dim); p+=n; continue; } p++; }

Valeriu Iorga *p=\0; return realloc(q,n); }

Programare n C / C++

n C++, alocarea dinamic se face mai simplu i mai sigur, folosind operatorii new i delete. Operatorul new permite alocarea de memorie n heap. El se folosete ntr-una din formele: tip *p, *q, *r; p=new tip; //rezerva in heap o zona de sizeof(tip) octeti q=new tip(expresie);//acelasi efect cu initializare cu val.expresiei r=new tip[expint]; //rezerva o zona neinitializata de // expint*sizeof(tip) octeti Eliberarea memoriei alocate se face prin: delete p; delete [] r; //elibereaza memoria alocata pentru tablou 10.2. Pointeri la pointeri. Adresa unei variabile pointer va fi de tip pointer ctre pointer (pointer dublu) S considerm definiiile: int x=10, *px=&x, **ppx=&px; care corespund situaiei: ppx px x
10

pentru a obine valoarea 10 putem folosi x, *px sau **ppx. O funcie care interschimb doi pointeri are forma: void pschimb(int **pa, int **pb) { int *ptemp; ptemp=*pa; *pa=*pb; *pb=ptemp; } cu apelul: int *px, *py; pschimb(&px, &py); Deoarece un tablou este accesat printr/un pointer, tablourile de pointeri pot fi accesate cu pointeri dubli: char *a[10]; char **pa; p=a; Funcia de afiare a irurilor de caractere adresate de un tablou de pointeri poate fi rescris ca: void afisare(char **tp, int n) { while(n--) printf(%s\n,*tp++); } 10.3. Tablouri multidimensionale. Un tablou cu mai multe dimensiuni se definete prin: tip nume[d1][d2][dn];

Valeriu Iorga

Programare n C / C++

Referirile la elemente unui tablou cu mai multe dimensiuni se fac folosind variabile indexate de forma: nume[i1][i2][in], n care 0<=ik<=dk-1 Un tablou cu n dimensiuni poate fi considerat ca un tablou cu o dimensiune avnd ca elemente tablouri cu n-1 dimensiuni. Elementele tabloului ocup o zon continu de memorie de: d1 x d2 xx dn x sizeof(T) octei. Adresa n memorie a unui element a[i1][i2][in] este dat de funcia de alocare: &a[i1][i2][in]=a+sizeof(T)*[i1*d2**dn+i2*d3**dn++in] n cazul vectorilor: &a[i]=a+sizeof(T)*i aceasta ne permite ca la declararea unui parametru vector s nu specificm dimensiunea tabloului. n cazul matricilor, compilatorul le transform n vectori: &a[i][j]=a+sizeof(T)*(i*C+j) i n cazul matricelor, ca i la vectori putem nlocui indexarea prin operaii cu indici i avem: a[i][j] = (*(a+i)[j]=*(*(a+i)+j) La transmiterea unui tablou multidimensional ca parametru al unei funcii vom omite numai prima dimensiune, celelalte trebuind s fie specificate. Prin urmare, prototipul unei funcii de afiare a unei matrici avnd l linii i c coloane nu poate fi scris ca: void matprint(int a[][], int l, int c); ci: void matprint(int a[][DMAX], int l, int c); n care DMAX este numrul de coloane al matricii din apel, ceeace ne limiteaz utilizarea funciei numai pentru matrici cu DMAX coloane! Vom reda generalitate funciei de afiare a matricilor, declarnd matricea parametru ca un vector de pointeri: void matprint(int (*a)[], int l, int c) { int i,j; for(i=0;i<l;i++) { for (j=0;j<c;j++) printf(%d,((int*)a)[i*n+j]; printf(\n); } } Problema transmiterii matricilor ca parametri poate fi evitat, dac le linearizm, transformndu-le n vectori. n acest caz, n locul folosirii a doi indici i i j vom folosi un singur indice: k=i*C+j Exemplul 30: Scriei o funcie pentru nmulirea a dou matrici A i B avnd mxn, respectiv nxp elemente. Matricea produs va avea mxp elemente, care vor fi calculate cu relaia: C ij =
n 1 k=0

ik

B kj

void matprod(int m,int n, int p, double A[], double B[], double C[]) { int i, j, k, ij; for (i=0; i<m; i++) for (j=0; j<p; j++) {

Valeriu Iorga ij=i*p+j; for (k=0; k<n; k++) C[ij]=C[ij]+A[i*n+k]*B[k*p+j];

Programare n C / C++

} }

Soluia propus nu ne permite s acceesm elementele matricelor folosind 2 indici. Am putea nlocui matricea printr-un vector de pointeri la liniile matricei. Exemplul 31: Definii o funcie care aloc dinamic memorie pentru o matrice avnd l linii i c coloane. a plin pelem plin[0] pelem[0][0] plin[1] pelem[0][1] plin[2] pelem[1][0] pelem[1][1] pelem[2][1] pelem[2][0] double **alocmat(int lin, int col) { double **plin; double *pelem; int i; pelem=(double*)calloc(lin*col, sizeof(double)); if(pelem==(double*)NULL){ printf(spatiu insuficient\n); exit(1);} plin=(double**)calloc(lin, sizeof(double*); if(plin==(double**)NULL){ printf(spatiu insuficient\n); exit(1); } for (i=0; i< lin; i++) { plin[i]=pelem; pelem+=col; } return plin; } 10.4. Probleme propuse. 1. S se construiasc un patrat magic de dimensiune n (cu n impar), adic o matrice cu n linii i n coloane avnd elemente numerele naturale 1,2,...,n2 astfel nct sumele elementelor pe linii, pe coloane i pe cele dou diagonale s fie identice. 2 .S se stabileasc dac exist elemente comune tuturor liniilor unei matrici date. Se vor afia cte asemenea elemente sunt, care sunt acestea i apoi se va indica ce poziie ocup acestea n fiecare linie. 3. O matrice ptrat a are n linii i n coloane. Cele dou diagonale determin patru zone notate 1,2,3,4 care nu includ elementele de pe diagonale. S se calculeze mediile geometrice ale elementelor pozitive din zonele 1 i 2. Dac media nu se poate calcula, se va afia un mesaj corespunztor. S se calculeze procentajul de elemente strict pozitive din zona 3 i numrul de elemente divizibile cu 5 din zona 4.Dac nu exist elemente cu proprietile cerute se va afia un mesaj corespunztor.

Valeriu Iorga

Programare n C / C++

4. Se dau dou matrici A i B ptrate, de ordin n. S se stabileasc dac cele dou matrici sunt sau nu una inversa celeilalte.n acest scop se creeaz matricea produs C=A*B i se verific dac aceasta este matricea unitate. 5. Dintr-o matrice A, avnd n linii i n coloane s se afieze liniile care reprezint iruri ordonate cresctor i coloanele care reprezint iruri ordonate descresctor. 6. O matrice a are p linii i q coloane. S se creeze o nou matrice b, din matricea a, exceptnd liniile i coloanele la intersecia crora se afl elemente nule.Se vor utiliza doi vectori n care se vor marca liniile, respectiv coloanele care nu vor apare n b. 7. Se consider o matrice A cu p linii i q coloane, de elemente reale. S se creeze pe baza acesteia o nou matrice B avnd m coloane cu elementele pozitive din A i un vector C cu elementele negative din matricea A. 8. Se d o matrice A ptrat, cu n linii i n coloane. S se fac schimbrile de linii i de coloane astfel nct elementele diagonalei principale s fie ordonate cresctor. 9. S se calculeze coeficieni polinomului Cebev de ordinul n, pornind de la relaia de recuren Tk(x) = 2xTk-1(x) Tk-2(x), k > 2 T0(x) = 1, T1(x) = x obinnd n prealabil relaii de recuren pentru coeficieni. 10. x y =
T

a) S se defineasc o funcie care calculeaz produsul scalar a doi vectori, adic:


n 1 i=0

yi

b) S se defineasc o procedur care calculeaz produsul diadic a doi vectori: x0 y0 x y 1 0 = x n 1 y0 x0 y1 x 1 y1 xn 1y1 x0y n 1 x1 y n 1 x n 1y n 1

xy

c) S se scrie un program care citete: un numr ntreg n ( n <= 10 ), o matrice ptrat A cu n linii i coloane i doi vectori u i v cu cte n componente i calculeaz matricea B, n care: B = A - u.v'/u'.v 11. S se scrie un program care citete un numr ntreg n i o matrice ptrat A cu n linii i coloane i afieaz numerele liniilor avnd n prima poziie elementul minim i n ultima poziie - elementul maxim din linie. Se vor afia de asemenea numerele coloanelor avnd n prima poziie elementul maxim i n ultima elementul minim. 12. S se realizeze un program care simuleaz jocul "viaa", adic traseaz populaia unei comuniti de organisme vii, prin generarea de nateri i mori timp de G generaii. Comunitatea de organisme este descris printr-o matrice cu N linii i N coloane, fiecare element reprezentnd o celul care poate fi vid sau poate conine un organism. Fiecare celul din reea, exceptndu-le pe cele de la periferie are 8 vecini. Naterile i morile de organisme se produc simultan la nceputul unei noi generaii. Legile genetice care guverneaz creterea i descreterea populaiei sunt:

10

Valeriu Iorga

Programare n C / C++

fiecare celul vid care este adiacent la 3 celule ocupate va da natere n urmtoarea generaie la un organism

fiecare celul care conine un organism ce are numai un vecin sau niciunul,va muri la nceputul generaiei urmtoare(datorit izolrii) orice organism dintr-o celul cu patru sau mai muli vecini n generaia prezent va muri la nceputul generaiei urmtoare(datorit suprapopulaiei). 13. S se scrie n C:

O funcie care verific dac dou linii date i i j dintr-o matrice ptrat (nxn) sunt identice sau nu. O funcie care afieaz numerele liniilor i coloanelor dintr-o matrice ptrat, unde se afl elemente nule (zero). Un program care citete o matrice ptrat cu maxim 30 de linii i coloane de numere ntregi, verific dac exist sau nu 2 linii identice n aceast matrice, folosind funcia de la punctul a). Dac toate liniile sunt distincte, atunci se afieaz poziia tuturor elementelor nule din matrice, folosind funcia de la punctul b)

14. S se nmuleasc dou matrici utiliznd o funcie pentru calculul produsului scalar a doi vectori. 15. Se d o matrice A avnd L linii i C coloane (L,C 10, C>3) de elemente ntregi. S se afieze liniile n care exist cel puin trei elemente avnd minim cinci divizori nebanali. Se va defini i utiliza o funcie care stabilete ci divizori nebanali are un numr dat. 16. S se defineasc o funcie care calculeaz diferena ntre elementul maxim i elementul minim ale unei linii date dintr-o matrice.

S se scrie un program care citeste: numerele naturale l i c (l,c 10), valoarea real eps i matricea A avnd l x c elemente i afieaz liniile din matrice care au diferena ntre extreme inferioar valorii eps.

17. Intr-o matrice dat A cu L linii i C coloane s se permute circular dreapta fiecare linie i cu i pozitii. Se va utiliza o funcie care permut circular dreapta cu o poziie componentele unui vector. 18. Pentru o matrice dat A cu L linii i C coloane s se afieze toate cuplurile (i,j) reprezentnd numere de linii avnd elementele respectiv egale. Se va defini i utiliza o funcie care stabilete dac doi vectori sunt sau nu egali. 19. Se dau dou matrici A i B avnd n linii i coloane fiecare. S se stabileasc dac una dintre ele este sau nu inversa celeilalte. Se va defini i utiliza o funcie pentru a nmuli dou matrici. 20. Un punct a ntr-o matrice este un element maxim pe coloan i minim pe linia pe care se afl sau minim pe coloan i maxim pe linia sa.Utiliznd funcii care verific dac un element este minim/maxim pe linia/coloana sa s se determine punctele n a dintr-o matrice cu elemente distincte. 21. Doi vectori x i y cu cite n componente fiecare, (n <= 20) se afl n relaia dac xi <= yi ,pentru i:=0..n-1 x <= y

S se defineasc o funcie care primind ca parametri dou linii i i k ale unei matrici, stabilete dac acestea se afl n relaia <=. S se defineasc o funcie care, primind ca parametri numerele a dou linii dintr-o matrice calculeaz diferena lor, depunnd rezultatul ntr-un vector.

11

Valeriu Iorga

Programare n C / C++

S se scrie un program care citete un numr ntreg n (n <= 20) i o matrice cu n linii i coloane i afieaz pentru toate perechile de linii care nu se gsesc n relatia <= diferena lor.

22. S se defineasc o funcie care stabilete dac o linie specificat a unei matrici este sau nu o secven ordonat cresctor.

S se defineasc o funcie care, pentru o linie specificat a unei matrici determin elementul minim i elementul maxim din acea linie. Se citete o matrice ptrat A cu n linii i coloane (n <= 10). S se afieze pentru fiecare linie, care nu reprezint un ir de valori cresctoare: numrul liniei, elementul maxim i elementul minim. Indicaie: O linie i dintr-o matrice reprezint o secven ordonat cresctor dac: AI,j <= AI,j+1 pentru j:= 1..n-1. S se defineasc o funcie care stabilete dac doi vectori dai ca parametri sunt sau nu ortogonali. S se scrie un program care citete o matrice ptrat cu n linii i coloane i stabilete dac matricea este sau nu ortogonal pe linii, i n caz afirmativ calculeaz matricea invers. Se tie c pentru o matrice ortogonal, matricea invers se obine transpunnd matricea dat i imprind fiecare coloan cu norma euclidian a ei (radicalul produsului scalar al coloanei cu ea nsi). O matrice este ortogonal, dac oricare dou linii diferite sunt ortogonale.

23.

12