Documente Academic
Documente Profesional
Documente Cultură
Functii
O funcţie reprezintă o secvenţă de instrucţiuni care poate fi identificată şi apelată prin intermediul unui
nume. Funcţiile sunt un element foarte important în orice limbaj de programare, deoarece uşurează foarte
mult munca programatorului, eliminând necesitatea scrierii aceluiaşi cod de mai multe ori.
De asemenea, prin folosirea funcţiilor programele pot fi structurate în blocuri, implicând o mai bună
depanare şi modularizare a programelor respective. Utilizarea unei funcţii presupune două elemente
distincte:
- definirea funcţiei;
- apelul funcţiei;
Definirea unei funcţii reprezintă precizarea tipului returnat de funcţia respectivă, a argumentelor funcţiei
şi a tipurilor acestora şi scrierea corpului funcţiei (instrucţiunile care vor fi executate când va fi apelată
funcţia). Forma generală a unei funcţii este următoarea:
tip_dateN argN );
. . .
Corpul functiei ;
. . .
Apelarea unei funcţii constă în folosirea propriu-zisă a funcţiei, într-o altă funcţie. Apelarea se poate face
atât în funcţia principală (main), cât şi într-o altă funcţie.
Returnarea unei valori de către o funcţie se face folosind instrucţiunea return înainte de încheierea funcţiei
respective. De asemenea, instrucţiunea return se poate folosi şi pentru încheierea forţată a execuţiei unei
funcţii. O funcţie poate returna orice valoare dintr-un tip de bază, cu excepţia unui tablou. Dacă funcţia nu
returnează nici o valoare, atunci se consideră că returnează void (tipul vid). Atenţie! dacă nu se specifică
nimic la tipul returnat de funcţie, compilatorul C consideră că funcţia respectivă returnează o valoare de
tip întreg (va fi semnalat un avertisment (warning) – Function should return a value)
int c;
c = a + b;
return c;
int x, y, z;
}Sa se scrie un program care calculeaza valoarea expresiei S=1-2+3-4+....+, folosind functii proprii
#include <stdio.h>
void main()
{
int n;
printf("Introduceti n:");
scanf("%d", &n);
getchar();
int k;
scanf("%d", k);
}
Capitolul 2
Tablouri si Pointeri
Notiunea de pointer
Pointerii au fost introdusi in limbajele de programare pentru a putea rezolva mai eficient anumite
probleme sau pentru a da mai multa claritate anumitor programe.
· variabila
· functie
Fie urmatorul exemplu:
int x;
int *px;
Am definit o variabila de tip intreg x si o variabila pointer, care poate contine adresa unei variabile de tip
intreg. Simbolul * ce apare in stanga variabilei px arata ca px este o variabila pointer.
Prin atribuirea
px=&x;
pointerul va avea ca valoare adresa de memorie alocata variabilei x (vezi laboratorul nr.1, definitia
variabilei). Operatorul unar & este utilizat pentru a se obtine adresa variabilei x (operator unar=are un
singur operand)
Acum putem sa lucram cu continutul variabilei x (i.e cu valoarea acesteia) prin intermediul pointerului
px, deci indirect, fara sa mai folosim variabila x. La prima vedere, aceasta modalitate de lucru poate parea
dificila si nu tocmai utila. Necesitatea utilizarii pointerilor va apare cu mai multa claritate in sectiunea
dedicata sirurilor de caractere si functiilor.
#include <iostream.h>
void main()
In programul de mai sus am introdus valorile variabilelor intregi x si y, am definit un pointer la variabila x
si am atribuit acestuia adresa de memorie alocat variabilei x. Sa analizam atent linia:
Prin *px se intelege valoarea aflata in zona de memorie a carei adresa este memorata in pointerul px.
Valoarea afisata va fi chiar valoarea introdusa pentru x deoarece, inainte de afisare, pointerul px a primit
ca valoare adresa variabilei x, adresa la care se afla valoarea acesteia (valoare dobandita prin utilizarea
functiei cin).
Atribuirea *px=y; va modifica valolarea care se afla la adresa memorata de px, valoare care va fi valoarea
introdusa de utilizator pentru variabila y. Astfel va fi modificata chiar valoarea pe care o are variabila x.
Fireste ca era mai simplu sa folosim atribuirea x=y; care are acelasi efect si ne scuteste de de-a mai folosi
pointeri, insa exemplul este pur didactic.
Operatorul unar * este folosit sub forma *variabila_pointer, valoarea acestei expresii fiind valoarea care
se gaseste in memorie la adresa memorata de pointerul ce apare ca operand. In concluzie, prin px avem
acces la adresa variabilei x, iar prin *px la valoarea variabilei x.
Vom spune ca un pointer “refera” indirect un obiect sau ca “pointeaza”(arata) la obiectul respectiv.
Variabilele pointer pot fi incadrate ca fiind de tip referinta.
#include <iostream.h>
void main()
2. Pointeri si tablouri
In limbajul C, exista o foarte stransa legatura intre pointeri si tablouri, astfel ca pointerii si tablourile sunt
tratate la fel. Orice program in care apar tablouri poate fi modificat astfel incat sa foloseasca poiteri in
locul tablourilor. In aceasta sectiune vom discuta despre legatura dintre pointeri si vectori (tablouri
unidimensionale).
int a[20];
int *pa;
Am declarat o variabila a , care este un vector cu maxim 20 elemente intregi si un pointer la o variabila de
tip intreg. Dupa cum se stie, o valoare int are nevoie de 16 biti pentru a fi memorata, adica 2 bytes ( o
variabila int poate retine numere intregi intre -32768 si 32767, vezi curs Bazele Informaticii). Pentru
tabloul a vor fi alocati 2· 20=40 bytes consecutivi in memorie adica, pentru primul element a[0] sunt
alocati primii 2 bytes, pentru a[1] urmatorii 2 bytes,…, pentru a[19] ultimii 2 bytes din cei 40 alocati.
Fie atribuirea:
pa=&a[0];
Dupa aceasta atribuire, pointerul pa contine adresa primului element al vectorului, adica pa pointeaza la
inceputul vectorului a.
Daca scriem pa=&a[3]; atunci pa va referi elementul al 4-lea din vectorul a, iar *pa va contine valoarea
sa.
· comparatia
se verifica daca adresa memorata de p1 este aceeasi cu adresa retinuta de p2, unde p1 si p2 sunt pointeri
de acelasi tip.
Se poate compara un pointer cu valoarea NULL (sau 0). Un pointer are valoarea NULL (valoare
nedefinita) daca nu refera nici un obiect.
Adunarea unui pointer cu un intreg este definita numai atunci cand pointerul refera un tablou (un element
al tabloului). Scaderea este definita in acelasi caz.
#include <iostream.h>
void main()
pa=&a[0];
for(i=0;i<n;i++)
Prima pate a programului nu contine elemente noi, doar a doua parte meritand atentie. Mai intai
initializam pointerul pa cu valoarea primului element al vectorului a. Ciclul for contine urmatoarele
prelucrari:
· aduna pointerul pa cu 1
Incrementarea pointerului pa are ca efect modificarea adresei memorate in pa. Noua adresa este adresa
zonei de memorie corespunzatoare elementului urmator, o adresa cu 2 bytes mai mare decat precedenta.
Observam ca marirea pointerului cu o unitate inseamna de fapt trecerea la urmatorul element din vector.
Daca vom introduce pentru n o valoare mai mare decat 20 (numarul maxim de elemente ale vectorului,
asa cum reiese din declaratie) atunci pointerul pa va depasi zona de memorie alocata vectorului si va
referi o adresa la care se pot afla date importante pentru program.
#include<string.h>
#include<conio.h>
int k;
putchar(sir[k]);
while(*s)
putchar(*s++);
void main(void){
char sirdat[20];
gets(sirdat);
afiseaza_prin_indici(sirdat);
afiseaza_prin_pointer(sirdat);
getch();
}
Capitolul 3
Structuri si uniuni
O structură este o colecĠie de variabile la care se face referire utilizându-se un singur nume. Datorită
faptului că permit gruparea mai multor variabile (între care există o anumită relaĠie într-un context dat)
úi tratarea lor în mod unitar úi nu ca entităĠi separate, structurile sunt cu succes utilizate în organizarea
datelor complexe .
Variabilele din interiorul structurii se numesc membri sau câmpuri úi pot avea tipuri diferite. Fiecare
membru are la rândul său un nume, utilizat pentru a-l selecta din structură.
Pentru definirea unei structuri se foloseúte cuvântul cheie struct într-o instrucĠiune a cărei formă generală
este : struct nume_structura{
tip 1
var11,
var12;
tip 2
var2;
tip n varn;
} lista_variabile;
Unde:
-nume_structura are caracter optional si este o etichetă prin intermediul căreia tipul de dată tocmai definit
poate fi folosit în continuare pentru declararea unor variabile;
-variabilele de acelasi tip pot fi definite într-o singură instructiune úi vor fi separate prin virgulă (,);
-definirea variabilelor de tipuri diferite se face în instructiuni diferite, separate prin punct si virgulă (;);
-lista_variabile are de asemenea caracter optional si este o listă care declară una sau mai multe variabile
-definirea structurii se încheie cu punct si virgulă (;), această definire fiind, în ansamblu, o instructiune;
-desi atât nume_structura, cât si lista_variabile au caracter optional, ele nu pot lipsi în acelaúi timp; cu alte
cuvinte măcar una dintre ele trebuie să apară pentru că altfel definirea structurii n-ar avea sens (de vreme
ce nici nu s-au declarat variabile, nici nu s-a dat un nume structurii pentru a putea fi folosită ulterior).
Un prim exemplu, foarte simplu, de structură este reprezentat de coordonatele unui punct în plan.
Structura poate fi definită astfel:
struct punct{
int x;
int y;
};
sau:
struct punct{
int x, y;
};
Uniunea
O uniune este o zonă de memorie folosită de două sau mai multe variabile (de obicei de tipuri diferite) la
momente diferite de timp. Se utilizează frecvent atunci când un element are la un moment dat unul ܈i
numai unul din mai multe formate. Definirea ei este similară cu cea a unei structuri, dar folosete cuvântul
cheie union:
union nume_uniune{
tip 2 var2;
tip n varn;
} lista_variable;
Uniunile pot contine structuri si tablouri si, de asemenea, pot apărea în structuri si în tablouri. Dacă o
variabilă membru a unui astfel de element imbricat trebuie accesată, notatia este identică cu cea utilizată
la structuri imbricate. Următorul exemplu declară un vector de elemente imbricate; fiecare locatie a
vectorului e o structură care contine câteva variabile, inclusiv o uniune.
Se va scrie un program C ce va evidenţia diferenţele între folosirea unei structuri şi a unei
uniuni.
a) se va folosi o structură de înregistrări:
#include<stdio.h>
struct exemplu
{
long int a;
char* b;
char* c;
};
void main()
{
exemplu x;
printf("Spatiul ocupat de o variabila la structura: %d\n",sizeof(x));
x.a=10;
x.b="ABCD";
x.c="EFG";
printf("%ld\n",x.a);
printf("%s\n",x.b);
printf("%s\n",x.c);
getchar();
int k;
scanf("%d", &k);
}
printf("%ld\n",x.a);
printf("%s\n",x.b);
printf("%s\n",x.c);
getchar();
int k;
scanf("%d", &k);
}
Capitolul 4
Un mediu integrat de dezvoltare a programelor oferă tehnici şi instrumente care asistă programatorul în
toate fazele elaborării programului: editare, codificare, compilare, testare etc. Într-un astfel de caz se
poate aprecia că o parte din tehnologia care urmează să fie aplicată este intrinsecă mediului de
dezvoltare.
întreţinerea programului: uşurinţa cu care poate fi modificat şi îmbunătăţit ulterior. Pentru a atinge
aceste obiective programatorii au la dispoziţie mai multe pârghii prin intermediul cărora pot acţiona atât
la fazele de proiectare cât şi la cele de programare, testare etc.
Acestea sunt:
- Organizarea datelor: trebuie să concorde cu structura obiectelor din realitatea problemei care se
rezolvă.
- Testarea prin program a unor categorii de erori, de exemplu cele de intrare/ ieşire. Unele limbaje,
inclusiv C, permit astfel de operaţii ceea ce determină îmbunătăţirea robusteşii programelor.
- Alegerea numelor simbolice (identificatorilor) din program astfel încât să se facă o legătură directă cu
semnificaţia utilităţii respective în problema de rezolvat. În acest fel se poate uşura urmărirea şi
înţelegerea programului. -Utilizarea comentariilor: reprezintă cea mai simplă metodă de documentare a
programelor, utilă chiar şi autorilor programului, dacă îl parcurg după un anumit timp. În practica
programării se utilizează linii de comentarii distincte prin care se descriu funcţiile programului, funcţia
fiecărui subprogram, datele de intrare şi cele de ieşire, indicaţii de utilizare a programului etc. De
asemenea, se obişnuieşte ca prelucrările mai importante sau mai dificile din program să fie însoţite de
comentarii explicative.
-Formatul liber de redactare al liniilor sursă. Această facilitate, prezentă în majoritatea limbajelor de
programare moderne, pune în concordanţă textul programului cu organizarea şi semnificaţia sa. În acest
fel creşte lizibilitatea şi claritatea programului
Cu cât problema este mai complexă, trecerea de la enunţul problemei la program se face mai anevoios.
În aceste situaţii este util ca atât elaborarea algoritmului cât şi scrierea programului să se facă treptat,
într-un proces de detaliere succesivă a rezolvării problemei. Stilul de lucru corespunzător s-a concretizat
într-o metodă de proiectare-programare descendentă (top-down) numită metoda detalierilor în paşi
succesivi (step wise refirement). În această metodă se porneşte de la general, elaborând mai întâi
programul principal (pasul 1). Astfel se proiectează şi se descriu, în limbajul de implementare ales,
principalele date ale programului (cele de la nivelul programului principal), iar funcţiile apelate din
programul principal sunt doar enunţate: numele şi lista de parametrii formali. În continuare, prin
detalieri (rafinări) succesive (paşii 2, 3, …) se dezvoltă funcţiile apelate direct din programul principal
(pasul 2), apoi funcţiile apelate din acestea din urmă (pasul 3) ş.a.m.d., până la elaborarea în amănunt a
întregului program. Caracteristica esenţială a acestui mod de rafinare a programului este următoarea: în
fiecare pas se dezvoltă funcţiile care au apărut (fiind doar enunţate) în pasul anterior; dacă operaţiile
implementate în pasul curent sunt suficient de complexe, este posibil să fie enunţate noi funcţii care vor
fi dezvoltate (detaliate) în pasul următor.
Capitolul 5
Programarea avansata
Un program C este compus dintr-o ierarhie de funcţii, orice program trebuind să conţină cel puţin
funcţia main, prima care se execută la lansarea programului C. Funcţiile pot face parte dintr-un singur
fişier sursă sau din mai multe fişiere sursă. Un fişier sursă C este un fişier text care conţine o succesiune
de funcţii şi, eventual, declaraţii de variabile.
-directive preprocesor
-definiţii de tipuri
-prototipuri de funcţii
-definiţii de funcţii
-Un identificator este o secvenţă de caractere, de o lungime maximă ce depinde de compilator (în
general are maxim 255 de caractere). Secvenţa poate conţine litere mici şi mari(a-z, A-Z), cifre (0-9) şi
simbolul '_' (underscore, liniuţa de subliniere).
-Primul caracter trebuie să fie o literă sau '_'. Pentru că multe nume rezervate de compilator, invizibile
programatorului, încep cu '_', este indicat a nu utiliza '_' pentru începutul numelor utilizator.
-Un identificator nu poate fi un cuvânt cheie (int, double, if, else, for).
-Deoarece limbajul C este case-sensitive identificatorii sunt şi ei la rândul lor case-sensitive. Astfel, suma
nu este Suma şi nici SUMA.
-Identificatorii sunt atomi lexicali, în cadrul lor nu e permisă utilizarea spaţiilor albe şi a altor caractere
speciale (ca +, -, *, /, @, &, virgulă, etc.) putem însă folosi caracterul '_'.
-nedefinit (void)
#include <stdio.h>
void main(){
unsigned short c;
for(c=0;c<=255;c++)
switch(c){
case 7 : printf("b%3uł",c);break; // beep
case 8 : printf("B%3uł",c);break; // back space
case 9 : printf("T%3uł",c);break; // tab
case 10 : printf("L%3uł",c);break; // line feed
case 13 : printf("R%3uł",c);break; // return
case 27 : printf("E%3uł",c);break; // escape
default : printf("%c%3uł",c,c); // caractere afisabile
};
}
Capitolul 6
Fisiere
Pentru a deschide un fisier la acest nivel de prelucrare a fisierelor se utilizeaza functia fopen. Ea
returneaza un pointer spre tipul FILE (tipul fisierului) sau pointerul nul in caz de eroare. Prototipul functiei
este urmatorul:
unde: - calea – are aceeasi semnificatie ca si in cazul functiei open adica este un pointer spre un sir de
caractere care defineste calea spre fisierul care se deschide;
- mod – este un pointer spre un sir de caractere care defineste modul de prelucrare al fisierului
dupa deschidere, acest sir de caractere se defineste astfel:
Daca se deschide un fisier existent in modul w, atunci se va crea din nou fisierul respectiv si vechiul
continut al sau se va pierde.
Deschiderea unui fisier in modul a permite adaugarea de inregistrari dupa ultima inregistrare
existenta in fisier.
Fisierele pot fi scrise si citite caracter cu caracter folosind doua functii simple
- fp – un pointer spre tipul FILE a carui valoare a fost returnata de functia fopen la deschiderea
fisierului in care se face scrierea; In particular fp poate fi (stdont, stderr, stdprn, stdaux).
unde: - fp – un pointer spre tipul FILE a carui valoare a fost definita la apelul functiei fopen. In
particular fp poate fi (stdin, stdoux).
Dupa terminarea prelucrarii unui fisier, acesta urmeaza a fi inchis. Inchiderea unui fisier se
realizeaza cu ajutorul functiei fclose de prototip:
- -1 –la eroare.
Biblioteca standard a limbajului C contine functiile fgets si fputs care permit citirea, respectiv
scrierea, inregistrarilor care sunt siruri de caractere.
unde: - s –este pointerul spre zona in care se pastreaza caracterele citite din fisier;
- fp –este pointerul spre tipul FILE a carui valoare s-a definit la deschiderea fisierului.
Citirea caracterelor se intrerupe la intalnirea caracterului “n” sau dupa citirea a cel mult n-1
caractere. In zona spre care pointeaza s se pastreaza caracterul “n” daca acesta a fost citit din fisier, iar apoi
se memoreaza caracterul nul (“ 0”). In mod normal, functia returneaza valoarea pointerului s. La intalnirea
sfarsitului de fisier functia returneaza valoarea 0.
unde: - s – este pointerul de la inceputul zonei de memorie care contine sirul de caractere care se scrie in
fisier.
- fp – este pointerul spre tipul FILE a carui valoare a fost definita la deschiderea fisierului prin
apelul fopen.
Functia fputs returneaza codul ASCII al ultimului caracter scris in fisier sau –1 la eroare.
Biblioteca standard a limbajului C contine functii care permit realizarea operatiilor de I/O cu format.
In acest scop se pot utiliza functiile fscanf, fprintf.
Acestea sunt similare cu functiile sscanf, respectiv sprintf. Diferenta dintre ele consta in faptul
ca fscanf si fprintfau ca prim parametru un pointer spre tipul FILE, iar sscanf si sprintf au ca prim parametru
un pointer spre o zona in care se pastreaza caractere. Astfel fscanf citeste date dintr-un fisier si le
converteste, in timp ce sscanf realizeaza acelasi lucru dar utilizand date din memorie.
Functia fprintf converteste date din format intern in format extern si apoi le scrie intr-un fisier, spre
deosebire de functia sprintf care realizeaza acelasi lucru dar rezultatele se pastreaza in memorie.
unde: - fp – este pointer spre tipul FILE a carui valoare a fost definita prin apelul functiei fopen.
Limbajul C contine functia fseek care permite deplasarea capului de citire-scriere al discului in vederea
prelucrarii inregistrarilor fisierului intr-o ordine diferita de cea secventiala.
unde: - fp – este pointer spre tipul FILE care defineste fisierul in care se face pozitionarea capului de citire-
scriere.
unde: - calea – este pointer spre un sir de caractere identic cu cel utilizat la crearea fisierului in
functia fopen.
1.Sa se scrie un program care afiseaza lungimea celei mai lungi linii din fisierul text
TEST:
/*------------------------------------------------*/
/* */
/* afiseaza lungimea lg_max a celei mai lungi */
/* linii a fisierului */
/* */
/*------------------------------------------------*/
#include <stdio.h>
void main(void)
{
FILE *f;
char c;
int lg_max, lg_curenta;
lg_max=lg_curenta=0;
if (!(f=fopen("TEST", "r")))
{
puts("Fisierul TEST nu poate fi deschis");
return;
}
while ((c=getc(f))!=EOF)
if (c=='\n')
{
if (lg_max<lg_curenta)
lg_max = lg_curenta;
lg_curenta = 0;
}
else
lg_curenta++;
fclose(f);
printf ("\nLinia cea mai lunga are lungimea %d", lg_max);
}
Capitolul 7
Recursivitate
1. o formulă de recurenţă;
Un exemplu de recursivitate este în definirea formală a numerelor naturale din cadrul teoriei mulțimilor:
- baza recursiei este faptul că 1 este număr natural;
- în plus, orice număr natural are un succesor, care este de asemenea un număr natural.
• formulă de recurenţă = formulă care exprimă orice termen dintr-un şir, în funcţie de termenii
precedenţi;
Se numeşte funcţie recursivă o funcţie care din corpul ei se apelează pe ea însăţi. Un subprogram se
numeşte recursiv dacă se autoapelează. Orice funcţie recursivă trebuie să îndeplinească două condinţii:
1. să se poată executa cel puţin o dată fără să se autoapeleze;
2. toate apelurile să se producă astfel încât să se tindă spre îndeplinirea condiţiei de execuţie fără
apeluri.
Competenţe specifice
• aplicarea mecanismului recursivităţii prin crearea unor subprograme recursive (definite de utilizator)
Din afara funcţiei recursive, se face un prim apel la funcţia recursivă, după care funcţia se autoapeleză
de un anumit număr de ori. Pentru orice algoritm iterativ există un algoritm recursiv echivalent (rezolvă
acceaşi problemă) şi invers, pentru orice algoritm recursiv există unul iterativ echivalent
1 Să se scrie un program C, pentru rezolvarea cmmdc-ului dintre două numere întregi fără semn (pentru
determinarea cmmdc-ului vom folosi algritmul lui Euclid prin scăderi). Varianta recursive
#include <stdio.h>
#include <conio.h>
getch();
}
Capitolul 8
Metode generale
Elaborarea algoritmilor
Prin elaborarea (proiectarea) unui algoritm intelegem intreaga activitate depusa de la enuntarea
problemei pana la realizarea algoritmului corespunzator rezolvarii acestei probleme.
- specificarea problemei;
Exista doua metode generale de proiectare a algoritmilor, a caror denumire provine din modul de
abordare a rezolvarii problemelor: metoda descendenta si metoda ascendenta. Proiectarea
descendenta (top-down) porneste de la problema de rezolvat, pe care o descompune in parti rezolvabile
separat. De obicei aceste parti sunt subprobleme independente, care la randul lor pot fi descompuse in
subprobleme. La prima descompunere accentul trebuie pus pe algoritmul (modulul) principal nu asupra
subproblemelor. La acest nivel nu ne intereseaza amanunte legate de rezolvarea subproblemelor, presupunem
ca le stim rezolva, eventual ca avem deja scrisi subalgoritmi pentru rezolvarea lor. Urmeaza sa consideram pe
rand fiecare subproblema in parte si sa proiectam (in acelasi mod) un subalgoritm pentru rezolvarea ei. In final,
se va descrie subalgoritmul de rezolvare al fiecarei subprobleme, dar si interactiunile dintre acesti subalgoritmi si
ordinea in care ei sunt folositi.
Notiunea de modul va fi definita in sectiunea urmatoare. Deocamdata intelegem prin modul orice
subalgoritm sau algoritmul principal. Legatura dintre module se prezinta cel mai bine sub forma unei diagrame
numita arbore de programare. Fiecarui modul ii corespunde in arborele de programare un nod, ai carui
descendenti sunt toate modulele apelate direct. Nodul corespunzator algoritmului principal este chiar nodul
radacina.
Arbore de programare
+---------+
| PRINC |
+---------+
+-------+ | +-------+
| | |
+------+ | +---+
| M1 | | M2 | | M3 |
In multe carti metoda top-down este intalnita si sub denumirea stepwise-refinement, adica rafinare
in pasi succesivi. Este vorba de un proces de detaliere pas cu pas a specificatiei, denumit proiectare
descendenta. Algoritmul apare in diferite versiuni succesive, fiecare fiind o detaliere a versiunii precedente.
Scopul urmarit este acelasi: concentrarea atentiei asupra partilor importante ale momentului si amanarea
detaliilor pentru mai tarziu. Daca ar fi necesar sa le deosebim am spune ca metoda top-down se refera la nivelul
macro iar metoda rafinarii succesive la nivel micro. La nivel macro se doreste descompunerea unei probleme
complexe in subprobleme. La nivel micro se doreste obtinerea unui modul in versiune finala. I
Programarea structurata este un stil de programare aparut in urma experientei primilor ani de activitate. Ea
cere respectarea unei discipline de programare si folosirea riguroasa a catorva structuri de calcul. Ca rezultat se
va ajunge la un algoritm usor de urmarit, clar si corect.
Termenul programare, folosit in titlul acestei sectiuni si consacrat in literatura de specialitate, este folosit
aici in sens larg si nu este identic cu cel de programare propriu-zisa. Este vorba de intreaga activitate depusa
pentru obtinerea unui program, deci atat proiectarea algoritmului cat si traducerea acestuia in limbajul de
programare ales.
Bohm si Jacopini au demonstrat ca orice algoritm poate fi compus din numai trei structuri de calcul:
- structura secventiala;
- structura alternativa;
- structura repetitiva.
Knuth considera programarea structurata ca fiind un mijloc de a face produsele program mai usor de citit. De
asemenea, programarea structurata este definita ca fiind programarea in care abordarea este top-down,
organizarea muncii este facuta pe principiul echipei programatorului sef, iar in proiectarea algoritmilor se
folosesc cele trei structuri de calcul definite de Bohm-Jacopini.
La nivel micro programarea structurata este cea in care autorul este atent la structura fiecarui modul in
parte, cerand claritate si ordine in scriere si respectarea structurilor de calcul definite mai sus.
In acest scop am definit limbajul Pseudocod, care are structurile de calcul mentionate. Schemele logice
obtinute dintr-o descriere in Pseudocod a unui algoritm, conform semanticii propozitiilor Pseudocod, se
numesc D-scheme (de la Dijkstra) sau scheme logice structurate.
1 Un program muzical
#include <stdio.h>
#include <dos.h>
#include <conio.h>
main(){ /* Do do# Re re# Mi Fa fa# sOl sol# La la# Si */
int octava[]={65 , 69 , 73 , 78 , 82 , 87 , 92 , 98 , 104 , 110 , 116 , 123};
int i,j,nr_octava,i_nota,timp=500;
float masura,durata,durata_masura;
char *linia="42$2R2R4M4F2O2L1R2R2S2S4L4O2O2"; //$4D2D4$3S4L2";
do{
masura=(float)(linia[0]-'0')/(linia[1]-'0');durata_masura=0;
for(i=2;linia[i]!='\0';i++){
if (i%2==0){
switch(linia[i]){
case '$' : {nr_octava=1;for(j=linia[++i]-'0';j>0;j--)nr_octava*=2;}
break;
case 'D' : i_nota=0;break;
case 'd' : i_nota=1;break;
case 'R' : i_nota=2;break;
case 'r' : i_nota=3;break;
case 'M' : i_nota=4;break;
case 'F' : i_nota=5;break;
case 'f' : i_nota=6;break;
case 'O' : i_nota=7;break;
case 'o' : i_nota=8;break;
case 'L' : i_nota=9;break;
case 'l' : i_nota=10;break;
case 'S' : i_nota=11;break;
}
} else {
if (linia[i]=='6') durata=1/16; else durata=1/(float)(linia[i]-'0');
durata_masura+=durata;
if (durata_masura>masura) { nosound();durata_masura=0;}
sound(nr_octava*octava[i_nota]);
delay(durata*timp);
} /* else */
} /* for */
} /* do */
while (!kbhit());
nosound();
}