Sunteți pe pagina 1din 10

CURS 2. Etapele realizrii unui program. Instructiuni preprocesor.

Afisarea la ecran si citire de la tastatura


2.1. Etapele realizrii unui program

Realizarea unui program presupune implicarea mai multor etape. Aceste etape sunt independente de limbajul de
programare utilizat i implic existen ctorva restricii cu privire la computerul/limbajul utilizat.Etapele
realizrii unui program sunt:
1. Studierea detaliat a cerinelor aplicaiei. Este foarte important ca cerinele impuse de aplicaie s fie foarte
bine explicitate. Adic nainte de a trece la realizarea unui program pentru o anumit aplicaie trebuie ca cea
aplicaie sa fie foarte bine analizat i cerinele pe care aceasta le impune trebuie s fie complete i consistente.
De exemplu o cerin de genul scrie un program care sa rezolve ecuaiile este evident c este incomplet i se
impun ntrebri de genul ce tip de ecuaii, cte ecuaii, care este precizia, etc.
2. Analiza problemei i determinarea rezolvrii acesteia. In aceast etap se decide asupra unei metode de
rezolvare a problemei (algoritm).
3. Traducerea algoritmului realizat la etapa anterioar ntr-un limbaj de programare evoluat corespunztor. Forma
scris a acestui program este denumit program surs (PS, source program sau source code). n aceast etap
programul trebuie citit i verificat pentru a i se stabili corectitudinea. Aceasta se face prin introducerea unui set
de valori i verificarea dac programul furnizeaz valorile corespunztoare corecte. Odat verificat programul
este scris ntr-un anumit limbaj prin intermediul unui Editor.

4. Compilarea programului n limbaj main. Astfel programul obinut n limbaj main se numete cod obiect
(object code). n aceast etap compilatorul poate determina erori de sintax ale programului. O eroare de
sintax este o greeal n gramatica limbajului. De exemplu n C trebuie ca fiecare linie s se termine cu ;
Dac se uit plasarea ; atunci compilatorul va semnala eroarea de sintax. Astfel se repet compilarea pn la
eliminarea tuturor erorilor de sintax.

5. Programul obinut n urma compilrii, object code, este apoi corelat (linked) cu o serie de biblioteci de funcii
(function libraries) care sunt furnizate de sistem. Toate acestea se petrec cu ajutorul unui program numit linkeditor (linker) iar apoi programul linked object codeeste ncrcat n memoria computerului de ctre un program
numit loader.

6. Rularea programului compilat, link-editat i ncrcat cu un set de date pentru testare. Astfel se vor pune n
eviden erorile de logic ale programului. Erorile de logic sunt erori care sunt produse de metoda de
rezolvare a problemei. Astfel dei programul este scris corect din punct de vedere al sintaxei acesta poate
executa ceva ce este incorect n contextul aplicaiei. Poate fi ceva simplu, de exemplu realizarea unei operaii
de scdere n loc de adunare. O form particular a erorilor de logic este apariia erorilor de rulare (run-time
error). O eroare de rulare va produce o oprire a programului n timpul execuiei pentru c nu anumite
instruciuni nu pot fi realizate. De exemplu o mprire la zero sau ncercarea de accesare a datelor dintr-un
fiier inexistent.

Astfel se impune ca n aceast etap programul s fie reverificat i apoi erorile s fie recorectate prin
intermediul editorului ceea ce impune ca etapele 3,4, i 5 s fie repetate pn la obinerea rezultatelor
satisfctoare.
7. Programul poate fi pus n execuie pentru rezolvarea problemei pentru care a fost conceput. Este posibil ca pe
parcursul execuiei sale s se mai depisteze anumite erori de logic. Astfel se impune reformularea algoritmului
i reluarea etapelor de realizare a programului.
Programul poate fi rulat in mod debug adic pas-cu-pas pentru a putea verifica execuia punctual a fiecrei
variabile. In acest sens, in mod debug, putem insera breakpoints, iar programul va rula pana la intalnirea acestora,
sau putem executa programul pana la linia unde se afla cursorul.
Pentru executia pas cu pas, avem 2 optiuni:
- Step-in care permite intrarea si execuia pas-cu-pas in funciile din linia curent
- Step-over care permite executia intr-un singur pas (totul o sigura data) a funciilor din linia curent de
cod.
La executia in mod debug avem activat fereastra Watch in care putem solicita afisarea valorilor pentru variabilele
din program.
Prezentm mai jos schema unui compilator.

