Capitolul 4.4. Variabile externe

Vezi subiectul anterior Vezi subiectul urmator In jos

Capitolul 4.4. Variabile externe

Mesaj  zooky la data de Mier Mar 18, 2009 12:19 pm

Un program C consta dintr-o multime de obiecte externe, care sint functii sau variabile. Adjectivul "extern" este folosit in primul rind in contrast cu "intern", care descrie argumentele si variabilele automate definite in interiorul functiilor.
Variabilele externe sint definite in afara oricarei functii si sint astfel disponibile potential pentru mai multe functii.
Functiile insesi sint intodeauna externe, deoarece limbajul C nu permite definitii de functii in interiorul altor functii. Implicit variabilele externe sint deasemenea "globale", astfel incit toate referintele la o astfel de variabila printr-un acelasi nume (chiar si pentru functiile compilate separat) sint referinte la un acelasi lucru. In acest sens, varaiabilele externe sint analoage cu COMMON din FORTRAN si cu EXTERNAL din PL/1.
Vom vedea mai incolo cum se pot defini variabile si functii externe care nu sint global disponibile ci sint vizibile ,in in schimb, doar intr-un singur fisier sursa. Deoarece variabilele externe sint global accesibile, ele ofera o alternativa la argumente de functii si valori returnate pentru comunicari de date intre functii. Orice functie poate accede o variabila externa prin referirea numelui ei, daca numele a fost declarat undeva sau cumva.
Daca un numar mare de variabile trebuie sa fie partajat folosite de mai multe functii, variabilele externe sint mai convenabile si mai eficiente decit listele lungi de argumente.
Asa cum am precizat in capitolul 1, aceasta modalitate trebuie, totusi, utilizata cu grija, deoarece ea poate avea efecte negative asupra structurii programului si poate conduce la programe cu multe conexiuni de date intre functii.
Un al doilea motiv pentru folosirea variabilelor externe priveste initializarea. In particular, tablourile externe pot fi initializate dar tablourile automate nu pot. Vom trata initializarea aproape de sfirsitul acestui capitol.
Al treilea motiv pentru folosirea varaiabilelor externe este domeniul si timpul lor de viata. Variabilele autmate sint interne unei functii; ele capata viata atunci cind rutina este introdusa si dispar atunci cind rutina se termina. Variabilele externe, pe de alta parte, sint permanente. Ele nu vin si pleaca, asa ca ele retin valorile de la un apel de functie la altul. Deci, daca doua functii trebuie sa-si partajeze niste date, chiar nefolosite de alte functii niciodata, este adesea mai convenabil daca datele partajabile sint pastrate in variabile externe decit trimise via argumente.
Sa examinam aceasta chestiune mai departe cu un exemplu mai mare. Problema consta in a scrie un alt program calculator, mai bun decit cel anterior. Aceasta va permite +,-,*,/ si = (pentru a tipari rezultatul). Deoarece este intrucitva mai usor de implementat, calculatorul va folosi notatia poloneza inversa in locul celei "infix". (Notatia poloneza este schema folosita, de exemplu, de calculatoarele de buzunar Hewlett-Packard) In notatia poloneza inversa, fiecare operator isi urmeaza operanzii;
o expresie "infix", de tipul:

(1 - 2) * (4 + 5) =

se introduce astfel:

1 2 - 4 5 + * =

Parantezele nu sint necesare.

Implementarea este aproape simpla. Fiecare operand este depus intr-o stiva. Cind soseste un operator, numarul de operanzi (doi pentru operatorii liniari) sint scosi din stiva si li se aplica operatorul iar rezultatul este depus din nou in stiva. In exemplul de mai sus, 1 si 2 sint depusi in stiva, apoi sint inlocuiti de diferenta lor, -1 . Apoi 4 si 5 sint depusi in stiva, apoi sint inlocuiti de suma lor ,9. Produsul lui -1 cu 9, ii inlocuieste apoi in stiva. Operatorul = tipareste elementul din virful stivei fara a-l distruge (se pot face astfel verificari intermediare).
Operatiile de introducere si extragere din stiva sint triviale dar, daca se adauga detectia de erori de timp si recuperarea lor, codurile sint suficient de lungi pentru a fi mai bine sa le punem in functii separate decit sa repetam codul de-a ungul intregului program. La fel, vom considera o functie separata pentru aducerea urmatorului operand sau operator de la intrare. Astfel, structura programului este

