Sunteți pe pagina 1din 18

LUCRAREA DE LABORATOR Nr.

5
Tema: Tehnicile prelucrării tablourilor, utilizînd subprograme
Scopul lucrării: însuşirea tehnicilor de algoritmizare şi programare cu subprograme în prelucrarea
structurilor complexe în TP şi C.
Obiectivele temei
1. Aprofundarea cunoştinţelor în limbajul şi mediul TurboC şi perfecţionarea tehnicii de programare cu
subprograme în prelucrarea structurilor complexe.
2. Însuşirea procedeelor de algoritmizare şi progamare prin descompunerea problemei în module autonome
care, apoi, vor fi reprezentate prin secvenţe /fragmente de program pentru prelucrarea unor informaţii după
principii comune cu apeluri multiple, analizând soluţiile stereotipe şi cele eficiente de introducere, afişare
şi rearanjări ale tablourilor etc.
3. Însuşirea tehnicilor eficiente de parcurgere, căutare, schimbare şi ordonare a structurilor şi calculul
conform cunoştinţelor obţinute din matematică în baza ciclurilor şi încorporate într-un program complex,
alcătuit după principiile structurale şi modulare.
Subiectele temei şi ordinea executării
1. Studierea principiilor prelucrării (descrierii, declarării, formării, etc.) tablourilor.
2. Studierea metodei de descompunere top-down a programului pe module aparte care să fie apelate în diferite
sectoare a programului, utilizînd subprograme.
3. Însuşirea tehnicilor moderne de elaborare a programelor complexe în C(cu subprograme proprii) în baza
problemelor din lucr. de laborator nr.3,4.
4. Elaborarea testelor şi depanarea programului diverse moduri în mediul integrat C.
5. Compararea tehnicilor simple şi celor bazate pe principiile structurale şi modulare.
Conţinutul raportului (vezi lucr. de laborator nr.1-3) şi suplimentar: Analiza erorilor admise pe
parcursul efectuării lucrării şi eficienţa algoritmilor elaboraţi.
Consideraţiile teoretice şi exemple
I. Subprograme în TP: PROCEDURI şi FUNCŢII
După cum aţi făcut cunoştinţă în liceu şi la lucrarea de laborator nr.1, structura unui program simplu în Turbo
Pascal cuprinde, de obicei, trei secţiuni, însă programele mai evoluate, care le vom numi complexe, în secţiunea
de declaraţii, fiind alcatuită la rîndul ei din cinci subsectiuni, şi mai poate să conţină şi secţiunea de declarare a
subprogramelor FUNCTION şi PROCEDURE, elaborate de programator, care reprezintă secvenţe de program
subordonate, efectuate eventual în mod repetat, cu parametri diferiţi. Atunci secţiunea de instrucţiuni
controlează execuţia programului, numindu-se de aceea şi program principal, şi face apel la eventualele
subprograme FUNCTION şi PROCEDURE definite in secţiunea de declaraţii. Deci în programul complex, în
afară de accesul la bibliotecile standarde ale TP pentru apeluri la subprogramele predefinite, se mai poate
conţine una sau mai multe subprograme (module: proceduri şi funcţii) care sunt secvenţe de program
subordonate şi se execută sub controlul lui. Ele sunt scrise o singură dată, însă pot fi apelate de un număr
nelimitat după necesitate. Procedurile si funcţiile reprezintă aceeaşi structură în trei secţiuni (antet, secţiune de
declaraţii şi secţiune de instrucţiuni) ca şi programul tradiţional scris la lucrările precedente.
2. Subprograme în C: FUNCŢII
2.1. Funcţii si programarea structurata
Programarea structurata este o metodă ce rezolva problema cu o strategie a programării mai eficientă si are
următoarele principii:
1. Structurile de control trebuie sa fie cât se poate de simple;
2. Construcţia unui program trebuie sa fie descrisa top-down.
Descrierea top-down se refera la descompunerea problemei noastre in module (subprobleme). De obicei,
aceste module sunt uşor de descris.
In faza de programere modulele vor deveni subprograme iar modulul principal – program principal.
Subprogramele in limbajul C/C++ se numesc functii.
Un program scris în limbajul C/C++ este un ansamblu de funcţii, fiecare dintre acestea efectuând o activitate bine
definită.
Un program C++ este alcatuit din una sau mai multe functii, din care una este radacina sau functie principala - adica nu
poate lipsi si executia incepe automat cu ea. Aceasta se numeste main.
Funcţiile comunică prin argumente: ele primesc ca parametri (argumente) datele de intrare,
efectuează prelucrările descrise în corpul funcţiei asupra acestora şi pot returna o valoare (rezultatul, datele de
ieşire).
Funcţiile pot fi descrise în cadrul aceluiaşi fişier, sau în fi şiere diferite, care sunt testate şi compilate separat,
asamblarea lor realizându-se cu ajutorul linkeditorului de legături.
Subprogramul este prin urmare un ansamblu alcatuit din tiputi de date, variabile si instructiuni scrise in
vederea unei anumite prelucrari (calcule, citiri, scrieri), care se identifica printr-un nume si care poate fi executat
doar daca este apelat .
2.1.1 Definirea şi apelarea funcţiilor în C. În 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).
Un program este compus din una sau mai multe funcţii, printre care si "main()" principala funcţie.
Întotdeauna execuţia unui program începe cu "main()". Când o funcţie este apelata (sau invocata) atunci
controlul programului este pasat funcţiei apelate. După ce aceasta îşi termina execuţia, atunci se pasează înapoi
controlul către principala funcţie.