Program
surs

Sir de atomi
lexicali

Analiza
lexical

Arbore
sintactic

Analiza
sintactic

Cod
intermediar

Analiza
semantic

Cod intermediar
optimizat

Optimizare
de cod

Generare de
cod

Program
obiect
Tratarea
erorilor

Gestiunea
tabelelor

Analiza

Sinteza

n procesul de comunicare om-calculator intervine un program intermediar, translatorul, care asigur


traducerea programelor scrise de utilizator din cod surs ntr-un alt limbaj mai apropiat de calculator.
Dac limbajul int este codul main, translatorul se numete compilator.
Astfel, execuia unui program surs se realizeaz, n cadrul limbajelor compilative, se face n 2 faze:
- compilare, care traduce codul surs n program obiect
- execuie, care ruleaz codul obiect pe calculator, folosind datele iniiale ale programului i produce rezultate
Conceptual, compilatorul realizeaz dou mari clase de operaii: analiza textului surs i sinteza codului obiect.
Compilatorul unui limbaj de asamblare se numete asamblor.
n practic, pe lng compilatoarele obinuite, exist i alte tipuri de compilatoare.
Astfel, preprocesoarele sunt translatoare care traduc dintr-un limbaj de nivel nalt n alt limbaj de nivel nalt.

2.2.Funcii de intrare/ieire
Funcia printf
convertete, formateaz i tiprete argumentele sale la ieirea standard sub controlul irului de control. Este o
funcie de bibliotec care realizeaz ieiri cu format ( in stdio.h).
Formatul general al acestei instruciuni este:
printf(control,param1, param2, ..., paramn);
control este un ir de caractere ce conine 2 tipuri de obiecte:
1)caractere ordinare care sunt simplu copiate n irul de ieire
2)semnificaii de conversie care cauzeaz conversia i tiprirea urmtoarelor argumente succesive ale lui printf.
param1, param2, , paramn sunt expresii ale cror valori se scriu conform specificatorilor de format
prezenti in parametrul de control.
Un specificator de format ncepe prin caracterul % i se ncheie prin caracterul de conversie. ntre caracterul % i
caracterul de conversie pot aprea:
o semnul minus care specific cadrarea la stnga n cmp a argumentului convertit
3

o un ir de cifre zecimale optional, care specific dimensiunea minim a cmpului n care se editeaz data.
Dac data necesit mai puine poziii dect cmpul descris de acest ir atunci el va fi completat la stnga cu
caractere nesemnificative (sau la dreapta dac s-a folosit semnul minus n specificatorul de format
respectiv). Caracterele nesemnificative implicite sunt spaiile. Dac irul de cifre ncepe cu un zero
nesemnificativ, caracterele nesemnificative vor fi zerouri.
o Un punct opional separ irul de cifre ce definete dimensiunea minim a cmpului de irul urmtor de
cifre ce semnific precizia
o un ir de cifre ce definete precizia care specific numrul maxim de caractere acceptate dintr-un ir de
caractere sau numrul de zecimale care se vor scrie n cazul numerelor reale.
Deci semnificaiile de conversie au structura:
%[-][sir_de_cifre][.][sir_de_cifre]c
Caracterul de conversie c poate avea urmtoarele valori:
Car
Semnificaie
d
Data se convertete din int n ntreg zecimal cu semn
i
ntreg zecimal cu semn
o
Data se convertete din int n ntreg octal fr semn
x
Data se convertete din int n ntreg hexagesimal fr semn (cu litere mici)
X
Data se convertete din int n ntreg hexagesimal fr semn (cu litere mari)
u
Data de convertete din unsigned n ntreg zecimal fr semn
c
caracter
s
ir de caractere
e
numr n virgul flotant sau flotant dubl precizie i e convertit n zecimal sub forma: [-]
m.nnnnnn e []xx.
Implicit numrul de zecimale este 6 iar dac se specific precizia, numrul de zecimale va fi
indicat de aceasta.
E
analog dar se folosete E
f
numr n virgul mobil simpl sau dubl precizie iar argumentul va fi convertit n notaie
zecimal
g
n acest caz se va folosi forma cea mai scurt dintre %e i respectiv %f
G
forma cea mai scurt dintre %E i respectiv %f
p
afieaz un pointer (o adres)
n
plaseaz n argumentul asociat numrul de caractere afiat pn n acel moment de funcia
printf
Exemple:
"%5f" arat ca numrul are o lungime de cel puin 5 caractere
%05d determin umplerea cu zerouri a unui numr mai mic de 5 cifre, astfel nct lungimea total s fie 5
"%.2f" solicit dou poziii dup punctul zecimal, dar lungimea lui nu este supus restriciilor
%-5.2f determin afiarea pe cel puin 5 poziii din care exact 2 zecimale aliniat la stnga (datorit prezentei
semnului -)
%.0f suprim tiprirea prii fracionare
%5.10s determin afiarea unui ir pe cel puin 5 poziii dar nu mai mult de 10 caractere
%% determin afiarea caracterului %
printf(Folosim%n caracterul %%n,&p); //determin ncrcarea n variabila
//pointat de pointerul p a valorii 7 (Folosim are 7 litere)
4