while (urmatorul operator sau operand nu este sfirsitul de fisier)
if (numar)
pune-l in stiva
else if (operator)
scoate operanzii din stiva
executa operatia
extrage rezultatul
else
eroare

Decizia principala de proiectare care nu a fost inca discutata este asupra locului stivei, adica ce rutina o poate accede direct. O posibilitate este aceea de a o tine in main si sa trecem stiva si pozitia ei curenta rutinelor care o folosesc pentru introducere si extragere de date. Dar main nu are nevoie sa stie despre variabilele care controleaza stiva; ea va trebui sa gindeasca numai in termeni de introducere si extragere in/din stiva. Asa ca am decis sa facem stiva si informatiile asociate ei drept variabile externe accesibile functiilor de introducere si extractie, dar nu si lui main.

Traducerea acestei schite in cod este destul de simpla.
Programul principal este in primul rind un mare comutator dupa tipul operatorului sau al operandului; aceasta este probabil cea mai tipica folosire a lui switch pe care am descris-o in Capitolul 3.

#define MAXOP 20 /* marime maxima operand, operator */
#define NUMBER '0' /* semnul pentru numar gasit */
#define TOOBIG '9' /* semnal pentru sir prea lung */
main() /* calculator de birou cu sirul Polonez invers */
{
int type ;
char s[MAXOP];
double op2, atof(), pop(), push();
while ((type = getop(s, MAXOP)) != EOF)
switch (type) {
case NUMBER:
push(atof(s));
break;
case '+':
push(pop() + pop());
break;
case '*':
push(pop() * pop());
break;
case '-' :
op2=pop();
push(pop() - op2);
break;
case '/' :
op2=pop();
if (op2 != 0.0)
push(pop() / op2)
else
printf("impartire cu zero \n");
break;
case '=':
printf("\t%f\n", push(pop()));
break;
case 'c':
clear();
break;
case TOOBIG:
printf("%.20s ... e prea lung \n",s);
break;
default:
prinf(" comanda necunoscuta %c\n", type);
break;
}
}
#define MAXVAL 100 /* marimea stivei */
int sp = 0; /* pointerul de stiva */
double val[MAXVAL]; /* stiva */
double push(f) /* depune pe f in stiva */
double f ;
{
if(sp < MAXVAL)
return(val[sp++] = f);
else {
printf("eroare: stiva plina\n");
clear();
return(0);
}
}
double pop() /* extrage elementul din virful stivei */
{
if (sp > 0)
return(val[--sp]);
else {
printf("eroare: stiva goala\n");
clear();
return(0);
}
}
clear() /* curata stiva */
{
sp = 0 ;
}

Comanda c curata stiva cu ajutorul functiei clear care este folosita deasemenea si de catre functiile pop si push in caz de eroare. Ne vom intoarce imediat la getop.
Asa cum am aratat in Capitolul 1, o variabila este externa daca este definita in afara corpului oricarei functii. Astfel stiva si pointerul de stiva care trebuiesc partajate de catre push, pop si clear sint definite in afara acestor trei functii. Dar main insusi nu refera stiva sau pointerul de stiva ( reprezentarea este ascunsa cu grija). Astfel, codul pentru operatorul = trebuie sa se foloseasca

push(pop()));

pentru a examina virful stivei fara a-l distruge.
Sa notam deasemenea ca deoarece + si * sint operatori comutativi, orinea in care se combina operanzii scosi din stiva este irelevanta, dar pentru operatorii - si / trebuie sa distingem intre operanzii sting si drept.

Exercitiul 4.3. Dat scheletul de baza, este usor sa extindem programul calculator. Adaugati procentul % si operatorul unar -. Adaugati o comanda de stergere, care sterge elementul din virful stivei. Adaugati comenzi pentru minuirea de variabile (este usor in cazul variabilelor formate dintr-o singura litera (26)).
avatar
zooky
Moderator
Moderator

Numarul mesajelor : 147
Data de inscriere : 15/03/2009
Varsta : 24
Localizare : Cernatesti City

Vezi profilul utilizatorului http://e-learning.forumhit.ro

Sus In jos

Vezi subiectul anterior Vezi subiectul urmator Sus


 
Permisiunile acestui forum:
Nu puteti raspunde la subiectele acestui forum