Codul sursă C care descrie ce face o funcţie se numeşte "definiţia funcţiei". Aceasta are următoarea formă
generala:
tip nume_funcţie (lista_parametri_formali)
{
< declaraţia variabilelor locale, vizibile numai pentra această funcţie; >
< instrucţiuni executabile; >
return <rezultatul final>;
}
Primul rând se numeşte "header-ul" (antetul) funcţiei, iar ceea ce este inclus intre acolade se numeşte corpul
funcţiei. Corpul funcţiei este un bloc, care implementează algoritmul de calcul folosit de c ătre func ţie. În
corpul
funcţiei apar (în orice ordine) declaraţii pentru variabilele locale şi instruc ţiuni. Dac ă func ţia întoarce o
valoare,
se foloseşte instrucţiunea return valoare. La execuţie, la întâlnirea acestei instrucţiuni, se revine în
funcţia
apelantă.
Daca in antet nu precizam parametrii, atunci se va scrie "void" (cuvânt rezervat pentru lista vida). Daca
Funcţia nu întoarce nici o valoare, atunci se va scrie ca tip întors tot "void". Tipul returnat (întors) de funcţie este
cel precizat in "return" (ce va fi îndată explicat). Parametrii din antetul funcţiei (lista_parametri_formali) sunt
daţi printr-o lista cu argumente separate prin virgula. Aceste argumente sunt date de tipul argumentului urmat de
un identificator ce aparţine acelui tip. Se mai spune ca acel identificator este "parametru formal".
Sa se scrie o functie care sa verifice daca un numar intreg este sau nu palindrom (este egal cu
rasturnatul sau).
#include <iostream >
using namespace std;
int palindrom(long int x) // x este declarat ca parametru formal
{
long int z=0,y;
y=x; // retin in y valoarea lui x pentru a nu se pierde valoarea citita
while(x!=0)
{ z=z*10+x%10; //se construieste numarul z adaugand ultima cifra din x
x=x/10; } //valoarea lui x se divide (sterge ultima cifra din x)
if(z==y) return 1; //testeaza daca valoarea construita chiar este egala cu valoarea initiala citita(y=x)
else return 0; //daca nu sunt egale returneaza val 0
}
int main()
{ long int a,b;
cout<<"Dati numarul a= ";cin>>a;
if(palindrom(a)!=0) cout<<"numarul "<<a<<" este palindrom"<<endl;
else cout<<"numarul "<<a<<" NU este palindrom"<<endl;
}
2.1.1.1 Exemplul definirii şi apelării funcţiilor în C, în stil vechi, când corpul funcţiei se amplasează
înaintea lui main():
#include <…>
void tipareste_mesaj(int k)
{ int i;
printf("Iti urez:\n");
for (i = 0; i < k; ++i)
printf(" O zi buna ! \n");
}
main()
{ int n;
printf("Dati un numar natural mic: ");
scanf("%d", &n);
tipareste_mesaj(n); / apelul functiei tipareste_mesaj /
}
Instrucţiunea "return" Instrucţiunea "return" este folosita pentru doua scopuri. Când se executa o
instrucţiune "return", controlul programului este pasat înapoi programului apelant. In plus, daca exista o
expresie după acest "return", atunci se va returna valoarea acestei expresii. Instrucţiunea "return" poate avea
formele:
return;
sau
return expresie;
Exemplul 2: Găsirea minimului a doi intregi.
#include <…>
int min(int x, int y)
{
if (x < y) return x;
else return y
}
main()
{
int j, k, m;

printf("Dati doi intregi: ");


scanf("%d%d", &j, &k);
m = min(j, k); / apelul functiei min /
printf("\n%d este minimul dintre %d si %d.\n", m, j, k);
}
Ca argument poate apărea orice expresie admisă în C. Funcţia returnează valoarea acestei expresii funcţiei
apelante.
O funcţie nu returnează în mod obligatoriu o valoare. O instrucţiune return, fără expresie ca parametru,
cauzează numai transferul controlului funcţiei apelante nu şi o valoare utilă.
La rîndul său funcţia apelantă poate ignora valoarea returnată.
De obicei o funcţie returnează o valoare de tip întreg. Dacă se doreşte ca funcţia să returneze un alt tip,
atunci numele tipului trebuie să preceadă numele funcţiei, iar programul trebuie să conţină o declaraţie a acestei
funcţii atît în fişierul în care funcţia este definită cît şi în fişierul unde funcţia este apelată.
Pentru a evita orice confuzie se recomandă ca tipul valorii returnate de funcţie să fie întotdeauna
precizat, iar dacă dorim în mod expres ca funcţia să nu returneze o valoare să folosim tipul void.
De exemplu, funcţia atof(s) din biblioteca asociată compilatorului converteşte şirul s de cifre în valoarea
sa în dublă precizie. Vom declara funcţia sub forma:
double atof(char s[]);
sau împreună cu alte variabile de tip double: double sum, atof(char s[]);
Funcţiile nu pot returna masive, structuri, reuniuni sau funcţii.
Dacă o funcţie returnează o valoare de tip char, nu este nevoie de nici o declaraţie de tip din cauza
conversiilor implicite. Totdeauna tipul char este convertit la int în expresii.
O metodă de a comunica datele între funcţii este prin argumente. Parantezele mici care urmează după numele
funcţiei închid lista argumentelor.
În limbajul C argumentele funcţiilor sînt transmise prin valoare. Aceasta înseamnă că în C funcţia
apelată primeşte valorile argumentelor sale într-o copie particulară de variabile temporare (în realitate pe stivă).
Funcţia apelată nu poate altera decît variabilele sale particulare, adică copiile temporare.
Apelul prin valoare este o posibilitate, dar nu şi o obligativitate. Apelul prin valoare conduce la
programe mai compacte cu mai puţine variabile externe, deoarece argumentele pot fi tratate ca variabile locale,
şi care pot fi modificate convenabil în rutina apelată.
Ca exemplu, prezentăm o versiune a funcţiei putere care face uz de acest fapt:
power(int x, int n) {
int p;
for (p=1; n>0; --n) p = p * x; return p;
}
Argumentul n este utilizat ca o variabilă temporară şi este decrementat pînă devine zero; astfel nu este
nevoie de încă o variabilă i. Orice operaţii s-ar face asupra lui n în interiorul funcţiei, ele nu au efect asupra
argumentului pentru care funcţia a fost apelată.
Dacă totuşi se doreşte alterarea efectivă a unui argument al funcţiei apelante, acest lucru se realizează cu
ajutorul pointerilor sau a variabilelor declarate externe.
În cazul pointerilor, funcţia apelantă trebuie să furnizeze adresa variabilei de modificat (tehnic printr-un
pointer la această variabilă), iar funcţia apelată trebuie să declare argumentul corespunzător ca fiind un pointer.
Referirea la variabila de modificat se face prin adresare indirectă (vezi capitolul 9).
Printre argumentele funcţiei pot apărea şi nume de masive. În acest caz valoarea transmisă funcţiei este
în realitate adresa de început a masivului (elementele masivului nu sînt copiate). Prin indexarea acestei valori
funcţia poate avea acces şi poate modifica orice element din masiv.
Functie care verifica daca un numar dat este prim sau nu. Program
pentru afisarea descompunerilor numerelor pare mai mici ca un intreg dat
in sume de doua numere prime (Ipoteza lui Goldbach = orice numar par se
poate scrie ca suma a doua numere prime).
Listingul programului :
#include<stdio.h>
#include<conio.h>