Exist posibilitatea de a utiliza doi modelatori de format pentru a afia ntregi de tip short i long. Aceti doi
modelatori sunt h i l. Se folosete %hd pentru a tipri un short int i %ld pentru a tipri un long int.
Modelatorul L se aplic numerelor n virgul mobil permind afiarea unui long double. Astfel, se folosete L n
faa caracterului de conversie e, f sau g.
Prezena modelatorului # n faa caracterului de conversie g, G, f, e sau E determin afiarea unui punct zecimal
chiar dac nu exist cifre zecimale.

Funcia scanf
Citete date de la intrarea standard pe care le convertete n format intern conform specificatorilor. Prototipul
funciei scanf se gsete n headerul stdio.h i are forma:
scanf(control,param1, param2, ..., paramn);
Funcia scanf returneaz numrul cmpurilor citite sau EOF dac se ntlnete prematur marca de sfrit de fiier
(detalii despre EOF la capitolul despre fisiere).
irul de control poate conine 3 tipuri de obiecte: specificatori de format, caractere albe sau alte caractere.
Specificatorul de format este precedat de caracterul % i specific tipul valorii ce urmeaz a fi citite. Acetia sunt
identici cu cei prezentai la funcia printf.
Un caracter alb n irul de control determin neglijarea unuia sau mai multor caractere albe din intrare. Un caracter
care nu este alb determin ca scanf s citeasc i s neglijeze caracterul respectiv din intrare.
Exemplu:
scanf(%d,%d,&a,&b);//determin citirea unui ntreg, apoi caracterul virgul care se neglijeaz i n final
citirea unui alt ntreg
Dac caracterul specificat nu se gsete n intrare, se termin execuia funciei scanf. Toate variabilele a cror
valori se citesc cu funcia scanf trebuie transmise prin adres. Astfel, pentru variabilele simple se folosete
operatorul &.
Pentru un ir de caractere citit cu %s se poate scrie doar numele irului. Un element de tablou precum a[i] se poate
citi folosind &a[i] sau simplu folosind a+i.
Datele din intrare trebuie separate prin caractere albe. Caracterele de punctuaie punct, virgul i punct i virgul
nu sunt considerate separatori. Caracterele albe sunt folosite ca i separatori dar pot fi citite i ca orice caractere
folosind codul de format %c.
Caracterul * plasat dup % i nainte de litera de format determin citirea datei de tipul respectiv dar nu se
asigneaz nici unei variabile.
Exemplu:
scanf(%d%*c%d,&x,&y);
-dac n intrare vom avea 10/20 va determina citirea n variabila x a valorii 10, citirea caracterului / care nu
se aloc nici unei variabile dup care variabilei y i se atribuie valoarea 20.
n specificatorul de format poate fi indicat lungimea maxim a cmpului care poate fi citit.
Exemplu:
scanf(%2d%3d,&x,&y); //dac n intrare avem 121234 atunci x=12, y=123
dup care urmtoarea instruciune scanf:
5

