POINTERI CA ARGUMENTE LA FUNCTII. APEL PRIN REFERINTA
Am precizat in capitolul precedent ca la apelul prin valoare functia apelata prelucreaza o copie a valorilor parametrilor, valori care au fost puse pe stiva. Inseamna ca functia apelata are efect asupre functiei apelante doar printr-o singura valoare returnata. Dar ce posibilitati are programatorul cand doreste ca functia apelata sa modifice mai multe variabile din functie apelanta? I 515c24f n aceste situatii programatorul va transmite functiei apelate adresele variabilelor ce urmeaza sa fie modificate. Avand la dispozitie aceste adrese, functia apelata va putea lucra direct asupra valorilor aflate la aceste adrese. Deci programul apelant va trebui sa transmita functiei apelate pointeri catre variabilele ce vor fi modificate. Urmeaza ca parametrii formali ai functiei apelate vor fi declarati ca pointeri.
Acest tip de apel de functie se numeste apel prin referinta sau prin adresa (in engleza: call by adress).
Exemplu 5.6.1.
Mai jos sunt doua variante pentru o functie care interschimba doua numere intregi.
/* Varianta 1 */ /* Varianta 2 */
void swap (int x, int y) void swap (int px, int py)
}
/* Gresit */ /* Corect */
Functia din varianta 1 (apel prin valoare) este gresita, deoarece se interschimba intre ele variabilele x si y locale functiei swap si nu parametrii efectivi de la apel, asa cum ar dori programatorul.
Functia din varinta 2 lucreaza direct cu variabilele de interschimbat din functia apelanta,intrucat are ca parametrii formali pointeri la acestea.O modalitate de apel ar fi:
swap (&x, &y );
ceea ce constituie de fapt apelul prin referinta . Doar in acest fel x si y sunt efectiv interschimbate intre ele.
Exemplul 5.6.2.
Calculul lungimii unui sir de caractere terminat cu ' \ O ' in varianta cu pointeri (vezi si : Exemplul 4.4.10.) este :
unsigned strlen (char * a)
OBSERVATIE
Instructiunea while ( * b! = ' O ') se putea scrie mai concis: while (* b ), deoarece expresiile : *b ! = ' \ O ' , respectiv * b sunt sau ambele adevarate, sau ambele false.
Exemplul 5.6.3.
In exemplul 4.4.12. s-a prezentat o functie care copie sirul s ( sursa) in sirul d (destinatie). Iata varianta cu pointeri .
void strepy (char * d, char * s)
}
Expresiile cu pointeri ne permit o scriere mult mai compacta :
void strcpy (char * d, char * s)
OBSERVATIE
Instructiunea: while ( * d++ = * s++); cuprinde urmatoarele operatii:
-la adresa curenta data de pointerul d atribuie caracterul curent aflat la adresa data de pointerul s;
-incrementeaza l atat la d, cat si la s ( se trece la caracterul urmator);
-daca ultimul caracter atribuit este = ' \ O ' atunci repeta observatiile de mai sus; altfel iese din
ciclul while.
In concluzie , cele trei operatii de la prima varianta :
* d = * s;
s++; si d++;
* d ! = ' \ O ' ?
se executa intr-a doua varianta cu o singura instructiune.
Exemplul 5.6.4.
In exemplul 4.4.11. se compara lexicografic doua siruri de caractere a cu b.Comparati varianta de acolo cu varianta cu pointeri de mai jos :
int stremp (char *a, char * b )
/* treci la caracterul urmator . */
/* Daca s-a ajuns la sfarsitul */
/* lui a si cum *a = = *b */
/* inseamna ca sirurile sunt */
/* egale si returneaza 0 */
/* Daca *a ! = *b atunci retur- */
/* neaza *a - *b (dif. carecte- */
/* relor curente). Daca diferenta*/
/* este negativa, atunci a < b, */
/* altfel a > b */
Exemplu 5.6.5.
Functia urmatoare utilizeaza pointerii pentru a sorta crescator un sir de numere prin metoda bulelor (vezi [ ] pag.).
void sortbule ( float *a, unsigned n )
m =
}
}
Prin
aceasta metoda sirul a [ 0 ] , a [ 1 ] , ., a [ n - 1 ] se parcurge de la
inceput spre dreapta, astfel incat daca a [ i ] > a [ i + 1 ] atunci se face
interschimbarea lui a [ i] cu a [ i + 1]
. Indicele i pentru care s-a facut interschimbarea se retine in ind care il va
schimba pe m. Intrucat de la ultimul indice i retinut in ind si pana la
sfarsitul sirului este ordonat crescator la urmatoarea parcurgere se analizeaza
sirul doar pana la ultimul indice ind minus l . Se continua astfel pana nu se
mai fac interschimbari (
Exemplul 5.6.6.
Functia urmatoare sorteaza crescator un sir de numere utilizand metoda insertiei directe ( vezi [ ] pag.). In ce consta metoda ?
Se presupune ca subsirul:
a[0], a[1],.,a[i-1] este deja ordonat crescator si se cauta locul lui a[i] in acest sir. Cautarea se face spre stanga, adica de la i - 1 spre 0. Daca j este indicele pentru care (j = -1, i; a[-1] = -
a[ j ] a[ i ] < a [ j + 1] atunci toate elementele a [ j + 1], a [j + 2],.,a[ i - 1] se deplaseaza la dreapta cu o pozitie, iar in pozitia j + 1 devenita libera se insereaza elementul a [ i ]. Se aplica procedeul de mai sus pentru i de la 1 la n - 1 si astfel sirul este ordonat crescator.
void sortinsdir (float * a, unsigned n)
/* a [ j + 1 ] vine a [ i ] */
*a = temp; /* Locul lui a [ i ] este cel mai */
/* din stanga */
sf : ; /* Instructiune vida etichetata */
}
}
Exemplu 5.6.7.
O alta metoda de sortare este metoda Shell (vezi [ ] pag. ) cea prezentata in functia de mai jos. Principiul metodei :
- se fixeaza un pas ; la inceput n/2 ;
- se sorteaza subsirurile avand elementele aflate la distanta pas intre ele :
a [ 0] cu a [pas] , a [1] cu a [pas+1],.
- se injumatateste pasul ; pas=pas/2 si se sorteaza subsirurile :
a [0] , a [pas], a [2 * pas],.
a [1] , a [pas + 1], a [2 * pas + 1],. s.a.m.d.
- cand pas = 0 algoritmul se termina : sirul este ordonat crescator.
Subsirurile se ordoneaza prin metoda insertiei directe prezentata anterior.
Metoda are avantajul ca aranjeaza inca de la inceput elementele aflate departe de locul lor final. Astfel, in etapele urmatoare (cu pasul injumatatit) ramane mai putin de facut.
Void sort Shell (float *a, unsigned n)
}
pas = pas/2 ; /* Injumatatirea pasului. Cand */
} /* acesta devine 0 programul */
} /* se termina */
Observatie
Daca ar fi sa facem o comparatie intre cele trei metode de sortare prezentate anterior, cea mai rapida este metoda Shell, urmeaza metoda insertiei directe si ultima, mai putin rapida, este metoda bulelor.
|