Funcţii.

1. Apelarea funcţiilor.
In C noţiunea de funcţie este esenţială, deoarece asigură un mecanism de abstractizare a controlului:
rezolvarea unei părţi a problemei poate fi încredinţată unei funcţii, moment în care suntem preocupaţi de ce
face funcţia, fără a intra în detalii privind cum face funcţia anumite operaţii. Însăşi programul principal este o
funcţie cu numele main(), iar programul C este reprezentat de o mulţime de definiri de variabile şi de funcţii.
Funcţiile pot fi clasificate în:
• funcţii care întorc un rezultat
• funcţii care nu întorc nici un rezultat (similare procedurilor din Pascal).
Apelul (referirea sau utilizarea) unei funcţii se face prin:
nume_funcţie (listă_parametri_efectivi)
Acesta poate apare ca o instrucţiune, în cazul funcţiilor care nu întorc un rezultat:
nume_funcţie (listă_parametri_efectivi);
De exemplu:
printf(“x=%5.2lf\n”,x);
mesaj();
Pentru funcţiile care întorc un rezultat apelul de funcţie poate apare ca operand într-o expresie.
De exemplu:
y=sin(x);
nr_zile=bisect(an)+365;
Se remarcă faptul că lista de argumente (sau de parametri efectivi) poate fi vidă.
Funcţiile comunică între ele prin lista de argumente şi prin valorile întoarse de funcţii. Comunicarea
poate fi realizată şi prin variabilele externe, definite în afara tuturor funcţiilor.
Exemplul 11: O fracţie este cunoscută prin numărătorul x şi numitorul y, valori întregi fără semn. Să
se simplifice această fracţie.
Simplificarea se va face prin cel mai mare divizor comun al numerelor x şi y. Vom utiliza o funcţie
având ca parametri cele două numere, care întoarce ca rezultat , cel mai mare divizor comun a lor. Funcţia
main() apelează funcţia cmmdc() transmiţându-i ca argumente pe x şi y. Funcţia cmmdc() întoarce ca
rezultat funcţiei main(), valoarea celui mai mare divizor comun. Programul, în care vom ignora deocamdată
definirea funcţiei cmmdc(), este:
#include <stdio.h>
void main(void)
{ unsigned long x, y, z;
scanf(“%lu%lu”, &x, &y);
printf(“%lu / %lu =”, x, y);
z=cmmdc(x,y);
x/=z;
y/=z;
printf(“%lu / %lu\n”, x, y);
}
2. Definiţii de funcţii.
În utilizarea curentă, o funcţie trebuie să fie definită înainte de a fi apelată. Aceasta impune o definire
a funcţiilor programului în ordinea sortării topologice a acestora: astfel mai întâi se vor defini funcţiile care nu
apelează alte funcţii, apoi funcţiile care apelează funcţii deja definite. Este posibil să eliminăm această
restricţie, lucru pe care îl vom trata ulterior.
O funcţie se defineşte prin antetul şi corpul funcţiei.
Funcţiile nu pot fi incluse unele în altele; toate funcţiile se declară pe acelaşi nivel cu funcţia main.
In versiunile mai vechi ale limbajului, în antetul funcţiei parametrii sunt numai enumeraţi, urmând a fi
declaraţi ulterior. Lista de parametri, în acest caz, este o enumerare de identificatori separaţi prin virgule.
tip_rezultat nume_functie( lista_de_parametri_formali )
{ declarare_parametri_formali;
alte_declaratii;
instructiuni;
}
In mod uzual parametrii funcţiei se declară în antetul acesteia. Declararea parametrilor se face printr-o
listă de declaraţii de parametri, cu elementele separate prin virgule.
tip_rezultat nume_functie( tip nume, tip nume,... )
{ declaratii;
instructiuni;
}
O funcţie este vizibilă din locul în care a fost declarată spre sfârşitul fişierului sursă (adică definiţia
funcţiei precede apelul).
Definirea funcţiei cmmdc() se face folosind algoritmul lui Euclid.
unsigned long cmmdc(unsigned long u, unsigned long v)
{ unsigned long r;
do {r=u%v;
u=v;
v=r;
} while (r);
return u;
}
In cazul în care apelul funcţiei precede definiţia, trebuie dat, la începutul textului sursă, un prototip al
funcţiei, care să anunţe că definiţia funcţiei va urma şi să furnizeze tipul rezultatului returnat de funcţie şi tipul
parametrilor, pentru a permite compilatorului să facă verificările necesare.
Prototipul unei funcţii are un format asemănător antetului funcţiei şi serveşte pentru a informa
compilatorul asupra:
• tipului valorii furnizate de funcţie;
• existenţa şi tipurile parametrilor funcţiei
Spre deosebire de un antet de funcţie, un prototip se termină prin ;
tip nume( lista tipurilor parametrilor formali);
Din prototip interesează numai tipurile parametrilor, nu şi numele acestora, motiv pentru care aceste
nume pot fi omise.
void f(void); /*functie fara parametri care nu intoarce nici un rezultat*/
int g(int x, long y[], double z);
int g(int, long[], double); /*aici s-au omis numele parametrilor*/
Dintre toate funcţiile prezente într-un program C prima funcţie lansată în execuţie este main(),
independent de poziţia pe care o ocupă în program.
Apelul unei funcţii g(), lansat din altă funcţie f() reprezintă un transfer al controlului din funcţia
f(), din punctul în care a fost lansat apelul, în funcţia g(). După terminarea funcţiei g() sau la întâlnirea
instrucţiunii return se revine în funcţia f() în punctul care urmează apelului g(). Pentru continuarea
calculelor în f(), la revenirea din g() este necesară salvarea stării variabilelor (contextului) din f() în
momentul transferului controlului. La revenire în f(), contextul memorat a lui f() va fi refăcut.
O funcţie apelată poate, la rândul ei, să apeleze altă funcţie; nu există nici o limitare privind numărul
de apeluri înlănţuite.
3. Comunicarea între funcţii prin variabile externe.
Efecte laterale ale funcţiilor.
Comunicarea între funcţii se poate face prin variabile externe tuturor funcţiilor; acestea îşi pot prelua
date şi pot depune rezultate în variabile externe. În exemplul cu simplificarea fracţiei vom folosi variabilele
externe a, b şi c . Funcţia cmmdc() calculează divizorul comun maxim dintre a şi b şi depune rezultatul
în c. Întrucât nu transmite date prin lista de parametri şi nu întoarce vreun rezultat, funcţia va avea prototipul
void cmmdc():
#include <stdio.h>
unsigned long a, b, c; // variabile externe
// definirea functiei cmmdc()
void main(void)
{ scanf(“%lu%lu”, &a, &b);
printf(“%lu / %lu = “, a, b);
cmmdc();
a/=c;
b/=c;
printf(“%lu / %lu\n”, a, b);
}
Definiţia funcţiei cmmdc()din Exemplul 11, este:
void cmmdc()
{ unsigned long r;
do {
r=a%b;
a=b;
b=r;
} while (r);
c=a;
}
Dacă se execută acest program, se constată un rezultat ciudat, şi anume, orice fracţie, prin simplificare
ar fi adusă la forma 1/0 ! Explicaţia constă în faptul că funcţia cmmdc() prezintă efecte laterale, şi anume
modifică valorile variabilelor externe a, b şi c; la ieşirea din funcţie a==c şi b==0, ceeace explică rezultatul.
Aşadar, un efect lateral (sau secundar),reprezintă modificarea de către funcţie a unor variabile externe.
În multe situaţii aceste efecte sunt nedorite, duc la apariţia unor erori greu de localizat, făcând
programele neclare, greu de urmărit, cu rezultate dependente de ordinea în care se aplică funcţiile care prezintă
efecte secundare. Astfel într-o expresie în care termenii sunt apeluri de funcţii, comutarea a doi termeni ar
putea conduce la rezultate diferite!
Vom corecta rezultatul, limitând efectele laterale prin interzicerea modificării variabilelor externe a şi
b, ceea ce presupune modificarea unor copii ale lor în funcţia cmmdc()sau din programul de apelare
void cmmdc(void)
{ unsigned long r, ca, cb;
ca=a;
cb=b;
do{
r=ca%cb;
ca=cb;
cb=r;
} while (r);
c=ca;
Singurul efect lateral permis în acest caz – modificarea lui c asigură transmiterea rezultatului către
funcţia apelantă.
Soluţia mai naturală şi mai puţin expusă erorilor se obţine realizând comunicaţia între funcţia
cmmdc() şi funcţia main() nu prin variabile externe, ci prin parametri, folosind o funcţie care întoarce ca
rezultat cmmdc.
Transmiterea parametrilor prin valoare, mecanism specific limbajului C, asigură păstrarea intactă a
parametrilor actuali x şi y, deşi parametrii formali corespunzători: u şi v se modifică! Parametrii actuali x şi y
sunt copiaţi în variabilele u şi v, astfel încât se modifică copiile lor nu şi x şi y.
In fişierul sursă funcţiile pot fi definite în orice ordine.Mai mult, programul se poate întinde în mai
multe fişiere sursă. Definirea unei funcţii nu poate fi totuşi partajată în mai multe fişiere.
O funcţie poate fi apelată într-un punct al fişierului sursă, dacă în prealabil a fost definită în acelaşi
fişier sursă, sau a fost anunţată.
Exemplul 12:
#include <stdio.h>
#include <conio.h>
unsigned long fact(unsigned char); // prototipul anunta functia
void main()
{ printf("5!=%ld\n", fact(5)); // apel functie
printf("10!=%ld\n", fact(10));
getch();
}
long fact(unsigned char n) // antet functie
{ long f=1; // corp functie
short i;
for (i=2; i<=n; i++)
f*=i;
return(f);
}
Tipurile funcţiilor pot fi:
• tipuri predefinite
• tipuri pointer
• tipul structură (înregistrare)
4. Funcţii care apelează alte funcţii.
Programul principal (funcţia main()) apelează alte funcţii, care la rândul lor pot apela alte funcţii.
Ordinea definiţiilor funcţiilor poate fi arbitrară, dacă se declară la începutul programului prototipurile
funcţiilor. In caz contrar definiţiile se dau într-o ordine în care nu sunt precedate de apeluri ale funcţiilor.
Exemplul 13: Pentru o valoare întreagă şi pozitivă n dată, să se genereze triunghiul lui Pascal, adică
combinările:
C
0
0
C
1
0
C
1
1
. . .
C
n
0
C
n
1
. . . C
n
n
Combinările vor fi calculate utilizând formula cu factoriale: C
n
p
=n!/p!/(n-p)!
#include <stdio.h>
unsigned long fact(int); /*prototip functie factorial*/
unsigned long comb(int,int); /*prototip functie combinari*/
void main(void) /*antet functie main*/
{ int k,j,n;
unsigned long C;
scanf(“%d”,&n);
for (k=0;k<=n;k++)
{ for (j=0;j<=k;j++)
printf(“%6lu “, comb(k,j));
printf(“\n”);
}
}
unsigned long comb(int n, int p) /*antet functie comb*/
{ return (fact(n)/fact(p)/fact(n-p));
}
/* functia fact a mai fost definita */
5. Programe cu mai multe fişiere sursă.
Pentru programele mari este mai comod ca acestea să fie constituite din mai multe fişiere sursă,
întrucât programul este conceput de mai mulţi programatori (echipă) şi fiecare funcţie poate constitui un fişier
sursă, uşurându-se în acest mod testarea. Reamintim că o funcţie nu poate fi împărţită între mai multe fişiere.
Un exemplu de program constituit din 2 fişiere sursă este:
/* primul fisier Fis1.c */
void F(); /* prototipul functiei definite in fisierul 2*/
#include <stdio.h>
void main(){
F(); /* apelul functiei F */
...
}
/* al doilea fisier Fis2.c */
#include <stdio.h>
void F(){
...
}
Pentru execuţia unui program rezident în mai multe fişiere se crează un proiect.
• se selectează opţiunea PROJECT
• se selectează OPEN PROJECT
• se introduce numele proiectului (creindu-se fişierul nume.prj)
• se adaugă pe rând numele fişierelor care compun proiectul cu ADD ITEM
• se execută proiectul din meniul RUN
6. Fişiere antet.
In C se pot utiliza o serie de funcţii aflate în bibliotecile standard. Apelul unei funcţii de bibliotecă
impune prezenţa prototipului funcţiei în textul sursă. Pentru a simplifica inserarea în textul sursă a
prototipurilor funcţiilor de bibliotecă, s-au construit fişiere de prototipuri. Acestea au extensia .h (header sau
antet).
De exemplu fişierul stdio.h conţine prototipuri pentru funcţiile de bibliotecă utilizate în operaţiile de intrare /
ieşire; fişierul string.h conţine prototipuri pentru funcţiile utilizate în prelucrarea şirurilor de caractere.
Includerea în textul sursă a unui fişier antet se face folosind directiva #include
Fişier antet Funcţii conţinute
stdio.h printf, scanf, gets, puts,...
conio.h putch, getch, getche, ...
math.h sqrt, sin, cos, ...
7. Funcţii matematice uzuale.
Fişierul antet <math.h> conţine semnăturile (prototipurile) unor funcţii matematice des folosite.
Dintre acestea amintim:
Notaţie Semnătură (prototip) Operaţie realizată
sin(x) double sin(double);
funcţii trigonometrice directe cos(x) double cos(double);
tg(x) double tan(double);
arcsin(x) double asin(double);
funcţii trigonometrice inverse arcos(x) double acos(double);
arctg(x) double atan(double);
arctg(y/x) double atan2(double, double);
sinh(x) double sinh(double);
funcţii hiperbolice cosh(x) double cosh(double);
th(x) double tanh(double);
exp(x) double exp(double); exponenţială naturală
10
n
double pow10(int); exponenţială zecimală
a
b
double pow(double, double); exponenţială generală
ln(x) double log(double); logaritm natural
lg(x) double log10(double); logaritm zecimal
| x |
double fabs(double);
valoare absolută int abs(int);
long labs(long);
√x double sqrt(double); rădăcină pătrată
long double sqrtl(long double);
x] double ceil(double); întregul minim >= x
x] double floor(double); întregul maxim <= x
conversii
double atof(const char *); conversie şir de caractere în float
long double atold (const char *); conversie şir de caractere în long double
Variabile.
1. Variabile externe (globale) şi variabile interne (locale).
Un program C este un ansamblu de obiecte externe: variabile şi funcţii.
O variabilă externă este o variabilă definită în afara oricărei funcţii, fiind astfel accesibilă din orice
funcţie. Am văzut că funcţiile pot comunica între ele prin variabile externe sau globale.Orice funcţie poate
accesa o variabilă externă, referindu-se la aceasta prin numele ei, dacă acest nume a fost declarat.
Prin urmare, variabilele externe au ca domeniu (sunt văzute şi pot fi accesate din) întregul fişier sursă
în care sunt definite.
Durata de viaţă a unei variabile externe (adică intervalul în care memoria este alocată) coincide cu
durata în care programul C este activ. Variabilele externe sunt permanente: ele reţin valori între apelurile
diferitelor funcţii.
Spre deosebire de variabilele externe, variabilele interne (numite şi automatice sau locale) au un
domeniu mult mai restrâns - ele sunt cunoscute numai în interiorul funcţiei în care sunt definite.
Durata de viaţă a variabilelor interne este mult mai scurtă ca a variabilelor externe – alocarea de
memorie se face la intrarea în funcţie, pentru ca la părăsirea funcţiei, memoria ocupată de variabilă să fie
eliberată.
Între ele, funcţiile sunt întotdeauna externe, pentru că nu pot fi definite în interiorul altor funcţii (ca în
Pascal!).
2. Domenii de vizibilitate ale variabilelor.
Funcţiile şi variabilele externe din care este alcătuit programul nu trebuie să fie compilate în acelaşi
timp; textul programului sursă poate fi separat în mai multe fişiere.
Domeniul unui nume reprezintă partea din program în care numele poate fi folosit.
Astfel pentru o variabilă locală, definită la începutul unei funcţii, domeniul îl reprezintă acea funcţie.
Variabilele locale cu acelaşi nume din funcţii diferite sunt entităţi diferite. Acelaşi lucru este valabil şi pentru
parametrii formali ai funcţiilor, care sunt de fapt variabile locale.
Domeniul unei variabile externe, ca şi a unei funcţii se întinde din punctul în care a fost declarată şi
până la sfârşitul fişierului sursă.
O variabilă externă poate fi referită şi dintr-un alt fişier sursă al programului, dacă este declarată în
acest fişier cu atributul extern.
O asemenea declaraţie anunţă proprietăţile variabilei (tipul), fără a aloca memorie pentru variabilă.
De exemplu: extern int x;
Alocarea de memorie se face o singură dată şi anume în fişierul sursă în care variabila externă este
definită. Tot în acel loc se face şi iniţializarea variabilei externe.
Intr-o funcţie sunt vizibili:
• parametrii formali
• variabilele locale
• variabilele globale locale modulului care declară funcţia ( variabilele declarate în afara
funcţiei în aceeaşi unitate de compilare;
• variabilele globale exportate de alte module şi importate de modulul care declară funcţia.
Orice definiţie este şi o declaraţie, dar reciproca nu este adevărată. Astfel prototipul unei funcţii este o
declaraţie.
3. Clase de memorare.
Orice variabilă are 4 atribute:
1. Clasa de memorare - reprezintă locul în care este memorată variabila:
• într-un segment de date
• într-un registru
• în stivă
• în heap
2. Vizibilitatea - reprezinta liniile textului sursă din care variabila poate fi accesată
• la nivel de bloc - variabila este cunoscuta într-un bloc, din momentul declarării până la
sfârşitul blocului
• la nivel de fisier - variabila este cunoscuta într-un fisier.
3. Durata de viaţă - reprezinta timpul în care variabila are alocat spaţiu în memoria internă.
• durată statică - variabila are alocat spaţiu pe tot timpul execuţiei programului. Variabilele
statice sunt memorate într-un segment de date si sunt în mod automat iniţializate cu 0.
• durată locală - variabila are alocat spaţiu cat timp se execută instrucţiunile unui bloc.
Alocarea de spaţiu se face în stivă sau într-un registru.
• durată dinamică - variabila este alocată şi dezalocată în timpul execuţiei programului prin
funcţii speciale. Alocarea de spaţiu se face în heap.
4. Tipul variabilei - determina numărul de octeţi rezervaţi pentru variabilă.
Atributele unei variabile se stabilesc:
• implicit - în locul unde se face declaraţia
• explicit - prin anumiţi calificatori.
Variabilele pot clasificate în:
• variabile globale
• variabile locale.
Variabilele globale:
• se definesc în afara corpurilor funcţiilor
• li se rezerva spaţiu într-un segment de date, înainte de execuţia programului
• au durata de viata statica
• sunt iniţializate implicit
• au vizibilitate la nivel de fisier
• vizibilitatea lor poate fi extinsa la nivel de program
O variabila globala poate fi accesata dintr-un fisier care nu conţine definiţia variabilei, dar trebuie sa
conţina o declaraţie a variabilei, care conţine numele variabilei precedat de specificatorul extern.
/* FISIER1.C */
int x=5; /* aici se defineste variabila x */
void F(); /* prototipul functiei F, definita in FISIER2.C */
void main(){
F(); /* apelul functiei F */
}
/* FISIER2.C */
#include <stdio.h>
extern a; /* declararea variabilei definite in alt fisier */
void F() /* aici se defineste functia F */
{
...
}
Dacă declaraţia unei variabile este facută înafara corpului funcţiei, ea este vizibilă din punctul
declaraţiei până la sfârşitul fişierului.
Dacă declaraţia variabilei se face în corpul unei funcţii, ea este vizibilă din locul declarării, până la
sfârşitul blocului.
3.1. Variabile şi funcţii statice.
Declararea unei variabile externe sau funcţii cu atributul static limitează domeniul obiectului la
fişierul sursă compilat. Folosirea cuvântului extern nu asigură, în acest caz accesul din alt fişier la obiectul
declarat static.
Variabilele interne pot fi şi ele declarate statice. Prin aceasta ele vor rămâne alocate şi după ieşirea din
funcţie, asigurând memorarea de valori între apeluri ale funcţiei. Variabilele interne statice :
• au durata de viaţă din momentul definiţiei până la sfârşitul execuţiei programului
• sunt memorate într-un segment de date
• sunt iniţializate automat
• definiţia lor începe cu cuvântul static
#include <stdio.h>
static double a;
void main(){
++a;
printf(“a=%.2lf”, a);
}
Variabila a este locală (fără specificatorul static ar fi fost globala). a este iniţializata la 0, astfel că
în primul apel se va afişa 1; următorul apel preia valoarea existentă (1), pe care o incrementează, deci afişează
2, ş.a.m.d. Vizibilitatea este la nivelul fişierului (modulului) şi nu se poate extinde la nivelul programului.
#include <stdio.h>
void increm(void){
static int a;
printf(“%d\n”, ++a);
}
void main(void){
int k;
for (k=0; k<5; k++)
increm();
}
Exemplul 14: Definiţi o funcţie pentru generarea de numere întregi aleatoare.
Un generator congruenţial de numere aleatoare este definit printr-o relaţie de forma:
x
n+1
= (a*x
n
+ b) % c,
în care x
0
poartă numele de sămânţa (seed) generatorului. a, b şi x
0
sunt numere prime, care asigură o
distribuţie aleatoare a numerelor în secvenţa {x
n
}. c dă domeniul în care se generează numerele aleatoare şi
se alege, de obicei, tot un număr prim. Funcţia generator de numere aleatoare calculează cu relaţia de mai sus
pe x
n+1
şi-l întoarce ca rezultat. Valoarea x
n
trebuie să provină din apelul precedent al funcţiei, aşa că va fi
declarată ca variabilă statică, iniţializată cu valoarea sămânţei x
0
. Iniţializarea va fi făcută numai la primul apel
al funcţiei, la fiecare din apelurile următoare se preia valoarea rămasă din apelul precedent. Se remarcă faptul
că se generează întotdeauna aceeaşi secvenţă de numere aleatoare! Pentru a genera de fiecare dată o altă
secvenţă aleatoare, sămânţa ar trebui generată aleator.
Există două funcţii de bibliotecă:
int rand(void); - care întoarce (dacă este folosită singură), o aceeaşi secvenţă de numere pseudoaleatoare
în domeniul 0 : RAND_MAX
void srand(unsigned s); - care stabileşte valoarea sămânţei (x
0
)
unsigned aleator(unsigned long c) {
static unsigned long x = 113;
unsigned long a = 121369, b = 179953;
x = (a*x + b) % c;
return x;
}
3.2. Variabile regiştri.
Pentru variabilele folosite în mod frecvent, pentru creşterea eficienţei programului, se doreşte ca
alocarea să se facă în regiştrii maşinii. În acest scop variabilele se declară cu atributul register.
De exemplu:
register int a;
register char c;
Pot fi declarate ca variabile regiştri numai variabilele automatice. Numai puţine tipuri de variabile
(care ocupă puţină memorie) permit declararea ca variabile regiştri (de exemplu tipurile char şi int dar nu
double!).
Întrucât numărul de regiştri maşină este limitat, declararea prea multor variabile de acest tip determină
ca, de la un anumit moment să se ignore această declaraţie, şi anume, după alocarea regiştrilor disponibili,.
Variabilelor alocate în regiştri nu poate să le fie aplicat operatorul de adresare.
Variabile definite în interiorul blocurilor.
O variabilă definită în interiorul unei instrucţiuni compuse ascunde o variabilă cu acelaşi nume
definită într-un bloc exterior şi durează până la terminarea blocului.
O variabilă definită şi iniţializată într-un bloc, va fi reiniţializată la fiecare intrare în acel bloc.
O variabilă statică, definită şi iniţializată într-un bloc, va fi iniţializată o singură dată, la prima intrare
în acel bloc.
3.3. Iniţializări.
În absenţa unei iniţializări explicite, variabilele externe şi cele statice sunt iniţializate la 0, în timp ce
variabilele interne şi regiştri rămân neiniţializate.
În cazul unei iniţializări explicite, iniţializatorul unei variabile externe sau statice poate fi o expresie
constantă, în timp ce pentru variabile interne sau regiştri putem avea orice expresie, conţinând chiar apeluri de
funcţii.
4. Probleme propuse.
1. Numerele naturale pot fi clasificate în: deficiente, perfecte sau abundente, după cum suma
divizorilor este mai mică, egală sau mai mare decât valoarea numărului. Astfel: n=12 este abundent deoarece
are suma divizorilor: sd = 1+2+3+4+6 = 16 > 12, n=6 este perfect: sd = 1+2+3 = 6, iar n=14
este deficient deoarece sd = 1+2+7 < 14.
• Definiţi o funcţie având ca parametru un număr întreg n, funcţie care întoarce ca rezultat –1, 0 sau 1
după cum numărul este deficient, perfect sau abundent.
• Scrieţi o funcţie main care citeşte două valori întregi x şi y şi clasifică toate numerele naturale cuprinse
între x şi y afişând după fiecare număr tipul acestuia, adică deficient, perfect sau abundent.
2. O pereche de numere naturale a şi b se numesc numere prietene, dacă suma divizorilor unuia dintre
numere este egală cu celălalt număr. De exemplu 220 şi 284 sunt numere prietene deoarece:
sd(220) = 1+2+4+5+10+11+20+22+44+55+110 = 284
sd(284) = 1+2+4+71+142 = 220
a) Scrieţi o funcţie având ca parametri un număr natural, care întoarce suma divizorilor numărului.
b) Scrieţi o funcţie având ca parametri două numere naturale, care întoarce 1 sau 0, după cum cele
două numere sunt sau nu prietene.
c) Scrieţi o funcţie main(), care în intervalul x, y dat găseşte toate perechile de numere prietene şi
le afişează.