scanf(%d,&z); //va conduce spre z=4.


Un numr se consider citit complet cnd s-a ntlnit un caracter care nu poate participa la scrierea numrului
respectiv sau cnd s-a luat din zon numrul de caractere specificat n format.
n cazul irurilor de caractere, scanf citete pn la ntlnirea primului spaiu alb. n cazul n care se dorete citirea
unui ir de caractere pn la ntlnirea caracterului sfrit de rnd, se va folosi funcia gets().
Specificatorul %n determin ca funcia scanf s atribuie variabilei spre care indic argumentul corespunztor
numrul de caractere citit din stream-ul de intrare pn n momentul ntlnirii specificatorului %n.
O facilitate a funciei scanf este aa-numitul scanset. Scanset definete o list de caractere ce vor fi selectate de
scanf i memorate ntr-o variabil de tip tablou de caractere. Cnd se ntlnete un caracter ce nu apare n
scanset, scanf pune caracterul null la sfritul irului de caractere corespunztor i trece la urmtorul cmp.
Scanset se indic ntre paranteze drepte. Pentru specificarea unui interval n scanset se poate utiliza caracterul deci
[0123456789] este echivalent cu [0-9]. Pentru litere mici i mari se poate folosi [a-zA-Z], iar [^0-9] nseamn orice
caractere n afara cifrelor.
Exemplu:
#include<stdio.h>
int main()
{ char s1[80], s2[80];
scanf(%[0123456789]%s,s1,s2);
}
Efectul acestui program este citirea unui ir de cifre n irul de caractere s1 iar la ntlnirea primului caracter care
nu este cifr se trece la citirea irului de caractere n s2 pn la ntlnirea primului caracter alb.

2.3.Funcii de citire/scriere caractere


int getchar(void)
n stdio.h
Efect: Funcia ateapt apsarea unei taste citind de la intrarea standard codul ASCII al caracterului din poziia
curent i returnnd codul ASCII al acestuia (tipul valorii returnate este int) sau constanta simbolic EOF dac s-a
ntlnit marca de sfrit de fiier (perechea CTRL/Z, detalii in cap. destinat fisierelor). Tasta apsat are automat
ecou pe ecran.
Exemplu:Se citeste o litera mare din fisierul de intrare si se rescrie ca litera mica.
#include <stdio.h>
int main()
{
putchar(getchar()-A+a);
}
Exemplu: Se testeaza daca s-a citit o litera mare si numai in acest caz se aplica transformarea in litera mica. In
cazul in care la intrare nu se afla o litera mare, se rescrie caracterul respectiv.
#include <stdio.h>
int main()
{
6

int c;
putchar(((c=getchar())>=A&&c<=Z)?c-A+a:c);
}

int putchar(int c)
n stdio.h
Efect: afieaz caracterul al crui cod ASCII este egal cu valoarea expresiei dintre paranteze; returneaz codul
ASCII al caracterului scris la ieirea standard sau EOF la detectarea unei erori. Se folosete pentru a scrie un singur
caracter n fiierul standard de ieire n poziia curent a cursorului.
Exemplu:
putchar(a); //trimite la ieirea standard caracterul a
putchar(\n); //trimite la ieirea standard codul \n care are ca efect trecerea
//cursorului pe linia urmtoare n prima coloan
putchar(A+10);//scrie caracterul de cod A + 10 =65+10=75 adica litera K

2.4 Compilare si Precompilare


