<<Pagina Materiale

 
 
 Functii cu parametri 
Definitia unei functii

Mai jos se reiau aspectele generale despre functii, prezentate deja la Functii fara parametri, detaliindu-se aspectele legate de functiile cu parametri, care returneaza o valoare.

Functia este un concept important in matematica si programare. In limbajul C prelucrarile sunt organizate ca o ierarhie de apeluri de functii. Orice program trebuie sa contina cel putin o functie, functia main.

Functiile incapsuleaza prelucrari bine precizate si pot fi reutilizate in mai multe programe.

Pentru a putea fi utilizata intr-un program, o functie trebuie sa fie definita ( sau declarata ) si apelata.

Definitia unei functii are urmatoarea forma:
 

tip_rezultat_returnat nume_functie (lista_parametri_formali){  /*antetul functiei*/
     definirea variabilelor locale
     prelucrari /* instructiuni */
/* intre { } corpul functiei */ 

Functiile nu pot fi definite incuibat ( ca in Pascal ).

Daca tip_rezultat_returnat este:

  • int - functia este intreaga
  • void - functia este void
  • float - functia este reala.
Lista parametrilor formali cuprinde declaratia parametrilor formali, separati prin virgula:
 
lista_parametri_formali=tip_p1 nume_p1, tip_p2 nume_p2, ..., tip_pn nume_pn

Parametrii formali sunt vizibili doar in corpul functiei care ii defineste. O functie poate deci prelucra variabilele globale, cele locale, precum si parametrii formali.

Pentru reutilizare si pentru a nu modifica accidental variabilele globale, este indicat ca o functie sa nu acceseze variabilele globale.

Daca functia nu returneaza nici un rezultat si nu primeste parametri, definitia va fi:
 

void nume_functie (void)  /*antetul functiei*/
     definirea variabilelor locale
     prelucrari /* instructiuni */
/* intre { } corpul functiei */ 

O functie void fara parametri poate prelucra variabilele globale si cele locale.

Declaratia unei functii se face prin precizarea prototipului functiei:
 

 antet;

In prototip, numele parametrilor formali pot fi omisi, aparand doar tipul fiecaruia.

Prototipul implicit este:

int nume_functie(void);
Sus
Apelul unei functii
     
    nume_functie(lista_parametri_actuali)/* poate
       apare ca operand intr-o expresie, daca 
       functia returneaza un rezultat */
La apelul unei functii, se executa corpul sau, dupa care se revine in functia apelanta, la instructiunea urmatoare apelului.
O functie poate fi apelata, daca in fata apelului exista definitia sau cel putin declaratia functiei.

Parametrii actuali sunt expresii, care trebuie sa corespunda ca numar si tipuri ( eventual prin conversie implicita ) cu parametrii formali. Parametrii actuali sunt transmisi prin valoare, la apelul functiei ( valorile lor sunt depuse pe stiva ). Modificarea valorii lor de catre functie nu este vizibila in exterior.

La apelul unei functii, pe stiva se creaza o inregistrare de activare, care cuprinde, de jos in sus:

  • adresa de revenire din functie
  • valorile parametrilor formali
  • variabilele locale.
In cazul functiilor void fara parametri, apelul se face prin:
     nume_functie();//instructiune expresie
Revenirea dintr-o functie se face la intalnirea instructiunii return, sau la terminarea executiei corpului functiei ( ultimul caz, ca functia sa nu contina instructiunea return, poate apare doar in cazul functiilor void - care nu returneaza nici un rezultat ).

Corpul unei functii poate contine una sau mai multe instructiuni return:
    return; //daca functia e void
    return expresie;  //expresia e de acelasi tip cu tip_rezultat ( eventual prin conversie implicita )

Sus
Transmiterea parametrilor

Transmiterea parametrilor se face prin valoare -  valorile parametrilor actuali sunt depuse pe stiva, la apelul unei functii, fiind prelucrate ca parametri formali de catre functie; modificarea parametrilor formali nu afecteaza deci parametrii actuali.

Daca se doreste ca o functie sa modifice valoarea unei variabile, trebuie sa i se transmita pointerul la variabila respectiva - vezi programul 2 care interschimba valorile a doua variabile.

Daca parametrul este un tablou, cum numele este echivalent cu pointerul la tablou, functia poate modifica valorile elementelor tabloului, primind adresa lui - vezi programele 3 si 4, unde apar ca parametri tablouri uni si bidimensionale. A se observa ca trebuie sa se transmita ca parametri si dimensiunea/dimensiunilor tabloului/matricii. 

Daca parametrul este sir de caractere, dimensiunea tabloului de caractere nu trebuie sa se transmita, sfarsitul sirului fiind indicat de caracterul terminator '\0' - vezi exemplul 5.
 

Parametru actual
Parametru formal
&nume_variabila tip_variabila * nume_param
nume_tab_unidim // forme echivalente
&nume_tab_unidim
&nume_tab_unidim[0]
tip_baza * nume_param // forme echivalente
tip_baza nume_param[]
tip_baza nume_param[dim] 
nume_tab_bidim // forme echivalente
&nume_tab_bidim
&nume_tab_bidim[0]
tip_baza nume_param[][dim2] //dim2 trebuie sa apara
tip_baza nume_param[dim1][dim2] 
Sus
Exemple

1.Sa se calculeze si sa se afiseze valoarea expresiei xm+yn+(xy)m^n , x,y,m,n fiind cititi de la tastatura, astfel incat intregii m,n sa fie pozitivi. Ridicarea la putere se va realiza de o functie putere care primeste baza si exponentul ca parametri si returneaza rezultatul. A se observa faptul ca apelul functiei putere ( analog pow ) apare intr-o expresie si de asemenea ca parametru actual intr-un apel.
 

#include <stdio.h>
#include <math.h>

int intreg_poz(char *nume_var); // citeste cu validare un intreg 
                                                                //pozitiv cu numele transmis ca param
double putere (double baza, int exp); // calculeaza baza^exp

void main(void){
  int m,n;
  double x,y;

  m=intreg_poz("m");
  n=intreg_poz("n");
  if(m==0 && n==0){ //semnalare eroare 0^0
    puts("0^0 imposibil");
    return; // din main
  }
  printf("valorile lui x,y:"); scanf("%lf%lf",&x,&y);

  printf("%lf^%d+%lf^%d+(%lf*%lf)^%d^%d ( cu putere ):%lf\n",
         x,m,y,n,x,y,m,n,putere(x,m)+putere(y,n)
         +putere(x*y,putere(m,n)));
  printf("rezultat ( cu pow ):%lf\n",pow(x,m)+pow(y,n)
         +pow(x*y,pow(m,n)));  //se tipareste si rezultatul obtinut
        // cu functia pow de biblioteca, pentru verificare
  getche();

} // main 

int intreg_poz(char * nume_var){
  int aux;
  while(printf("%s(>=0):",nume_var),scanf("%d",&aux),aux<0);
  return aux;
} // intreg_poz

double putere (double baza, int exp){
  int i; float rez;
  for(i=rez=1;i<=exp;i++)rez*=baza;
  return rez;
} // putere

Folosind functia putere scrieti programul care citeste N intregi ( N variabil, intre 2 si Max ) si calculeaza i1^i2^i3^...^iN. Atentie la depasiri! Ce modificari trebuie operate asupra tipurilor pentru ca rezultatul sa fie corect? 
Observatie: intregii vor fi cititi intr-un tablou de dimensiune Max. 

2.Programul de mai jos prezinta o varianta incorecta si una corecta de interschimbare a doua variabile de catre o functie.
 

#include <stdio.h>
#include <conio.h>

void intersch_er(int x,int y){ //functia primeste valorile de interschimbat
  int t=x;
  x=y;
  y=t;
}

void intersch_ok(int* px,int* py){ //functia primeste pointerii la 
                                   //variabilele de interschimbat
  int t=*px;
  *px=*py;
  *py=t;
}

int citire(char * nume){
  int aux;
  printf("%s=",nume);
  scanf("%d",&aux);
  return aux;
}

void main(void){
  int a,b;

  clrscr();

  a=citire("a");
  b=citire("b");

  intersch_er(a,b);
  printf("dupa prima functie:a=%d,b=%d\n",a,b);
  intersch_ok(&a,&b);
  printf("dupa a doua functie:a=%d,b=%d\n",a,b);

  getche();
}

3.Se citesc si se tiparesc elementele a trei tablouri de intregi, de dimensiuni diferite. Citirea elementelor unui tablou se face pana la tastarea lui CTRL/Z sau pana la introducerea numarului maxim de elemente. A se observa ca aceeasi functie de citire, respectiv tiparire poate citi/scrie tablouri de dimensiuni diferite, care au insa acelasi tip de baza. Functiile trebuie sa primeasca insa dimensiunile tablourilor.
 

#include <stdio.h>

void cit(int * tab,int dm,int * dc,char * nume){ 
  // functia primeste adresa tabloului, numarul de maxim de elemente, adresa variabilei
  // ce va contine numarul de elemente citite si numele tabloului
  // primul parametru formal poate fi definit echivalent: 
  // int t[10] - constanta fara efect, sau
  // int t[]
  int i;
  printf("Tastati elementele tabloului %s (max %d sau terminati cu CTRL/Z):\n", 
          nume,dm);
  for(i=0;i<dm;i++)
    if(scanf("%d",&tab[i])==EOF)break;
  *dc=i; // numarul de elemente citite
}

void tip(int * tab,int dc,char * nume){ // functia primeste adresa tabloului, numarul de 
                                        // elemente citite si numele tabloului
  int i;
  printf("Elementele tabloului %s\n",nume);
  for(i=0;i<dc;i++)
    printf("%d ",tab[i]);
  putchar('\n');
}

void main(void){
  int t1[2],t2[30],t3[40],d1,d2,d3; // tablouri si numerele de elemente citite

  cit(t1,2,&d1,"t1");
  cit(t2,30,&d2,"t2");
  cit(t3,40,&d3,"t3");

  tip(t1,d1,"t1");
  tip(t2,d2,"t2");
  tip(t3,d3,"t3");

  getche();
}

Adaugati cate o functie pentru fiecare din prelucrarile: 

  • returneaza valoarea maximului unui tablou, primit ca parametru 
  • primeste un intreg, interpretat ca indice in tabloul primit ca parametru; functia va aduna la elementul de la acel indice, toate elementele anterioare, daca indicele este valid, returnand 1, altfel 0 
  • aduna doua tablouri ( pe lungimea minima dintre dimensiunile lor ) intr-un al treilea; tablourile si dimensiunea sunt parametri. 
4. Se tiparesc elementele a doua matrici de intregi,  cu acelasi numar de coloane.
 
#include <stdio.h>
#include <conio.h>

void tip(int t[][10],int nl, int nc,char *nume){//functia primeste numarul
         // de linii si coloane initializate
         // la parametrul t, a doua dimensiune trebuie neaparat precizata
         // t poate fi declarat echivalent int t[dim1][10] - dim1, expr cta
         // nu se ia in considerare
  int i,j;
  printf("Elementele matricii %s:\n",nume);
  for(i=0;i<nl;i++){
    for (j=0;j<nc;j++)
    printf("%d ",t[i][j]);
  putchar('\n'); 
  } // for i
}

void main(void){
  int t1[40][10]={{4,5},{3,4}},t2[50][10]={{9,15,8},{13,99,14}};
  tip(t1,2,2,"t1");
  tip(t2,2,3,"t2");
  getchar();
}

Adaugati cate o functie pentru fiecare din prelucrarile: 

  • citeste o matrice 
  • returneaza suma elementelor unei matrici 
  • insumeaza doua matrici intr-o a treia 
  • inmulteste doua matrici intr-o a treia. 
5.Functia intreaga de mai jos transforma minusculele din sirul primit ca parametru in majuscule si returneaza numarul de modificari operate. Sunt date doua variante echivalente: in prima accesul la caracterele sirului se face indexat, la a doua, prin indirectare.
 
int prel_sir(char * s){
  int i,nr;
  for(i=nr=0;i<strlen(s);i++)
    if((c=toupper(s[i]))!=s[i]){
      s[i]=c;
      nr++;
    }
  return nr;
int prel_sir(char * s){
  int i,nr;
  for(nr=0;*s;s++)//se marcheaza diferentele fata de prima varianta
    if((c=toupper(*s))!=*s){
      *s=c;
      nr++;
    }
  return nr;
Sus
<<Pagina Materiale


Copyright © 2001-2002. Carmen Holotescu
All rights reserved. Published by Timsoft