3. Să se rezolve ecuaţia f(x)=0, prin metoda tangentei, pornind cu un x
(0)
dat, şi calculând
x
(k+1)
=x
(k)
-f(x
(k)
)/f'(x(
(k)
) cu o precizie dată eps, care se atinge când |x
(k+1)
- x
(k)
| < eps).
Funcţiile f(x) şi f’(x) sunt date de programator.
4. Se consideră funcţia f(x) = ln (1 + x
2
). Să se scrie un program care tabelează funcţia pe n
intervale, fiecare interval fiind precizat prin capetele a şi b şi pasul de afişare h.
5. Să se scrie toate descompunerile unui număr par ca o sumă de două numere prime. Se va utiliza o
funcţie care stabileşte daca un număr este sau nu prim.
6.Să se scrie în C:
a) Un subprogram funcţie pentru calculul valorii unei funcţii f(x) pentru o valoare dată x, definită
astfel:
b) O funcţie pentru calculul integralei definite:
¹
¹
¹
'
¹
> +
≤ ≤ − −
− < − −
·
1 x x x 1
1 x 1 x 1
1 x x x 1
) x ( f
2
pentru
pentru
pentru
prin metoda trapezelor, cu n paşi egali, pe intervalul [a,b], după formula
unde h=(b-a)/n
c) Un program care calculează integrala unei funcţii definite la punctul a), folosind funcţia b), pe un
interval dat [p,q], cu precizia epsilon (se repetă calculul integralei pentru n=10, 20,... paşi, până
când diferenţa dintre două integrale succesive devine mai mică decât epsilon
7.Pentru un număr dat N să se afişeze toţi factorii primi ai acestuia şi ordinul lor de multiplicitate.Se
va utiliza o funcţie care extrage dintr-un număr un factor prim.
8. Utilizând o funcţie pentru calculul celui mai mare divizor comun a două numere, să se
calculeze c.m.m.d.c. a n elemente întregi ale unei liste date.
9. Pentru fiecare element al unei liste de numere întregi date, să se afişeze numărul prim cel mai
apropiat de el ca valoare. Dacă două numere prime sunt la distantă egală de un element din listă se vor
afişa ambele numere prime.

·
b
a
dx ) x ( f I
]
]
]

+ + + ≅


·
1 n
1 i
) ih a ( f ) b ( f ) a ( f
2
h
I