int prim(int i)
{int p=1,c=0;
while(p<=i) { if(i%p==0) c=c+1; p=p+1; }
if(c<=2) return 1; else return 0;
}

int main ()
{ int i,j,n;
printf("Introduceti un numar natural: "); scanf("%d",&n); i=4;
do{ for(j=1;j<=i;j++)
if(prim(j)&& prim(i-j) ) printf(" %d=%d+%d ",i,j,i-j);
i=i+2;} while (i<=n);
}
Exemplul în stil vechi . Fie dat v un tablou unidimensional de dimensiune n si k un element de acelasi tip cu
elementele tabloului. (k=cheie de cautare). Sarcina lui k este de a gasi daca exista sau nu un element din v care are
valoarea k.
#include <stdio.h>
#include <conio.h>
int v[20];
int n,k,c;
//Crearea vectorului
void citire()
{
int i;
printf("elementele sirului in ordine crescatoare\n");
printf("v[1]=");scanf("%d",&v[1]);
for(i=2;i<=n;i++)
do
{
printf("v[%d]=",i);
scanf("%d",&v[i]);
} while (v[i]<=v[i-1]);
}
//Afisarea vectorului
void afisare()
{
int i;
for(i=1;i<=n;i++)
printf("v[%d]=%d ",i,v[i]);
printf("\n");
}
//Functia de cautare, de tip intreg
int cautare(int k,int inf, int sup)
{
int mij;
if (inf<=sup)
{ mij=(inf+sup)/2;
if (v[mij]==k) return mij;
else if (v[mij]>k) cautare(k,inf,mij-1);
// apelul recursiv al functiei de cautare
else cautare(k,mij+1,sup);
//apelul recursiv al functiei de cautare
}
else return 0;
}
void main()
{ clrscr();
do{
printf("n="); scanf("%d",&n);
}while(n<1||n>20); //verificarea elementului introdus care trebuoe sa fie 1< si >20

//Apelul functiei de completare a sirului


citire();
printf("vectorul introdus \n");
//Apelul functiei de afisare
afisare();
printf("nr cautat in sir =");
scanf("%d",&k); //Citirea elementului cautat in sir
c=cautare(k,1,n); //Apelul functiei de cautare cu indicarea variabilelor de intrare si atribuirea rezultatului ei
in variabila c
if (c==0) printf("elementul nu este in sir\n");
else printf("elementul cautat este pe pozitia %d\n",c);
getch();
}
2.1.1.2 Exemplul definirii funcţiilor în C prin prototipurile funcţiilor, în stil nou, când corpul funcţiei se
amplasează după necesitate fără restricţii în afara lui main():
In C, apelul unei funcţii poate apare înaintea declarării ei. Funcţia poate fi definita mai târziu in acelaşi fişier,
sau in alt fişier sau dintr-o biblioteca standard. In ANSI C, prototipul funcţiei remediază problema punând la
dispoziţie numărul si tipul argumentelor funcţiei. Prototipul specifica, de asemenea, si tipul returnat de funcţie.
Sintaxa prototipului unei funcţii este:
tip nume_funcţie (lista_tipuri_parametri_formali);
In lista de parametri putem specifica chiar si parametrul, dar acesta este optional. Daca Funcţia nu are
parametri, atunci se foloseşte "void".
Exemplu: Reluam un exemplu precedent.
#include <…>
main()
{
int n;
void tipareste_mesaj(int);
printf("Dati un numar natural mic: ");
scanf("%d", &n);
tipareste_mesaj(n);
}
void tipareste_mesaj(k)
{
int i;

printf("Iti urez:\n");
for (i = 0; i < k; ++i)
printf(" O zi buna ! \n");
}
Prototipul unei funcţii poate fi plasat in corpul altei funcţii, sau de regula, se scriu la începutul programelor
după directivele #include <…> si #define.
2.2. Principiile programării structurate. Programarea structurată are ca scop dezvoltarea unor programe uşor
de realizat în echipă, uşor de depanat şi de actualizat. Conceptul de subalgoritm prevede ca orice problema poate apare ca o
subproblema S a unei probleme mai complexe. Algoritmul de rezolvare a problemei S devine in acest caz un subalgoritm
pentru algoritmul de rezolvare a problemei. Deci SUBPROGRAMUL va reprezinta parti identificabile prin nume care se
pot activa la cerere prin intermediul acetui nume. O parte din subprogram se contruieste ca subprogram daca un algoritm
cuprinde in mai multe locuri aceiasi secventa de operatii executabila pentru aceleasi date sau pentru date diferite. In loc ca
subprogramul sa cuprinda in acelasi loc, acelasi grup de instructiuni, concepand grupul de intructiuni ca subprogram, el va
aparea in program o singura data si se va activa de mai multe ori. Partea respectiva de program rezolva o subproblema din
cele in care se descompune problema complexa.Apar deci câteva principii de care un programator trebuie să ţină seama.
Acestea se numesc principiile programării structurate.
Primul principiu este modularizarea. În cadrul unor probleme complexe este necesară descompunerea acestora în
subprobleme mai simple, pentru care se pot scrie module de program mai simple. Fiecare modul este independent de
celelalte, în final ele interacţionând printr-un program principal, un fel de interfaţă. Modulele pot fi implementate de
programatori diferiţi din cadrul unei echipe. Ele pot fi testate, modificate, depanate în mod independent, neafectând şi
celelalte module.