Fisierul este unitatea de compilare. Un program poate fi compus din mai multe fisiere care se compileaza, iar
fiecare fisier care se compileaza trebuie sa aiba extensia c. Compilatorul trateaz diferit fisierele care au extensia c
de fisierele care au extensia cpp. De accea este absolut necesar ca pentru a se invoca compilatorul corect fisierele
sa aiba extensia C.
Fiecare fisier al programului este compus din funcii. Fiecare funcie se compileaz separat i pentru acestea se
genereaz cod obiect. La compilare se genereaza cod obiect pentru toate functiile din program.
Dupa compilare umeaza linkeditarea care colectezeaza toate codurile compilate ale functiilor utilizate in program
(inclusiv a celor referite prin include-uri de funcii system) si apoi se creaza prima imagine a zonei de memorie de
date si cod a programului
Compilatorul C conine un preprocesor capabil s fac substituii lexicale, macroinstruciuni, compilri
condiionate i includeri de fiiere.
Prepocesorul execut operaii anterioare compilrii propriu-zise, operaii ce sunt specificate prin directive
preprocesor. Preprocesorul este apelat automat nainte de a ncepe compilarea.
Preprocesorul limbajului C este relativ simplu i el, n principiu, execut substituii de texte.
Prin intermediul lui se pot realiza:
- Includeri de texte;
- Definiii i apeluri de macrouri simple;
- Compilare condiionata.
Acestea au ntotdeauna ca i prim caracter simbolul # i permit efectuarea de manipulri n textul programului
surs naintea compilrii sale.
Liniile care ncep cu simbolul # au o sintax independent de restul limbajului, pot aprea oriunde n cadrul
programului surs (dar se recomand plasarea la nceputul lui) i au efecte cu remanen pn la sfritul execuiei
programului sau pn cnd o nou directiv anuleaz acest lucru. Fiecare din directivele preprocesor trebuie s se
gseasc pe o linie separat.
7

Substituia lexical se face prin directiva:


#define identificator [text]
Dac identificatorul este recunoscut ca element lexical n analiza programului surs, preprocesorul va nlocui toate
apariiile ulterioare ale identificatorului cu secvena text precizat. Dac textul trebuie s se extind pe mai multe
linii, liniile intermediare vor fi precedate de un caracter \. Textul poate fi i vid ceea ce va avea ca i efect
suprimarea din textul surs a tuturor apariiilor identificatorului. Pentru a distinge mai uor identificatorul
substituit, se recomand folosirea majusculelor.
Exemple:
#define
#define
#define
#define
#define

void
//suprimarea din textul surs a tuturor apariiilor identificatorului void
then
//suprimarea tututor apariiilor identificatorului then
begin { //nlocuirea identificatorului begin cu {
end } // nlocuirea identificatorului end cu }
N 100 //nlocuiete identificatorul N cu valoarea 100

O dat fcut o substituie lexical, ea poate fi folosit ca parte a unei alte substituii lexicale. Astfel, avnd ultima
substituie lexical din exemplul precedent, este corect s scriem:
#define NPATRAT N*N
Un identificator care a apare deja ntr-o linie #define poate fi ulterior redefinit ulterior n program cu o alt linie
#define. Preprocesorul va substitui n continuare identificatorul cu noua definiie a lui.
Substituirea nu se face n cazul n care identificatorul apare ntre ghilimele, n acest caz el nejucnd practic rolul
unui identificator.
Exemplu:
#define PI 3.14

printf(valoarea lui PI are un numar infinit de zecimale!\n);

n acest caz, nu se face expandarea.


Macroinstruciuni
Sunt substituii cu parametri formali i se realizeaz cu ajutorul directivei:
#define identificator(lista_param_formali) text
Parametri formali sunt nlocuii de cei din lista parametrilor reali. Nu trebuie s existe nici un spaiu ntre
identificator i lista_param_formali.
Exemple:
#define max(a,b) (a)>(b)?(a):(b)
#define abs(a) (a)<0?-(a):(a)
8