Modulele au aceeaşi structură ca şi programele principale, putând declara variabile atât în module (numite variabile
locale) cât şi în programul principal (numite variabile globale). Modulele create sunt proceduri şi funcţii şi vor fi studiate
în cadrul unui limbaj de programare.

Un al doilea principiu este structurarea datelor şi a prelucrărilor. Datele se pot grupa în structuri de date aşa
cum am aratat mai sus. Prelucrările asupra datelor se pot grupa şi ele în structuri despre care vorbim în teorema
Bohm-Jacopini.
Teorema Bohm-Jacopini afirmă ca orice algoritm se poate reprezenta folosind 3 tipuri de structuri fundamentale:
structură liniară, structură alternativă şi structură repetitivă.
Structura liniară (numită şi secventială) este alcatuită din urmatoarele instrucţiuni, Structura alternativă etc.
(vezi LL1,2)

Subprogramele devin unităţi de program care:

☼au un algoritm propriu,


☼pot fi proiectate independent,
☼pot fi scrise independent,
☼pot fi compilate independent,
☼nu se pot executa independent ci numai in cadrul unui program (apel).
Avantajele utilizării lor:
§☺ evitarea scrierii repetate a aceluiaşi set de instrucţiuni,
§◄ creşterea eficienţei, prin reutilizarea subprogramelor (biblioteci de subprograme).

Descrierea metodei "top-down" Presupunem ca avem de citit câţiva întregi si trebuie sa-i afişăm in ordine
pe coloane (in capătul de sus al coloanelor trebuie sa scriem numele câmpului), sa le afişăm suma lor parţiala,
minimul si maximul lor. Pentru scrierea unui program C ce face acest lucru, vom utiliza proiectarea (descrierea)
"top-down".
Astfel, descompunem problema in următoarele module:
1. Un antet pentru problema data;
2. Scrierea câmpurilor;
3. Citirea si scrierea lor pe coloane.
Toţi aceşti trei paşi vor fi descrişi in câte o funcţie ce se apelează din "main()". Obţinem, un prim cod sursă:
#include <…>
main()
{
void tipareste_antet(void);
void scrie_campurile(void);
void citeste_scrie_coloanele(void);
/ apelurile funcţiilor:/
tipareste_antet();
scrie_campurile();
citeste_scrie_coloanele();
}
Aceasta reprezintă într-un mod foarte simplu descrierea "top-down". Daca o problema este prea grea, atunci
o descompunem in module, si apoi le rezolvam pe acestea. Beneficiul suplimentar al acestei metode este
claritatea sa.
void tipareste_antet(void)
{
printf("\n%s%s%s\n",
"**************************************************\n",
"* Calculul sumelor, minimului si maximului *\n",
"**************************************************\n");
}
Funcţia ce foloseşte la scrierea câmpurilor este la fel uşor de scris:
void scrie_campurile(void)
{
printf("%5s%12s%12s%12s%12s\n\n",
"Numar", "Articol", "Suma", "Minimul", "Maximul");
}
Urmeaza apoi funcţia ce serveste la scrierea înregistrărilor referitoare la câmpurile discutate mai sus:
void citeste_scrie_coloanele(void)
{
int contor = 0, articol, suma, minim, maxim;
int min(int, int), max(int, int);

if (scanf("%d", &articol) == 1)
{
++contor;
suma = minim = maxim = articol;
printf("%5d%12d%12d%12d%12d\n\n", contor, articol, suma, minim, maxim);
while (scanf("%d", &articol) == 1)
{
++contor;
suma += articol;
minim = min(articol, minim);
maxim = max(articol, maxim);
printf("%5d%12d%12d%12d%12d\n\n",
contor, articol, suma, minim, maxim);
}
}
else printf("Nici o data nu a fost citita.\n\n");
}
Daca datele se introduc de la tastatura, atunci tabelul se va afişa "intrerupt" de citirile ce au loc de la
tastatura. Astfel, se prefera citirea dintr-un fişier extern. Presupunem ca fişierul nostru executabil (asociat
fişierului sursa scris in C) se numeşte "numere.exe" si am creat un fişier numit "fisier.int" ce contine
urmatoarele numere:
19 23 -7 29 -11 17
Dând comanda
numere < fişier.int vom obtine un tabel ce contine toate datele dorite.
Invocare si apel prin valoare O funcţie este invocata prin scrierea numelui sau împreuna cu lista sa de
argumente intre paranteze. De obicei, numărul si tipul acestor argumente se "potriveste" cu parametrii din lista
de parametri prezenti in definitia funcţiei. Toate argumentele sunt apelate prin valoare ("call-by-value"). Asta
inseamna ca fiecare argument este evaluat si valoarea sa este folosita ca valoare pentru parametrul formal
corespunzator. De aceea, daca o variabila (argument) este folosita la transmiterea unei valori, atunci valoarea ei
nu se schimba. Exemplu:
#include <…>
main()
{
int n=3, suma, calculeaza_suma(int);

printf("%d\n", n); /* se va scrie 3 */


suma = calculeaza_suma(n);
printf("%d\n", n); /* se va scrie 3 */
printf("%d\n", suma); /* se va scrie 6 */
}

int calculeaza_suma(int n) /* suma numerelor de la 1 la n */


{
int suma = 0;
for ( ; n > 0; --n) /* n se schimba aici, dar nu si in main() */
sum += n;
printf("%d\n", n); /* se va scrie 0 */
return suma;
}
Chiar daca n este trimis ca argument in funcţia "calculeaza_suma()" si valoarea lui n se modifica in aceasta
funcţie, valoarea sa din mediul apelant rămâne neschimbata. Vom vedea mai târziu cum se poate simula apelul
prin adresa ("call-by-reference").
Deosebirea dintre "return" si "exit" Exista doua procedee de a returna o valoare.
return expresie si exit(expresie)
Daca se folosesc in "main()", atunci acestea sunt echivalente, dar in orice alta funcţie efectul lor este diferit
(in ANSI C, Funcţia "main()" intoarce o valoare de tip int). Un apel al lui exit() in orice alta funcţie va implica
terminarea execuţiei programului si returnarea valorii către mediul apelant (sistemul de operare sau mediul de
programare C). Valoarea returnata se numeşte stare de iesire ("exit status"). Prin convenţie, starea de iesire zero
indica terminare cu succes, pe cand iesire cu un numar diferit de zero indica o situatie anormala.
Exemplu model: Scopul lucrarii : Însuşirea tehnicii top-down de algoritmizare şi programare cu funcţii şi în
prelucrarea structurilor complexe în C/C++.
Sarcina lucrarii : Sunt date tablourile X={xi}, i=1…n; Y={yi}, i=1…n şi valoarea w, în baza cărora să
calculeze valorile lui v:

Schema bloc:

Start Start(first) Start(third)

scanf(n,w) i=0 j=0

i=0
i j
< <
i n n
< v=pow(*(a+i),2)+pow(*(b+i),2 s=1
n )+*(a+i)**(b+i);
scanf(x[i]) i=0
i++
i++
i
<
j
w==
return
s=s**(b+i)
1 v
v=first(x,y,n) Start(second i++
)
i=0
w== v=v+*(a+j)+s
2
i j++
v=second(x,y,n)
<
n
s1=s1+pow(*(a+i),2)
w==
3
s2=s2+pow(*(b+i),2) return v
STOP
i++
v=third(x,y,n)

Return s1*s2 ;
vgssss1*s2
Listingul :
#include<stdio.h>
#include<conio.h>
#include<math.h>
int first(int x[],int y[],int n)
{
int i,v,*a,*b;
a=x;b=y;
for(i=0;i<n;i++)
v=pow(*(a+i),2)+pow(*(b+i),2)+*(a+i)**(b+i);
return v;
}
int second(int x[],int y[],int n)
{
int i,v,*a,*b,s1,s2;
a=x;b=y;s1=0;s2=0;
for(i=0;i<n;i++)
{
s1=s1+pow(*(a+i),2);
s2=s2+pow(*(b+i),2);
}
return s1*s2;
}
int third(int x[],int y[],int n)
{
int j,i,v,*a,*b,s;
a=x;b=y;v=x[1];
for(j=0;j<n;j++)
{
s=1;
for(i=0;i<j;i++)
s=s**(b+i);
v=v+*(a+i)+s;
}
return v;
}
main()
{
clrscr();
int i,j,n,x[50],y[50],v,w;
printf("Introduceti marimea masivelor:");
scanf("%d",&n);
printf("\nIntroduceti valorile masivului x:");
for(i=0;i<n;i++)
scanf("%d",&x[i]);
printf("\nIntroduceti valorile masivului y:");
for(i=0;i<n;i++)
scanf("%d",&y[i]);
printf("\nIntroduceti w:");
scanf("%d",&w);
if(w==1) v=first(x,y,n);
if(w==2) v=second(x,y,n);
if(w==3) v=third(x,y,n);
printf("\nRezultatul este: %d",v);
getch();}
Comunicarea între funcţii se face prin argumente şi valori returnate de funcţii. Comunicarea între funcţii
poate fi făcută şi prin intermediul variabilelor externe.
O metodă de a se schimba cu datele între funcţii se face prin argumentele funcţiei (lista-parametri
formali). Parantezele mici care urmează după numele funcţiei închid lista argumentelor.
În limbajul C argumentele funcţiilor sunt transmise, de obicei, prin valoare. Aceasta înseamnă că în C
funcţia apelată primeşte valorile argumentelor sale într-o copie particulară de variabile temporare (în realitate pe
stivă).
Exemplul : suma a 2 matrici
#include<stdio.h>
#include<conio.h>
#define MAXLIN 100
#define MAXCOL 200

void citireMatrice(int lin, int col, int x[][MAXCOL]);


void afisareMatrice(int lin, int col, int x[][MAXCOL]);
void sumaMatrice(int, int, int[][MAXCOL], int[][MAXCOL], int[][MAXCOL]);

void main(void) {
int a[MAXLIN][MAXCOL], b[MAXLIN][MAXCOL], c[MAXLIN][MAXCOL];
int m, n;
clrscr();
//la intrare se introduce m=3 n=4
if(scanf("m=%d n=%d", &m, &n) != 2)
printf("Eroare la citirea dimensiunilor");
else {
printf("\nDimensiunile matricii(%d, %d)", m, n);
printf("\nMatricea a=\n");
citireMatrice(m,n,a);
puts("\nDupa citire: matricea a=");
afisareMatrice(m,n,a);
printf("\nMatricea b=\n");
citireMatrice(m,n,b);
puts("\nDupa citire: matricea b=");
afisareMatrice(m,n,b);
sumaMatrice(m,n,a,b,c);
puts("\nDupa citire: matricea c=");
afisareMatrice(m,n,c);
}
getch();
}
void citireMatrice(int lin, int col, int x[][MAXCOL]) {
int i, j;
for(i=0; i<lin; i++)
for(j=0; j<col; j++)
scanf("%d", &x[i][j]);
}
void afisareMatrice(int lin, int col, int x[][MAXCOL]) {
int i, j;
for(i=0; i < lin; i++) {
printf("\n");
for(j=0; j < col; j++)
printf("%d\t", x[i][j]);
}
}
void sumaMatrice
(int lin,int col,int x1[][MAXCOL],int x2[][MAXCOL],int x3[][MAXCOL]) {
int i, j;
for(i=0; i<lin; i++)
for(j=0; j<col; j++)
x3[i][j] = x1[i][j] + x2[i][j]; }