Se obine o scriere asemntoare unui apel de funcie dar care este tratat mai direct prin nlocuire n textul surs i
nu printr-un apel de funcie ceea ce este mai avantajos din punct de vedere al performanelor de vitez.
Macroinstruciunile se execut mai repede dect funciile lor echivalente deoarece compilatorul nu necesit
depunerea pe stiv a parametrilor i apoi returnarea valorilor. Avnd n vedere c macroinstruciunile mresc
dimensiunea codului, este indicat a ne limita doar la calcule simple pentru a nu crete talia programului.
Se remarc utilizarea parantezelor rotunde la ncadrarea parametrilor formali. Dac acestea sunt omise, evaluarea
se poate face eronat dac parametri formali sunt substituii de expresii.
Exemplu:
#include<stdio.h>
#define PAR(a) a%2==0?1:0
//ncercm folosirea macroinstruciunii fr paranteze rotunde
int main()
{ if PAR(9+1)) printf(este par\n);
else printf(este impar\n);
}
Efectul utilizrii n acest mod a macroinstruciunii este eronat deoarece:
9+1%2= =0 va conduce la 9+0 = =0 adic fals ceea ce va genera mesajul este impar n loc s obinem mesajul
este par.
Cauza este lipsa parantezelor la definirea macroinstruciunii. Utilizarea sub forma:
#define PAR(a) (a)%2= = 0?1:0 va conduce spre un rezultat corect deoarece:
(9+1)%2= = 0 conduce spre 0 = = 0 ceea ce este adevrat iar mesajul generat va fi este par.
Includerea fiierelor se face prin una din directivele:
#include <nume_fisier>
#include nume_fisier
Aceast directiv are rolul de a solicita compilatorului ca, in faza de preprocesare, acesta s includ n textul surs
n care este folosit aceast directiv, ntregul coninut al fiierului desemnat, cu scopul de a fi compilate mpreun.
Este valid prezena unei directive include ntr-un fiier care este apelat la rndul lui printr-o alt directiv include.
Standardul ANSI C prevede existena unui numr minim de opt niveluri de includere imbricate.
Fiierul este cutat dup cum urmeaz:
a)dac fiierul se delimiteaz ntre paranteze unghiulare se va cuta fiierul n directorul specificat de mediul de
programare Dac fiierul nu este gsit, se continu cutarea n directoarele standard ale mediului.
b) dac fiierul se delimiteaz ntre ghilimele fiierul este cutat:
b1)Dac se specific calea ca i parte component a numelui fiierului doar n acel director se va face
cutarea.
b2)Dac nu se specific calea, fiierul va fi cutat n directorul curent (cel n care am fost n momentul n
care am lansat mediul de programare).

n loc ca programatorul s foloseasc propriile sale declaraii pentru funciile de bibliotec, se recomand
includerea n cadrul programului surs a unor fiiere antet (header), care conin declaraiile funciilor de bibliotec
apelate. Aceste fiiere au n general extensia .h i se gsesc n directorul INCLUDE.
Fisierele include vor contine doar DECLARATII si nu definitii de funcii. Declaratiile si definitiile pot fi de functii
sau variabile globale. Daca un fisier include contine definitii, este dincolo de controlul programatorului ca aceste
fisiere sa apara incluse de 2 ori intr-un proiect, ceea ce genereaza eroare de linkeditare in sensul ca o definitie este
gasita (la linkeditare) ca si duplicata.,
Includerea fiierelor se folosete pentru gestionarea corect a unui proiect, n general de mari dimensiuni, care se
compune din mai multe module. Pentru ncorporarea la nceputul fiecrui modul de de fiiere de descriere se pot
crea:
-fiiere coninnd definiii generale ale proiectului: declaraii de tip i directive ale preprocesorului, n particular
directive define
-fiiere coninnd declaraii de variabile externe n cazul n care definirea lor a fost regrupat ntr-un modul special.
Programele C mari pot fi structurate pe mai multe fiiere, care pot fi compilate distinct. Aceasta prezint mai multe
avantaje:
-n cazul erorilor sintactice i semantice, doar fiierul eronat trebuie recompilat, dup modificrile sau coreciile
aduse. Programatorul poate profita de faptul c unitatea de compilare este fiierul, repartiznd funciile
programului su n mai multe fiiere. n acest fel, modificarea unei funcii va fi urmat de recompilarea doar a
fiierului care o conine i a fiierelor care depind de el, nu a ntregului program, obinndu-se astfel un ctig de
timp nsemnat.
-structurarea programelor pe mai multe fiiere permite simularea mecanismului de ncapsulare a datelor.
Variabilele i funciile avnd clasa de memorare static pot fi accesate doar n cadrul fiierului n care au fost
definite. Variabilele i funciile declarate cu clasa de memorare extern sunt definite n alt fiier dect cel curent, dar
ele pot fi accesate n fiierul curent.
Observaie: Dac se modific un fiier care este inclus printr-o directiv #include, atunci toate fiierele care
depind de el trebuie recompilate.

10

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