Funcţia apelată nu poate altera decît variabilele sale particulare, adică copiile temporare.
Apelul prin valoare este o posibilitate, dar nu şi o obligativitate. Apelul prin valoare conduce la
programe mai compacte cu mai puţine variabile externe, deoarece argumentele pot fi tratate ca variabile locale,
şi care pot fi modificate convenabil în rutina apelată.
Ca argument poate apărea orice expresie admisă în C. Funcţia returnează valoarea acestei expresii funcţiei
apelante.
O funcţie nu returnează în mod obligatoriu o valoare. O instrucţiune return, fără expresie ca parametru,
cauzează numai transferul controlului funcţiei apelante nu şi o valoare utilă.
La rîndul său funcţia apelantă poate ignora valoarea returnată.
De obicei o funcţie returnează o valoare de tip întreg. Dacă se doreşte ca funcţia să returneze un alt tip,
atunci numele tipului trebuie să preceadă numele funcţiei, iar programul trebuie să conţină o declaraţie a
acestei funcţii atît în fişierul în care funcţia este definită cît şi în fişierul unde funcţia este apelată. Pentru a
evita orice confuzie se recomandă ca tipul valorii returnate de funcţie să fie întotdeauna precizat, iar dacă
dorim în mod expres ca funcţia să nu returneze o valoare să folosim tipul void.
Astfel definirea unei funcţii se poate face oriunde in cadrul codului sursa, sau chiar in alte fişiere, insă nu
poate fi făcuta in interiorul altei funcţii. Deseori mai întâi se declară prototipul unei funcţii iar mai jos corpul
funcţiei. Prototipul funcţiei are rolul de a anunţa numele funcţiei, tipul returnat si tipul si numarul parametrilor.
În cazul că funcţia nu are parametri sau nu returneaza nici o valoare, se foloseste tipul vid “void”. Nu este
necesară prezenţa prototipului, dar dacă acesta lipseşte, iar funcţia este apelată înaintea declaraţiei ei, unele
compilatoare (mai vechi) vor da mesaje de avertizare in momentul compilării. Prototipurile au fost introduse în
standardul ANSI (versiunile mai vechi de C nu prevedeau prototipuri de funcţii) pentru a permite compilatorului
să facă anumite verificări legate de numarul parametrilor funcţiei şi de conversii ilegale între tipul parametrilor
şi cel al argumentelor.
Deci mecanismul de transmitere a parametrilor către funcţii în limbajul C este prin valoare, spre deosebire de
alte limbaje (ca de ex. Pascal), unde se întâlneşte şi transmiterea prin valoare şi prin adresă în mod expres. La
transmiterea prin valoare, modificările asupra parametrilor efectuate în interiorul funcţiei nu se propaga si în
afara funcţiei. Dacă totuşi se doreşte alterarea efectivă a unui argument al funcţiei apelante, acest lucru se
realizează cu ajutorul pointerilor sau a variabilelor declarate externe. Astfel, chiar daca mecanismul de
transmitere a parametrilor este doar prin valoare, in limbajul C se poate transmite parametrii si prin adresa, intr-
un mod indirect, folosind pointeri.
În general numele funcţiei este ales după dorinţa utilizatorului. Însă în fiecare program trebuie să existe
o funcţie cu numele impus main; orice program îşi începe execuţia cu funcţia main. Celelalte funcţii sunt apelate
din interiorul funcţiei main. Unele dintre funcţiile apelate sunt definite în acelaşi program, altele sunt conţinute
într-o bibliotecă de funcţii.
O funcţie poate fi declarată şi static. În acest caz ea poate fi apelată numai din fişierul unde a fost
definită.
Funcţiile în C pot fi folosite recursiv, deci o funcţie se poate apela pe ea însăşi fie direct, fie indirect.
Functie recursiva pentru ridicarea unui numar la o putere intreaga pe baza relatiei de recurenta x^k = x * x^(k-1) si cu
x^0=1
double power (double x, int n) {
if (n==0) return 1. ;
return x * power(x,n-1); }
Functie recursiva pentru ridicarea unui numar la o putere intreaga cu numar redus de inmultiri, pe baza relatiei de
recurenta x^k = x^(k/2) * x^(k/2) daca k este par si x^k= x * x^(k-1) daca k impar
double power (double x, int n) {
double y;
if (n==0) return 1;
if ( n %2 ==0) { y=power(x,n/2); return ( y*y); }
else return (x * power (x,n-1));
}

Când un tablou multidimensional este un parametru formal in definitia unei functii (argumentul), toate dimensiunile,
exceptand prima, trebuie specificate.

Exemplul cu proceduri De aflat minimul si maximul pe intr-o matrice in diferite conditii ,pe diagonal
principal,diagonal secundara,din intreaga matrice ,din fiecare rind si fiecare coloana.
Schema logica:
Listingul programului :
#include <stdio.h>
include<conio.h>
int i,j;
oid citire (int x[][100], int n)
{int i,j;
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{printf("x[%d][%d]= ",i,j);
scanf("%d",&x[i][j]);}
}
void afisare (int a[][100],int n)
{ int i,j;
for (i=0;i<n;i++)
{printf("\n");
for (j=0;j<n;j++)
printf("%4d",a[i][j]);
}
}
void extremtotal(int a[][100],int n,int *xmin,int *xmax)
{
*xmin=a[0][0];
*xmax=a[0][0];
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{if(a[i][j]>*xmax)
*xmax=a[i][j];
if(a[i][j]<*xmin)
*xmin=a[i][j];
}}
void exdprin(int a[][100],int n,int *xmin,int *xmax)
{ *xmin=*xmax=a[0][0];
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{if(j==i)
{if(a[i][j]>*xmax)
*xmax=a[i][j];
if(a[i][j]<*xmin)
*xmin=a[i][j];}
}
}
void exdsec(int a[][100],int n,int *xmin,int *xmax)
{ *xmin=a[0][n-1];
*xmax=a[0][n-1];
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{if(j==n-1-i)
{if(a[i][j]>*xmax)
*xmax=a[i][j];
if(a[i][j]<*xmin)
*xmin=a[i][j];}
}
}
void excoloane(int a[][100],int n)
{ int max[100],k;
for(j=0;j<n;j++) {
max[j] = a[0][j];
for(i=0;i<n;i++) {
if(a[i][j]>max[j]) {
max[j] = a[i][j];
}
}
}
for (k=0;k<n;k++)
printf(" \n Coloana %d : \n max= %d",k,max[k]);
}
void excoloanem(int a[][100],int n)
{ int min[100],k;
for(j=0;j<n;j++) {
min[j] = a[0][j];
for(i=0;i<n;i++) {
if(a[i][j]<min[j]) {
min[j] = a[i][j];
}
}
}
for (k=0;k<n;k++)
printf(" \n Coloana %d : \n min= %d",k,min[k]);
}
void rind_min(int a[][100],int n)
{ int min[100],k;
for(j=0;j<n;j++) {
min[j] = a[j][0];
for(i=0;i<n;i++) {
if(a[j][i]<min[j]) {
min[j] = a[j][i];
}
}
}
for (k=0;k<n;k++)
printf(" \n Rindul %d : \n min= %d",k,min[k]);}

void rind_max(int a[][100],int n)


{ int min[100],k;
for(j=0;j<n;j++) {
min[j] = a[j][0];
for(i=0;i<n;i++) {
if(a[j][i]>min[j]) {
min[j] = a[j][i];
}
}
}
for (k=0;k<n;k++)
printf(" \n Rindul %d : \n max= %d",k,min[k]);}

int main()
{ int a[100][100],n,tmax,tmin,pmax,pmin,smax,smin,max,min ,p,m1;
printf("Introduceti dimensiunea matrici: "); scanf("%d",&n);
citire(a,n); getchar();
system("cls");
afisare(a,n);
printf("\n\n\nCe va intereseaza:\n\n1.Maximul de pe diagonala principalu?\n2.Minimul de pe diagonala
principala?\n3.Maximul de pe diagonal secundara?\n");
printf("4.Minimul de pe diagonal secundara\n5.Maximul din matrice\n6.Minimul din matrice\n7.Maximul de pe
coloane\n");
printf("8.Minimul de pe coloane \n9.Maximul de pe rinduri\n10.Minimul de pe rinduri \n\n\nAlege cifra
corespunzatoare:");
m1: scanf("%d",&p);

switch(p)
{ case 1: exdprin(a,n,&pmin,&pmax); printf("%d",pmax);break;
case 2: exdprin(a,n,&pmin,&pmax); printf("%d",pmin);break;
case 3: exdsec (a,n,&smin,&smax); printf("%d",smax);break;
case 4: exdsec (a,n,&smin,&smax); printf("%d",smin);break;
case 5: extremtotal(a,n,&tmin,&tmax); printf ("%d",tmax);break ;
case 6: extremtotal(a,n,&tmin,&tmax); printf ("%d",tmin);break ;
case 7: excoloane(a,n);break;
case 8: excoloanem(a,n); break;
case 9: rind_max(a,n);break;
case 10: rind_min(a,n);break;
}
printf("\n\nTe mai intereseaza ceva?");
goto m1;
return 0;
}

Exercitii propuse spre implementare


1. Folosind funcţiile "rand()", "min(,)" si "max(,)", sa se genereze n numere naturale si sa se afiseze minimul
si maximul dintre acestea.
2. (Jocul cap-pajura, simulare Monte-Carlo) Presupunem ca dispunem de o moneda ideala (nemasluita).
Doi jucatori arunca cu moneda dupa urmatoarele reguli:
1.a. Se fac un numar total de n aruncari;
1.b. Primul jucator arunca moneda si celalalt spune "cap" sau "pajura";
1.c. Daca acesta "ghiceste" ce va pica moneda, atunci se inverseaza jucatorii (adica arunca al doilea si
primul incearca sa ghiceasca);
1.d. La sfarsit, trebuie afisat scorul (si procentul de castig al fiecaruia).
3. (Conjectura lui Goldbach)
Orice numar par mai mare decat 2 se poate scrie ca suma a doua numere prime. Scrieti un program C care
verifica aceasta conjectura pentru numere situate intre m si n. De exemplu, daca m=700 si n=1100, atunci
afisati:
700 = 17 + 683
702 = 11 + 691
704 = 3 + 701
...
1098 = 5 + 1093
1100 = 3 + 1097
Generalizare: Scrieti toate combinatiile posibile de adunare a doua numere prime egal cu un numar dat.
PROBLEME PROPUSE

PROBLEME PROPUSE.
P3.1 Functie pentru determinarea numarului de cifre al unui numar dat (de
orice tip intreg). Program pentru citirea unui intreg n si afisarea a n
numere aleatoare intre 0 si n, cu determinare numar de coloane in functie
de valorile afisate. ( nr de coloane = 80/(nr.cifre+2) )
Se va utiliza functia "random" declarata in <math.h>

P3.2 Functie care verifica daca un numar dat este prim sau nu. Program
pentru afisarea descompunerilor numerelor pare mai mici ca un intreg dat
in sume de doua numere prime (Ipoteza lui Goldbach = orice numar par se
poate scrie ca suma a doua numere prime).

P3.3 Functie care primeste doi intregi a si b si determina alti doi


intregi k si c astfel ca a = c * b^k ( b este un divizor posibil al lui a,
k este ordinul de multiplicitate, c este numarul ramas dupa k impartiri
repetate a lui a prin b). Program pentru descompunerea unui numar dat in
factori primi (cu puterile lor) folosind functia. Exemplu:
360 = 2^3 * 3^2 * 5^1

P3.4 Functie care determina pozitia valorii maxime intr-un vector. Program
pentru ordonarea unui vector de numere prin determinarea repetata a valorii
maxime dintr-un vector si schimbarea cu ultimul element din vector.

P3.5 Functie care determina semnul unui numar intreg ("sign") si are
rezultat 0 (valoare zero), -1 (numar negativ) sau +1 (numar pozitiv).
Functie care determina numarul cadranului in care se afla un punct de
coordonate intregi date x,y; rezultatul este 0 daca punctul se afla pe
una din axe sau la intersectia axelor. Indicatie: Se face o selectie
("switch") dupa valoarea 3*sign(x)+sign(y). Program de verificare.

P3.6 Functie pentru cautare binara intr-un vector ordonat in doua moduri:
iterativ si recursiv. Cautarea binara se face prin compararea valorii
cautate cu valoarea din mijlocul vectorului cercetat si alegerea primei
sau ultimei jumatati din vector pentru pasul urmator, in functie de
rezultatul comparatiei. Procesul de injumatatire a vectorului se opreste
fie la gasirea valorii cautate, fie la reducerea dimensiunii pana la 1.
Functia primeste ca argumente valoarea cautata, adresa vectorului si
indicii (pozitiile) din vector intre care se cauta.
P3.7 Functii pentru operatii cu multimi de 256 intregi realizate printr-un
sir de 256 de biti (16 intregi fara semn sau 32 de octeti). Bitul k din
sir este 1 daca multimea contine elementul cu valoarea k si este zero
daca multimea nu contine valoarea k. Bitul k din sir se afla in bitul cu
numarul k%16 din intregul k/16 din vectorul de 16 intregi. Operatii
(functii): initializare multime vida, adaugare intreg la multime, verifica
apartenenta unui numar la o multime, afisare multime (intre acolade),
reuniune, intersectie si diferenta de multimi.
Program pentru verificarea acestor functii

P3.8 Functii pentru operatii cu multimi de numere intregi reprezentate


prin vectori neordonati de lungime fixa, in care elementele multimii sunt
grupate la inceputul vectorului, dupa care urmeaza zerouri. Operatii:
initializare multime vida, verificare apartenenta la o multime, adaugare
element la o multime (daca nu exista deja), afisare multime (intre acolade),
reuniune, intersectie si diferenta de multimi. Program pentru verificarea
acestor functii.

P3.9 Functie pentru determinarea divizorilor unui numar intreg dat.


Functie pentru calculul valorii unui polinom cu coeficienti intregi.
P(x)= a[0]*x^n+a[1]*x^(n-1)+ ... +a[n-1]*x + a[n]

Functie pentru determinarea coeficientilor polinomului cat ("b") al


impartirii unui polinom (dat prin coeficientii "a") prin (x-r). Se vor
folosi relatiile de recurenta urmatoare:
b[0]=a[0]; b[k]=a[k]+b[k-1]*r k=1,n-1
Program care determina si afiseaza radacinile unei ecuatii polinomiale
cu coeficienti intregi, aflate printre divizorii termenului liber; se
vor afisa divizorii (cu valori pozitive sau negative) care anuleaza
valoarea polinomului dat. exemplu: x^3+3x^2+2x+6 are ca radacina x=-3
(dar nu are radacinile 2,-2,3). Coeficientul puterii maxime a lui x va fi 1.

P3.10 Functie pentru calculul valorii polinomului de interpolare Lagrange


pentru o valoare data xx folosind relatia :
yy = Suma (y[k]*Prod((xx-x[i])/(x[k]-x[i]) )
Suma pentru k=1,n. Produs pentru i=1,n si i!=k
Program pentru citirea a 2 vectori x si y ce definesc o functie prin n
puncte si calculeaza valorile functiei la mijlocul intervalelor de pe
axa X prin interpolare Lagrange. Se vor afisa coordonatele celor n-1
puncte astfel determinate.

P3.11 Functie pentru inmultirea unui polinom cu coeficienti dati cu un


binom de forma (x+c). Program pentru calculul coeficientilor polinomului
care are ca radacini numerele intregi c[1],c[2],...c[n] (citite ca date
initiale). (Termenul liber trebuie sa fie egal cu produsul r[1]*r[2]*...,
iar coeficientul lui x^(n-1) sa fie egal cu suma r[1]+r[2]+...r[n])
Pentru c[1]=c[2]=..=c[n]=1 coeficientii afisati sunt coeficientii puterii
n a binomului (x+1)

P3.12 Functie recursiva pentru determinarea celui mai mare divizor comun
a 2 intregi, pe baza relatiei cmmdc(a,b) = cmmdc (b,a%b) daca a%b != 0
si cmmdc(a,b) =b daca a%b==0.

P3.13 Functie recursiva pentru afisare in binar a unui intreg primit ca


argument. Algoritm: echivalentul binar al lui m se obtine din echivalentul
binar al lui m/2 urmat de cifra binara m%2. Scrieti si o forma iterativa
pentru acest algoritm de impartiri succesive la 2 si afisare de resturi
in ordinea inversa obtinerii lor.

P3.14 Functie recursiva pentru cautarea secventiala intr-un vector a unei


valori date, cu rezultat pozitia in vector a numarului cautat sau -1 daca
negasit. Rezultatul cautarii intr-un vector a cu n elemente este fie
a[n-1] fie egal cu rezultatul cautarii in primele n-1 elemente (daca n>0).
P3.15 Functie pentru inmultirea a doua matrice patratice cu acelasi numar de linii si coloane. Functie pentru ridicarea
unei matrice patratice la o putere intreaga, prin inmultiri repetate (folosind prima functie). Program pentru verificare pe o
matrice unitate.
P3.16 Functie care schimba intre ele doua linii i si j dintr-o matrice patratica. Program care foloseste functia pentru a
aduce pe diagonala principala numai elemente nenule (daca este posibil). Se va afisa matricea obtinuta prin schimbari de
linii.

Bibliografie
1. D. Lucanu: Bazele proiectarii programelor si algoritmilor, Universitatea “A.I.Cuza” Iasi, 1996
2. L. Livovschi, H. Georgescu: Sinteza si analiza algoritmilor, Ed. Stiintifica si enciclopedica, 1986
3. O. Catrina, I. Cojocaru, Turbo C++, ed. Teora 1993
4. V. Petrovici, Florin Goicea, Programarea in limbajul C. Eed. Teora 1999
5. Liviu Negrescu, ,,Limbajul C” ,volumul I_partea I-a si partea II-a18 18ditura MicroInformatica, Cluj-
napoca 2001
6. Б.Керниган, Д.Ритчи. Язык программирования Си. Санкт-Петербург, 2001,,, Brian Kernighan, Dennis
Ritchie ” The C Programming Language” este în l. română format electronic
7. Indrumar de lucrări de laborator: “Informatica”. /A.Popescu, Ş. Marin / Chisinau. UTM,2003.
8. Vlad Caprariu ”Ghid de utilizare Turbo C” Cluj - Napoca 1993.
9. Cristea Valentin. Tehnici de programare. Ed.: Bucur., Teora, 1993. /681.3; T29/
10. Odagescu Ioan, Copos Cristina s.a. Metode si Tehnici de programare./enunturi, solutii, probleme propuse/
Ed.:Bucur.: INTACT, 1994 /681.3; O23/
11. Tudor Bălănescu. Corectudinea agoritmilor.Bucur.:Ed. Tehn.1995

S-ar putea să vă placă și