Date post: | 29-Dec-2015 |
Category: |
Documents |
Upload: | masteringlove |
View: | 46 times |
Download: | 0 times |
PROGRAMARE PROCEDURALĂ
Limbajul în general este un mijloc de comunicare. Limbajul folosit între oameni
pentru a comunica între ei este limbajul natural. Un limbaj artificial este utilizat atunci
cand unul natural un poate fi folosit în mod adecvat ca şi în cazul comunicării om - maşină.
Tipuri de limbaje artificiale: limbaje construite (în vederea simplificării
comunicării interlingvistice: Esperanto, Lojban etc), limbaje formale (semantică şi sintaxă
precis definite), limbaje de calcul (limbaj de comandă, limbaj de programare, limbaj de
marcare).
Limbajul de programare este un limbaj artificial care prin exprimări simbolice bine
definite (instrucţiuni, directive, comenzi) descrie operaţiile de prelucrare automată a datelor
necesare pentru rezolvarea unei anumite probleme a utilizatorului.
Un limbaj de programare operează cu elemente concrete numite programe.
Instrucţiunea face parte din program şi este o comandă care se dă calculatorului
pentru a efectua o anumită operaţie de calcul, de transfer de date, de intrare\ieşire a datelor
etc.
Calculatorul manevrează informaţia în formă binară. Codul în care este scrisă informaţia este
codul binar, iar limbajul este limbajul maşină sau limbajul procesorului.
Etapele creării unei aplicaţii (în C):
Figura 1. Paşii pentru construirea unei aplicaţii
(http://control.aut.utcluj.ro/iatr/lab3/cintro.htm, de completat cu mediu de programare)
Editarea fişierului sursă (presupune existenţa unui editor de text)
Compilare.
Editare de legături (link edit)
Rezultă fişierul executabil
Etapa de depanare (debug)
O clasificare a limbajelor:
a) După tipul (paradigma) programării: ezoterice, ex. (Brainfuck), procedurale;
ex. C, Java, Perl, funcţionale: ex. ML, Haskell, pentru programarea logică ex. Prolog,
DATALOG, limbaje mixte: ex. LISP (programare imperativă şi programare functională).
Limbajele de programare care descriu algoritmul de rezolvare a unei probleme sub forma
unei secvenţe de instrucţiuni (care se vor executa în ordinea scrierii) se numesc limbaje
procedurale sau algoritmice. Replica acestor limbaje de programare procedurală sunt cele
neprocedurale gen LISP, Prolog etc.
b) După nivelul de abstractizare (exprima printre altele uşurinţa cu care programele
pot fi citite şi înţelese de către programatori):
limbaje de generaţia întâia: limbajele cod-maşină (limbaj maşină proprii fiecarui
tip de procesor)
limbaje de generaţia a doua: limbajele de asamblare (în locul codului maşină
folosesc o desemnare simbolică a elementelor programului, relativ uşor de citit şi
interpretat de către om). Limbajele din primele două generaţii = limbaje de nivel scăzut.
limbaje de generaţia a treia: cum ar fi C-ul (şi toate derivatele sale: C++, Java, ...),
Pascal, Fortran ş.a. Obs: C, C++ = limbaje de nivel mediu.
limbaje de generaţia a patra: limbajele neprocedurale, orientate pe rezolvarea unei
anumite clase de probleme: SQL ş.a. limbaje de generaţia a cincea: limbaje utilizate în
domenii precum logica fuzzy, inteligenţa artificială sau şi reţelele neuronale: Prolog, LISP.
Java, Pascal, SQL, Prolog sunt limbaje de nivel înalt întrucât necesită existenţa unuia sau
mai multor filtre de translare din limbaj înalt în limbaj cod maşină. Aceste programe se
numesc translatoare şi sunt de 2 tipuri: compilatoare şi interpretoare. Compilatoarele
traduc întreg programul, după care acesta se poate executa la nevoie; interpretoarele traduc
şi execută pe rând fiecare instrucţiune.
Altă clasificare alimbajelor:
- limbaje tipizate: acestea sunt limbaje care impun anumite restricţii asupra
operaţiilor care se pot aplica anumitor date, funcţie de tipul datelor (numerice, siruri de
caractere, etc). Tipul datelor trebuie declarat înainte de introducerea acestora în program si
respectat pe tot parcursul programului. Majoritatea limbajelor compilate sunt şi tipizate: C,
C++, Pascal, Java.
- limbaje netipizate, care nu impun restrictii (spre exemplu, variabilele nu sunt
restricţionate la un anumit tip de dată şi nu trebuie declarate înainte de a fi folosite). Aceste
limbaje ofera o flexibilitate mai sporită, sunt mai puţin restrictive. Majoritatea limbajelor
specializate sunt netipizate, iar majoritatea limbajelor netipizate sunt interpretate: Php,
Matlab etc.
Obs: Limbajul de programare C a fost elaborat de Dennis Rithie şi Brian Kernighan
între 1969 şi 1973 la compania BELL Telephone pentru a permite realizarea sistemului de
operare Unix. În anii 1980 a fost adoptat şi de calculatoarele IBM PC, popularitatea
acestuia începând să crească semnificativ. În acest timp, Bjarne Stroustrup împreună cu alţi
colegi de la Bell Labs au început să adauge limbajului C caracteristici ale programării
orientate pe obiecte. Limbajul rezultat a fost denumit C++ şi este cel mai popular limbaj de
programare pe sistemele de operare Microsoft Windows (http://ro.wikipedia.org/wiki/C_
%28limbaj_de_programare%29#.C3.8Enceputurile_limbajului_de_programare_C)
Prezentare generală a limbajului C
În cadrul C se foloseşte setul de caractere ASCII, care asociază fiecărui caracter un
număr întreg din intervalul [1; 127].
Caracterul 0 ASCII corespunde caracterului impropriu nul şi acesta se foloseşte
pentru a marca sfârşitul unui şir arbitrar de caractere.
Mulţimea caracterelor poate fi impărţită în 3 grupe:
1. caractere negrafice, care au caracterele ASCII corespunzătoare mai mici decât
32; face excepţie de la această regulă caracterul Delete căruia îi corespunde 127;
2. Spaţiul, care are ca şi corespondent ASCII valoarea 32;
3. caracterele grafice, care au codurile ASCII mai mari decât 32 (litere mari, mici,
cifre).
Literele mari au în ordine codul ASCII de la 65 la 90, literele mici de la 97 la 122,
iar cifrele de la 48 la 57.
Specificaţii de limbaj C
Vocabular:
setul de caractere: a - z , A - Z , 0 - 9;
semne de punctuaţie: ‘ . ‘ , ‘ , ‘ , ‘ ; ‘ ;
caractere speciale : % , & , $ etc.;
cuvinte rezervate: while, if, for, else, void, char, int, float, double, unsigned,
include, main, getch etc.
Constante şi expresii
O constantă nu îşi modifică valoarea pe parcursul rulării unui program.
Pot fi constante predefinite (gen MAX INT) sau constante propriu-zise. Declararea
se face prin CONST.
OBS. Înţelegem prin identificator un nume (denumire) ce se poate atribui (şi care
defineşte de regulă în mod unic) unei constante, variabile, funcţii.
Regulă de construcţie identificatori valizi
Un identificator conţine doar litere, cifre şi “_” (underline). Nu poate conţine
spaţii şi nu poate începe cu o cifră.
Definiţie: O expresie este o construcţie validă în C din punct de vedere sintactic şi
semantic.
Exemplu: ( a||b ) sau ( a&&c ).
Separatori
Definiţie: Un separator separă uzual atomi–lexicali (cuvinte rezervate). Cel mai
uzual separator este “spaţiul ” iar “ ; “ separă două instrucţiuni. Alţi separatori: ( ) , [ ] ,
{ } , virgulă, ‘, “ “.
Comentarii : “ // “ pe o singură linie şi “ / * a……b */ “ pe mai multe linii.
TIPURI DE DATE
Un tip de date constă într-o mulţime de valori pentru care există un mod de
reprezentare în memoria calculatorului, cât şi o mulţime de operatori, care pot fi aplicate
acestor valori.
OBS. Tipul de date determină lungimea zonei de memorie ocupată de acea dată.
Tipuri de date: char, int, float, double.
OBS. Tipurile de date pot avea calificatori gen: short, long, sign, etc .
OBS. Constantele simbolice (max long etc) sunt definite în biblioteca <values.h>.
TIP Memorie uzuală
DescriereMS-DOS Linux
Char 8 8
unsigned char 8 8
signed char 8 8
int 16 32
Long 32 64
long long int 32 64
short int 16 32
unsigned int 16 32 Fără semn
unsigned long 32 64 valoarea întreagă fără semn
float 32 32valoare numar zecimale,
simplă “precizie”
Double 64 64 “dublă precizie” (10)
long double 80 128 “dublă precizie”
Observaţii:
Secvenţele ESCAPE sunt folosite pentru reprezentarea caracterelor invizibile sau greu de
obţinut. Cele mai uzuale sunt:
Constanta char Cod ASCII Denumire
‘ \n ’ 10 LF(line feel) Enter
‘ \t ’HT(horizonter
Tabulator)Tab
‘ \r ‘CR
(carriage return)
mă întoarce la
capăt de rand
‘ \f ‘ FFsalt la pagina
din imprimantă
‘ \a ‘ BELse activează un
sunet
VARIABILE
O variabilă spre deosebire de o constantă îşi poate modifica valoarea în cadrul unui
program. Ea este caracterizată de:
1. Identificator (nume);
2. Domeniul de vizibilitate (zona de program în care variabila are influenţă/efect )
<engleză: scope >;
OBS. Din acest punct de vedere pot exista într-un program 2 variabile cu acelaşi
identificator ( int a , A = 2 ).
3. Valoare;
4. Tipul de date (indică spaţial de memorie alocat/ocupat);
5. Adresă.
O variabilă poate primi drept valoare:
─ o valoare constantă;
Exemplu: A = 2 .
─ valoarea unei constante predefinite sau nu;
Exemplu: PI = 3.14;
float X = PI;
float X = MAXINTEGER;
─ valoarea întoarsă de o funcţie;
─ valoarea unei alte variabile;
Exemplu: a = A.
─ valoarea unei expresii;
Exemplu: x = (a+b)&&(!c)||1
INSTRUCŢIUNI DE CONTROL
Instrucţiunile de control descriu structurile de control şi fluxul circulaţiei datelor.
Structura decizională (alternativă):
1. alternativă binară (instrucţiunea IF);
Sintaxă: if <conditie> then A
[else] B
OBS. În cazul în care A şi B lipsesc obţinem o structură decizională cu ramură vidă.
2. alternativă generalizată (corespunde instrucţiunii SWITCH)
Sintaxa: switch(expresie)
{case const1:<i1>; break;
case const2:<i2>; break;
…………………………..
case constn:<in>; break;
[default: < B >]
}
Semantica: se evaluează expresia şi se compară rezultatul evaluării cu valorile
constante specificate; se execută secvenţa de instrucţiune asociată k, dacă evaluarea
expresiei coincide cu valoarea constantei din cazul k. Default este opţional.
OBS. Pot exista maxim 257 cazuri (case ).
Exemplu: int i;
cin>>i ;
swich(i)
{case 1: cout<<”Introduceti date“ >>; break;
case 2: cout<<”Afisare date”; break;
default: cin<<”Iesire” ;
}
OBS. Prezenţa instrucţiunii break face ca atunci când se evaluează cazul respectiv,
la întâlnirea lui break să se părăsească switch pentru a nu evalua inutil restul cazurilor.
INSTRUCŢIUNI DE SALT ŞI ÎNTRERUPERE
Instrucţiunile de salt sunt:
GO TO – este o intrucţiune de salt la o altă instrucţiune din acelaşi program ce a fost în
prealabil etichetată. O etichetă este un identificator urmat de 2 puncte.
Exemplu: i=1;
if(k==i) go to unu;
unu: i=2;
OBS. GO TO se evită a fi folosită întrucât încalcă principiile programării
structurale. GO TO trebuie să fie în aceeaşi funcţie cu eticheta (în C nu există proceduri)
pentru că nu se poate face salt peste funcţii.
RETURN – este folosită pentru reîntoarcerea dintr-o funcţie. Este de salt întrucât la
intalnirea ei se face salt la intrucţiunea imediat următoare celei care a determinat apelul
funcţiei. În general sintaxa este RETURN.
Sintaxă: return [<expresie>]
Observaţii:
1. Dacă return are o valoare, aceasta devine valoarea întoarsă de funcţii.
2. În C++ o funcţie care nu are tipul void trebuie să întoarcă o valoare.
3. Acolada care încheie o funcţie determină ieşirea din funcţie şi echivalează cu
RETURN, însoţită sau nu de valoare.
Instrucţiuni de întrerupere
BREAK – determină ieşirea dintr-o instrucţiune alternativă (de obicei la switch şi
câteodată la if ) sau determină părăsirea unei bucle (a unei instrucţiuni repetitive),
controlul programului fiind cedat instrucţiunii ce urmează imediat după buclă.
Funcţia EXIT
OBS. Nu este o instrucţiune de control ci o funcţie ce determină părăsirea
programului. Exit poate fi apelată oriunde în program, de regulă atunci când nu sunt
indeplinite condiţii obligatorii pentru program.
Sintaxă: exit();
CONTINUE – este o funcţie similară cu break , cu deosebirea că nu forţează
părăsirea buclei ci trecerea la următoarea interaţie.
OBS. Aflată în interiorul instrucţiunilor repetitive continuă transferul controlului
programului expresiei de testare (condiţiei) ignorând instrucţiunile care o succed în buclă.
Exemplu: v = (10, 2, 6, 1, 8, 7, 5)
for( i = 1; i<=7; i++)
if(v[i]%2==0) // v[i]=nr par
S = S+v[i];
else continue ;
p = S+2v[i];
INSTRUCŢIUNI REPETITIVE
Clasificare:
A. Instrucţiuni repetitive cu număr necunoscut de paşi:
1. Repetiţia cu test iniţial (while);
2. Repetiţia cu test final (do…while).
B. Instruncţiuni repetitive cu număr cunoscut de paşi:
1. Structura repetitivă cu contor (for):
a. cu contor în creştere ;
b. cu contor în descreştere.
A1. Repetiţia cu test iniţial
Intrucţiune: while…do
Sintaxa: while(<cond>)
[do]
Set instruct <A>
Semantica: se evaluează expresia <cond>; dacă valoarea obţinută în urma evaluării
expresiei este nenulă se execută setul de instrucţiuni A şi se revine la pasul 1, în caz
contrar se trece la instrucţiunea imediat următoare.
Exemplu: Afişarea unui şir de numere naturale de la 1 la n (dat).
Presupunem ca în i se depun valorile 1,2,….,n . Iniţial i=1
int i=1;
int n=10;
while(i<=n)
{cout<<i<<” “ ;
i++;
}
OBS. Setul de instrucţiuni A trebuie să conţină minim o instrucţiune care să
afecteze valoarea restului astfel încât să devină la un moment dat fals (ies din buclă astfel -
ciclare infinită).
A2. Repetiţia cu test final
Exemplu: do
{cout<<i<<” “;
i++;
}
while(i<=n)
Instrucţiunea: do…while
Sintaxă: do
set instruct B;
while(<cond>)
instrc_urm;
Semantică:
─se execută setul de instrucţiuni B (1);
─se evaluează expresia <cond>. Dacă e adevarată se revine la (1), în caz contrar se
execută instrucţiunea următoare;
─se execută B până când <cond> devine falsă (cât timp cond rămâne adevarată).
Observaţii:
1.Spre deosebire de while, do…while presupune execuţia cel puţin odată a setului
de instrucţiuni B.
2. Similar cu while şi pentru do...while trebuie să existe în setul B minim o
instrucţiune care să afecteze valoarea testului, altfel se ciclează la infinit.
Exemplu: S = 1 + 2 + …. + n
int i=1; s=0;
int n=10;
while (i <= n)
{cout<<i<<” “;
S = S + i; i++;
}
cout <<”suma este : ”<<S;
B. Repetiţia cu număr cunoscut de paşi
Instrucţiunea FOR
Sintaxă: for(<expr1> ; <expr2> ; <expr3>)
set instr A;
instr_urm;
Semantică:
- <expr1> se numeşte expresie de iniţializare; se stabileşte valoarea iniţială a
contorului.
- <expr2> se numeşte expresie de test. Dacă valoarea rezultată a evaluării expr2
este nenulă, se execută set instr A. În caz contrar se execută instrucţiunea următoare
( instr_urm ).
- <expr3> se numeşte expresie de incrementare/decrementare folosită pentru
creşterea/descreşterea contorului.
OBS. Dacă vi<vf atunci rezultă for cu contor în creştere, în caz contrar for cu
contor în descreştere.
Principiul de execuţie:
- se evaluează expr1;
- se evaluează expr2; dacă s-a produs o valoare diferită de 0 se execută A, altfel se trece
la instrucţiunea următoare;
- se evaluează expr3 şi se revine la pasul 2.
Exemplu: for(i=1;i<=n;i++)
cout<<i<<” “;
S=0;
for (i=1;i<=n;i++)
S=S+i;
cout<<”Suma primelor”<<n<<” numere naturale”<<S;
Un exemplu complet: algoritmul lui Euclid
Pentru a obţine c.m.m.d.c. a două numere a şi b, folosim:
-împărţim a la b ( b≠0);
-dacă restul împărţirii este 0 (r1=0) atunci c.m.m.d.c. este b;
-dacă nu, împărţim pe b la restul împărţirii anterioare (r1) şi obţinem r2;
-împărţim r1 la r2 si obţinem r3 etc.;
-ultimul rest nul este c.m.m.d.c. a lui a şi b.
c.m.m.d.c.(a,b)=c.m.m.d.c.(b,a mod b)
Program:
#include <iostream>
using namespace std;
int a, b, deimp, imp, cmmdc, rest;
int main()//void pentru medii
do
{
cout<<”Dati a şi b”<<endl;
cout<<”a= “;cin>>a;
cout<<endl;
cout<<”b= “;cin>>b;
cout<<endl;
deimp=a;imp=b;
do
{rest=deimp%imp;
deimp=imp;
imp=rest;
}
while(imp!=0)
cmmdc=deimp;
cout<<”continuati (d/n)”<<endl;
cin>>ok;
while(ok=”n”)
cout<<”c.m.m.d.c.”<<cmmdc;
system(“Pause”);
getchar();
return 0;
}
Determinarea cmmdc prin scăderi repetate:
# include <iostream.h>
# include<conio.h>
int main(){
int a,b,u,v,cmmdc,cmmmc;
cout<<”dati a: “; cin>>a;
cout<<endl;
cout<<”dati b: “; cin>>b;
cout<<endl;
if(a*b==0 ) \\ a sau b sunt 0
{if(a + b != 0)
{cout<<”cmmdc este: “<<a+b;
cout<<endl; }
else
cout<<”nu exista cmmdc”;
cout<<”cmmmc=0“;
}
else {
u=a;
v=b;
while(a*b)
if(u > v)
u=u-v;
else
v=v–u;
cmmdc=u;
cmmmc=(u*v)/cmmdc;
cout <<”cmmdc= “<<cmmdc<<”cmmmc= “<<cmmmc;
}
system(“pause”);
getch();
}
TIPURI STRUCTURATE
1. TABLOURI
Cel mai uzual tip stucturat de date.
Un tip de date este structurat dacă este format din tipuri de date elementare.
Alte tipuri structurate:
- matrici, masive;
- înregistrări, uniuni, fişiere etc.
Observaţii:
1. Generalizarea conceptului de vector poartă denumirea de tablou
(unidimensional=vector, bidimensional=matrice, tridimensional=masiv)
Declarare:
<tip_v>.<nume_v>[<dim>]
Exemple: int vector[20]; char alfabet_RO[31];
2. Indexarea elementelor unui vector începe în C/C++ de la 0.
3. C/C++ nu face “check boundaries”(nu verifică dacă s-a depăşit dimensiunea
vectorului).
Parcurgere:
Presupunem cunoscută dimensiunea.
Exemplu: for(i=0;i<n;i++)
<prelucrare elemente>
Unde <prelucrare elemente> poate fi:
a) citire:
cin>>vector[i];
b) afişare:
cout<<vector[i];
c) mixt a) şi b).
{cout<<”vector[“<<i<<”]=”;
cin>>vector[i];
cout<<endl;
d) alte prelucrări
Prelucrări pe vectori (operaţii):
aritmetice: sumă, produs scalar, norma unui vector etc.
sortări: boublesort, sortare cu pivotare, quick sort etc.
Metoda bulelor:
int bule=1;
while(bule = = 1) {
bule=0;
for (i=1; i<=n; i++)
if (v[i] > v[i+1]) {
aux= v[i]; // interschimb
v[i]= v[i+1];
v[i+1]= aux;
bule=1;
}
}
regăsirea unuia sau a mai multor elemente ale tabloului ce satisfac o sumă
de proprietaţi: determinarea minimului, a maximului, verificare dacă elementele vectorului
determină o progresie, calcul număr apariţii elemente, determinare elemente impare, a
celor divizibile printr-un număr dat, a acelor elemente care sunt palindroame, care conţin
un anumit număr de vocale etc.
gasit=1;
for (i=1; i<=7&&gasit; i++)
if (v[i]= = 5) {
cout<<”gasit”;
gasit=0;
}
interclasarea: presupune obţinerea din 2 sau mai mulţi vectori sortaţi, un al
treilea format din elementele primilor, în aceeaşi ordine
(crescătoare sau descrescătoare).
while (( i<n) && (j<m))
if (a[i]<b [j])
c[k++]=a [i++];
else c[k++]=b[j++];
tablou bidimensional: este un tip de dată corespunzător unei matrici <nr
linii>][<nr coloane>].
for (i=0;i<n;i++)
for (j=0;j<n;j++)
{cout << “ a[“ << i << “][“ << j << “]“;
cin>>a[i][j];}
cout<<endl;
OBS. Aplicaţiile cu matrici sunt similare cu cele de la vectori.
masive;
Declarare: tip nume_masiv[<dim1>][<dim2>]….[<dimn>]
Structuri. Uniuni
OBS. Spre deosebire de tablouri care conţin elemente de acelaşi tip, structurile/uniunile pot
conţine variabile diferite reunite sub acelaşi nume.
Structurile sau uniunile sunt tipuri structurate de date. Variabilele ce alcătuiesc structura se
numesc membrii structurii sau câmpuri. Pentru accesul la un câmp a unei structuri se
foloseşte operatorul “ . “ . Declararea unei structuri se încheie cu “;“ deoarece e considerată
o singură instrucţiune.
Sintaxa:
struct<nume_structura>
{ <tip_camp_1><lista_var_1>;
<tip_camp_2><lista_var_2>;
.
.
.
<tip_camp_n><lista_var_n>; }
<lista_var_tip_struct>;
Structurile implicate în situaţii în care se declară o structură în interiorul unei alte
structuri.
Exemplu:
struct student {
char nume[30], prenume[30];
struct {
char specializare[20];
float note[14];
} Situatie;
}S1,S2;
OBS. În interiorul structurii “student” se află o structura anonimă ce poate fi
apelată prin intermediul variabilei “Situatie“:
cout<<S1.Situatie.specializare;
cout<<S2.Situatie.note[0];
Definiţie. Uniunile sunt un tip de dată structurată prin care se rezervă o locaţie de
memorie pentru două sau mai multe variabile. Deci uniunea este o structură în care
componentele sale de tip diferit, ocupă la momente de timp diferite aceeaşi locaţie de
memorie.
Sintaxa:
union <nume_uniune>
Uniunile sunt în general declarate dacă există înregistrări cu structură variabilă. O uniune
poate fi declarată atât în afara unei structuri cât şi în interiorul ei.
Exemplu:
struct persoana {
char nume[20],prenume[20];
union {
int clase;
struct {
char denumire[20];
char oras[20]
} liceu;
struct {
char denumire[20], oras[20]
} facultate;
} studii;
} p;
p.studii.liceu.denumire sau p.studii.clase sau p.studii.facultate.oras
POINTERI
Numim pointer o variabilă al cărei atribut valoare poate conţine doar o adresă.
Sintaxa: < tip >*< identificator_pointer >
Exemple: int *a,*b; //a şi b pointer către întreg
float *pointer_to_float;
int a1; int *p;
p=&a1; // p primeşte ca valoare adresa lui a1
OBS. Afişarea valorii lui p, cât şi a adresei lui a dau evident acelaşi rezultat.
Avantaj: reutilizarea spaţiului de memorie.
OBS. Pointerii au o aritmetică proprie. O variabilă poate ocupa unul sau mai mulţi octeţi,
în funcţie de tipul său. Un pointer va conţine adresa unei variabile, în fond adresa primului
octet ocupat de aceasta. Dacă pentru o variabilă ştim adresa şi numărul de octeţi ocupaţi,
putem face un calcul prin care, de exemplu, să aflăm adresa următoare. Procedeu dificil
întrucât variabilele pot avea tipuri diferite. Aritmetica pointerilor simplifică acest calcul:
pointer + 1 → înseamnă adresa următoarei variabile de tipul celei conţinute de
pointer;
pointer + 2 → înseamnă adresa următoare de acelaşi tip.
Legătura pointeri–tablouri:
OBS. C/C++ furnizează două metode de acces la elemenetele unui tablou:
a) specificând indicele elementelor;
b) cu ajutorul pointerilor.
Exemplu: char sir[20];*p;
a) sir[3];
b) p=sir;
c) *(p+3).
OBS. p=sir ≡ p=&sir[20].
int *x[ 10 ] → vector de 10 pointeri către întreg.
OBS. Pentru a declara pointeri constanţi folosim:
int b=5;
int *const p=&b;
- p este o constantă de tip integer ce conţine adresa variabilei b (conţinutul său, adică
conţinutul de la adresa &b, nu mai poate fi modificat).
Operaţii cu pointeri
1.Atribuirea
Exemplu: int *a ,*b;
char *a ;
a = b ;
Atribuirea se realizează dacă cei doi pointeri reţin adrese către variabile de acelaşi
tip, în caz contrar, atribuirea nu se poate realiza, implicit se foloseşte operatorul de
conversie explicită.
Exemplu: int a=5;
*adresa=&a;
float b=5.2;
*adresb=&b;
adresa = (int *) adresb;
2.Compararea variabilelor de tip pointer
Fiind date două adrese de memorie, acestea pot fi comparate folosind operatorii
relaţionali.
3.Incrementarea/Decrementarea pointerilor
Dacă a este pointer de tip x si n număr natural, atunci a+n reprezintă adresa ce se
obţine ca sumă între adresa reţinută în “a“ şi produsul dintre n şi numărul de octeţi rezervat
de compilator pentru a memora o variabilă de tipul celei a cărei adresă se află în a .
4.Pointeri către funcţii
OBS. Deşi o funcţie nu este o variabilă, ea are o localizare în memorie, ce poate fi
atribuită unui pointer.
OBS. Pointeri speciali (POO):
- this – intervine în cazul apelului unei funcţii membre a unei clase;
- near si far – gestionează reprezentarea fizică a memoriei în pointeri, respectiv zona de
memorie, respectiv numele cu semnificaţie de adresă. Funcţiile de dimensiunea de
memorie alocată unui pointer, numele reţinute pot fi mai mici sau mai mari. Un pointer
near poate adresa un bloc de memorie de 64 Kb.
O referinţă este un nume alternativ al unui obiect. Sunt utilizate în principal în
specificarea argumentelor şi a valorilor returnate de funcţie, cât şi pentru supraîncărcarea
operatorilor (POO).
Notaţie: &x înseamnă referinţă la obiectul x.
Exemplu: int i=1;
int &r=i; //r şi i se referă la aceeaşi entitate
int x=r;
x++; // i are aceeaşi valoare
r++; // i işi schimbă valoarea
OBS. Deşi pentru declararea unei referinţe folosim operatorul &, tipul construcţiei în care
este folosit diferă.
Exemplu: int a=5;
int *pi=&a; // pi = adresa lui a
int &r=a; // r = alt nume pentru a
OBS. O referinţă este utilizată ca argument pentru o funcţie care poate să modifice
valoarea acestui argument.
Exemplu: void incr(int &x)
{x++;
}
void f ()
{int i=1;
incr(i);
}
Conversii de tip
Atunci când într-o expresie sunt amestecate constante şi variabile de diferite tipuri,
ele sunt convertite (la tipul cel mai mare) de către compilator.
Exemplu: int i;char c;float f; double d;
expresie = (c/i)+(f*d)-(f+I)
c ← int
f ← double
i ← float
int+double ← double
double - float ← double
Conversia forţată se face specificând tipul dorit între paranteze, în faţa variabilei
sau expresiei ce se converteşte .
FUNCŢII ÎN C/C++
Subprograme
Limbajele de programare permit construirea programelor pe baza tehnicii
programelor structurate, ce presupune o metodologie de proiectare organizată cât şi
folosirea adecvată a instrucţiunilor de control.
Divizarea algoritmilor de mari dimensiuni în module mai uşor de controlat,
prezintă o serie de avantaje precum:
- rezolvarea unei probleme printr-un program monoid nu evidenţiază legatura naturală între
algoritmul folosit şi unitatea de program destinată implementării acestuia;
- programe extrem de mari sunt dificil de înţeles, în special după trecerea unei perioade mari
de timp sau dacă se impune transferul dezvoltării ulterioare a acestuia unor terţe persoane;
- se impune ca o unitate de program (subprogram) să aibă o funcţie bine definită care să
implementeze un singur algoritm având bine precizate intrările şi ieşirile.
Concluzie: În general un subprogram este un modul scris independent de programul
principal, dar legat de acesta printr-un proces de transfer şi revenire.
Definiţie. Procesul de transfer al controlului se numeşte apelare subprogram. Modulul care
solicită execuţia subprogramului se numeşte modul apelant, subprogramul numindu-se
modul apelat.
Un subprogram uzual este format din:
- nume;
- definire subprogram, care poate avea o zonă declarativă (variabile locale) şi zonă
executivă.
OBS. În general entităţile (uzual variabile) declarate în interiorul unui subprogram sunt
entităţi locale – pot fi utilizate doar în interiorul subprogramului respectiv. În cazul în care
unele entităţi trebuie folosite în comun de toate modulele (sau numai de o parte) unui
program, acestea se vor numi entităţi globale.
OBS. Utilizarea entităţilor globale este contraindicată.
Apelul subprogramelor:
<tip_rezultat><nume_subprog>(<lista_param_formali>)
Exemplu: int maxim(int a,int b)
bool este_in_sir(double sir[], double x )
void aria(float lung, float latime)
OBS. Spre deosebire de Pascal unde există chiar cuvântul rezervat procedure, în C/C++ nu
există proceduri, ci doar funcţii către void (funcţii care nu întorc nici un rezultat). Spre
deosebire de funcţii, procedurile (în sens clasic) nu întorc în modulul apelant nici o valoare
(rezultat).
OBS. Funcţiile pot conţine minim o singură dată o instrucţiune return.
Exemplu: subprogram maxim(int x, int y, int z)
Apel: maxim(a, b, max)
a) a şi b sunt transferate în x, respectiv y;
b) subprogramul plasează valoarea mai mare în z;
c) valoarea din z este transmisă modulului apelant.
Modalităţi de transfer a parametrilor:
1) Datele sunt copiate efectiv din locaţiile respective, din programul principal, în
celulele de memorie asociate subprogramului, caz în care se spune că transferul se
realizează prin valoare (ineficient dacă dimensiunea datelor asociate parametrilor
sunt mari, întrucât, lucrându-se cu copii ale parametrilor reali, stiva alocată
subprogramului se încarcă).
OBS. La apel, parametrii formali sunt substituiţi cu cei reali, cele două liste trebuie să
coincidă ca tip şi număr de parametri.
2) Se pot transfera doar adresele celulelor de memorie ce conţin datele respective,
fapt ce oferă subprogramului acces direct la date fără a genera o copie a acestora.
Se spune că transferul se realizează prin adresă sau referinţă. Parametrii transmişi
prin referinţă vor avea în faţa numelui un & (et).
Exemplu: void unu(int a)
{a = a + 2;
cout<<”unu”<<a;}
void doi(int &b)
b = b + 5;
unu(b); cout<<”doi1”<<b;
unu(b); cout<<”doi2”<<b;
}
void main()
{int c = 10;
doi(c); cout<<”afara”<<c;}
OBS. În cazul în care apelul unu(b)←unu(a), valoarea lui a trebuie precizată înaintea
apelului. În această situaţie a devine variabilă globală pentru “unu“ ca funcţie şi “doi“.
Exemplu: int x, y, z;
void P(int x, int &y)
{z = x + y;
x++;
y = y + x;
cout<< x<<y<<z<<endl;}
void main()
{x = 3; z = 4; int t = 10;
P(t,x);
cout<<x<<y<<z;}
void p(int x, int &y)
{x++; y = x;}
void pa(int &x, int &y)
{x++; y = x;}
void main()
{int x = 0, y;
while(x<3)
{p(x ,y); x++; cout<<x<<y<<endl;}
x=0 ;
while(x<3)
{pa(x ,y); x++; cout<<x<<y<<endl;}
OBS. Dacă mediul nu acceptă tipul logic (bool), bool se înlocuieşte cu integer, true←1,
false←0.
Problemă. Să se scrie un program care să conţină procedura citeşte elementele unui
vector, dimensiunea şi numele lui, o procedură care afişează vectorul, o funcţie care
validează dacă un element aparţine unui vector (mulţimii), o procedură mulţime care
transferă vectorul într-o mulţime, cât şi procedurile reuniune, intersecţie, diferenţă, care să
fie apelate într-un program ce transferă vectorul în mulţimi şi operează cu acestea.
#include<stdio.h>
#include<stdlib.h>
void citeste(int x[], int &n, char nume[])
{int i;
printf(“Dati numarul de elemente pentru vectorul %s”,
nume);
scanf(“%d”, &n);
for(i=1; i<=n; i++)
{printf(“Dati %s[%d]= “, nume, i);
scanf(“%d”, &(x[i]));
}
}
void afiseaza(int x[], int n, char nume[])
{int i;
printf(“Vectorul este %s: “, nume)
for(i=1; i<=n; i++)
{printf(“%d”, x[i]);
printf(“\n”);
}
}
bool estein(int a ,int x[], int n)
{int i;
for(i=1; i<=n; i++)
if(x[i] == a)
return true;
return false;
}
void multime(int x[i], int n, int y[], int &n)
{int i;
m = 0;
for(i=1; i<=n; i++)
if(!estein(x[i], y, m)
{m++;
y[m] = x[i];
}
}
void reuniune(int x1[], intn1, int x[], int n2, int
r[], int &nr)
{int i;
for(i=1; i<=n1; i++)
r[i] = x1[i];
nr = n1;
for(i=1; i<=n2; i++)
if(!estein(x2[i], x1, n1)
{nr++;
r[nr] = x2[i];
}
}
void intersectie(int x1[], intn1, int x2[], int n2, int
s[], int &ns)
{int i; ns = 0;
for(i=1; i<=n1; i++)
if(estein(x1[i], x2, n2)
{ns++;
s[ns] = x1[i]; }}
int main()
{int a[20], b[20], am[20], bm[20], reun[40], inters[20],
difer[20];
int na, nb, nam, nbm, nr, ns, nd;
citeste(a , na, “a“);
afiseaza(a, na, “a”);
citeste(b, nb, “b“);
afiseaza(b, nb, “b“);
multime(a, na, am, nam);
afiseaza(am ,nam, “Multime a“);
multime(b ,nb ,bm ,nbm);
afiseaza(bm ,nbm, “Multime b“);
reuniune(am ,nam ,bm , nbm, reun, nr);
afiseaza(reun , nr, “Reuniunea: “);
intersectie(am, nam, bm, nbm, inters, ns);
afiseaza(inters, ns, “Intersectia: “);
diferenta(am, nam, bm, nbm, difer, nd);
afiseaza(difer, nd, “Diferenta: “);
………………
}
OBS. Transferul prin adresă se poate face şi prin intermediul pointerilor.
Exemplu: void cuPointer(int x, int *y)
{x++;
*y = x;}
int main()
{int x, y;
x = 1;
while(x<=5)
cuPointer(x, &y);
}
OBS. Pointeri la structuri: când structurile sunt mai mari, este mai eficient să se transmită
un pointer către acea structură, iar în interiorul funcţiei să se folosească accesul prin
pointer. Când un pointer al unei structuri e transmis unei funcţii, în stivă se reţine doar
adresa structurii. Acest lucru garantează apeluri de funcţii rapide, funcţiile putând totodată
să modifice conţinutul structurii folosite la apelare.
Exemplu: struct timp
{int ora;
int minute;
int secunde;
}*t;
- apel câmp structură prin pointer
if(t→minute == 60)
{t→minute = 0;
t→ora++;
}
- funcţie simulare potrivire oră la ceas
void potrivire(timp *t) {
if(t→minute == 60)
{t→minute = 0;
t→ora++;
}
if(t→ora == 24)
t→ora = 0;
}
Pointeri către o funcţie
Deşi funcţia nu este o variabilă, ea are localizare în memorie; aceasta poate fi
atribuită unui pointer. Altfel spus, adresa unei funcţii este punct de intrare în funcţie, deci
se poate folosi un pointer către o funcţie pentru a o apela.
OBS! Adresa unei funcţii se obţine specificând numele funcţiei fără paranteze sau
argumente.
Exemplu: float mult(float x, float y)
{return x*y;}
float add(float x, float y)
{return x+y;}
float scad(float x, float y)
{return x-y;}
float operatie(float(*f)( float , float ),
float x, float y)
{return (*f)( x, y )*1000;}
void main()
{float a = 2, b = 3, c;
float(*t[3])(float, float);
t[0] = mult;
t[1] = add;
t[2] = scad;
c = (*t[1])(a, b);
c = operatie(scad, a, b);
Funcţii standard în C++
double abs(double x) → calculează modulul;
double ceil(double x) → calculează partea întreagă (în minus);
double floor(double x) → calculează partea întreagă (în plus);
double exp(double x) → calculează ex
double log(double x) → calculează ln x;
double log10(double x) → calculează lg x;
double pow(double x, double y) → calculează xy;
int rand() → generează aleatoriu un număr întreg cuprins între 0 şi
32687.
OBS! Pentru setarea generatorului de numere aleatorii într-un anumit punct se foloseşte
void strand(unsigned n). Dacă n=1 se reiniţializează generatorul.
RECURSIVITATE
Pentru a putea rezolva o problemă în mod recursiv, ea trebuie formulată recursiv,
fapt ce presupune că:
- este specificat un set de situaţii în care soluţia problemei este cunoscută (aceste situaţii
descriu încetarea apelurilor recursive; pot fi situaţii nemijlocite sau rezultate prin apelul
unei alte metode).
- sunt definite o sumă de situaţii admisibile (A ≠ Ǿ) pentru care problema se poate
rezolva.
Exemplu: În problema determinării lui n! situaţiile admisibile A sunt date de N, nu
şi de Z de exemplu. Orice situaţie din A este reductibilă la o situaţie iniţială (din I ≠ Ǿ).
OBS. Posibilitatea de a rezolva o problema recursiv este o caracteristică a limbajului de
programare şi nu ţine doar de formularea problemei.
Un subprogram recursiv se comportă ca şi cum am avea definite în acelaşi program un
număr de copii identice ale subprogramului.
I. Mod iterativ:
unsigned long facti(int n)
{int i, unsigned long f=1;
for(i=1; i<=n; i++)
f = f*i;
return f;}
II. Mod recursiv:
unsigned long factr(int n)
{if(n == 0)
return 1;
else
return n*factr(n-1);}
În urma apelurilor recursive, valorile întoarse se refac în ordinea inversă a apelului.
Exemplu:
#include<iostream>
using namespace std;
void frec(int n)
{if(n == 0)
{cout<<”GATA”<<endl;
return;}
cout<<”#n”<<n<<” “<<$n<<endl;
frec(n-1);
cout<<”*n”<<n<<” “<<$n<<endl;
return;}
void main()
{frec(5);…}
Se afişează : #n 5 0012FE98
#n 4 0031DE45
#n 3 00120AB20
#n 2 0011AB19
#n 1 0011AB15
GATA
*n 1 0011AB15
*n 2 0011AB19
. . . . . . .
*n 5 0012FE98
Restricţii specifice recursivitaţii:
Exemplu: int Peano(int n)
{if(n == 1)
return 1;
else
return (1+Peano(n-1));
}
OBS. Reamintim: f(1)=1 (funcţia identitate)
f(n)=f(n-1)+1
a) Dacă renunţ la if(n = = 1) return 1; obţin: “stack overflow error “, deci toate
valorile admise la apelul unei funcţii recursive trebuie să conducă la condiţia de oprire.
b) Dacă în loc de secvenţa if(n == 1) return 1; avem:
if(n == 5)
return 5;
atunci funcţia va funcţiona corect pentru apeluri cu n≥5;
în caz contrar nu se va opri.
c) Dacă apelăm funcţia cu o valoare foarte mare putem obţine eroare generată de
depăşirea spaţiului de memorie.
Exemplu: Peano(214748364) //OK
Peano(412400012) //eroare
Exemple de programe rezolvate recursiv:
1) Aranjamente ( I)=iterativ, R)=recursiv)
R) int aranjamente(int n, int k)
{if(k == 0)
return 1;
else
return n*aranjamente(n-1, k-1);}
I) int aranjamente(int n, int k)
{int i; float a = 1;
for(i=n; i>=n-k+1; i--)
a = a*i;
return a;}
2) Combinări
R) int combr(int n, int k)
{if((n == k)||(k == 0))
return 1;
else
return (combr(n-1, k-1) + combr(n-1, k ));}
3) Minimul într-un vector – metoda DIVIDE ET IMPERA
#include<iostream.h>
int n, i, x[20];
int minim(int x[], int inceput, int sfarsit) {
int m1, m2, mij, m;
if((sfarsit-inceput) == 1)
{if (x[inceput]>x[sfarsit])
m = x[sfarsit];
else
m = x[inceput];}
else
{mij = (inceput + sfarsit)/2;
m1= minim(x,inceput,mij);
m2 = minim(x,mij,sfarsit);
if(m1<m2)
m = m1;
else
m = m2;}
return m;
}
FIŞIERE
OBS. În C nu există instrucţiuni de intrare/ieşire (în sens clasic). Operaţiile de intrare/ieşire
sunt realizate prin apelul unor funcţii ale sistemului de operare. Aceste operaţii sunt
implementate prin funcţii sub o formă compatibilă cu diverse sisteme de operare.
Un fişier e o colecţie ordonată de articole (înregistrări) păstrate pe un suport de memorie şi
identificate printr-un nume.
OBS! Pentru fişierul standard de intrare datele sunt introduse de la tastatură, iar pentru cel
standard de ieşire sunt afişate pe aşa numitul terminal de ieşire. Erorile se afişează în
fişierul standard de eroare. Există un articol ce marchează sfârşitul fişierului, care pentru
fişierul standard de intrare, pentru DOS şi WINDOWS, se generează cu Ctrl+Z.
Operaţii specifice cu fişiere: deschiderea / închiderea, crearea, citirea, actualizarea
(modificarea), adăugarea la sfarşit, poziţionarea în fişier, schimbarea numelui fişierului,
ştergerea.
Prelucrarea se poate face pe două niveluri:
a. inferior (se apelează direct la sistemul de operare);
b. superior (utilizând structuri speciale tip FILE);
OBS! Funcţiile standard de intrare / ieşire au prototipurile în fişierul antet < stdio.h >.
Clasificare:
- fişiere text;
- fişiere binare.
În orice fişier text datele sunt memorate ca şiruri de caractere, linii separate prin Enter.
Într-un fişier text spaţiul de memorare pe disc nu e folosit eficient. Într-un fişier binar
datele sunt păstrate în formatul lor intern.
Pentru fişiere text EOF (end of file), caracterul OX1A există fizic în fişier. La întâlnirea
lui, funcţia fgetcc întoarce EOF (-1). Pentru fişierele binare, marcajul de sfârşit de fişier e
generat de fgetc (nu există fizic).
OBS. În DOS (Unix) intrările / ieşirile standard pot fi redirectate în fişiere disc la
nivelul liniei de comandă, gen: ”<” redirectează intrarea spre fişierul specificat ,”>”
redirectează ieşirea spre fişierul specificat.
Accesul la fişiere: atât fişierele standard cât şi la cele de pe disc sunt gestionate prin
pointeri la structuri specializate tip FILE ce se asociază acestora pe durata prelucrarii.
Declararea unui pointer într-un fişier în C se face prin *pf.
Deschiderea unui fişier:
a) înainte de prelucrare;
b) se asociază unui nume de fişier un pointer la acesta;
c) se stabileşte un mod de acces la fişier;
Prototipul funcţiei FILE *fopen(char *nume_fisier, *mod_acces).
Deschiderea presupune crearea unei conexiuni între fişier şi variabila pointer şi
alocarea unei zone de memorie.
Funcţia întoarce un pointer la fişier dacă deschiderea e corectă sau NULL în caz
contrar.
Moduri de acces:
a) citirea ”R” (citirea din fişier inexistent dă eroare);
b) scrierea ”W” (dacă fişierul există deja, el va fi şters).
OBS! Fişierele standard nu trebuie deschise. Redirectarea unui fişier deschis se poate face
cu FILE *freopen(char *nume, char *mod, FILE *fisier).
Fişierul deschis este închis, se deschide unul nou avand ca sursa fluxul
(fişier), de nume (nume) şi modul de acces specificat (mod): instrucţiunea fclose.
Închiderea unui fişier se face după terminarea prelucrărilor.
OBS: La apelul ”exit” toate fişierele se închid automat.
int fclose(FILE *pf )
Întoarce 0 la închiderea normală şi EOF la eroare.
OBS: Fişierele standard nu se închid.
Pentru un fişier de ieşire se scriu datele nescrise din buffer în fişier. Închiderea e
obligatorie pentru un fişier de intrare.
Operaţii de intrare / ieşire la nivel de caracter
int fputc(char c, FILE *pf)
OBS. Funcţia întoarce primul parametru sau EOF în caz de eroare.
int fgetc(FILE *pf) – citeşte un caracter dintr-un fişier. Întoarce ca rezultat următorul
caracter citit din fişier. EOF dacă s-a citit sfârşitul sau s-a produs o eroare.
Operaţii de intrare / ieşire pentru şiruri de caractere
char fgets(char *s, integer, FILE *pf) – citeşte caractere din ”pf ”(fişierul considerat),
cel mult (n-1), în tabloul ”s”; pune la sfârşit ’\n’ (Enter) şi marcajul de sfârşit de şir ’\
o’; (citirea se face pâna la întâlnirea unui Enter) intoarce ’s’ sau NULL la întâlnirea lui
EOF sau eroare.
char *fputs(char *s ,FILE *pf ) – un string în FILE; copiază şirul în fişierul de ieşire,
nu copiază terminarea de şir ’\o’. Întoarce numărul de caractere scrise în fişier sau EOF
la eroare.
Moduri de acces
Situaţii :
1. fişierul nu există: dorim să-l creăm şi să punem informaţii în el - ” W ” ;
2. fişierul există: dorim să extragem informaţii din el - ” R ” si ” R+ ” ( citire şi scriere);
3. fişierul există: dorim să adăugăm pastrând informaţiile existente
a: deschiderea spre adăugare la sfarşit ;
a+: citire şi adăugare. Dacă nu există el va fi creat;
4. fişierul există: dorim să punem alte informaţii ştergându-le pe cele existente - ” w+ ”
(citire şi scriere) .
OBS. Modul de acces binar se specifică cu ” b ” . Avem : ” Rb ” , ” W+b”. Modul text
este considerat implicit, dar se poate specifica prin ” t ” .
Intrări / ieşiri cu format
1. Scrierea cu format
int printf( FILE *pf , char *format , lista_expresii ; –
transferă în fişierul specificat valorile expresiei convertite conform formatului. Întoarce
numărul de caractere scrise dacă am eroare .
OBS. Un descriptor de conversie pentru format are sintaxa:
%[ indicator ][ latime ].[ precizie ][ spec.lung];
Unde ” indicator ” poate lua ca valori : ”-” pentru aliniere la stânga, ”+” pentru afişare cu
semn, ”0” pentru completarea la stânga cu zerouri, adăugare spaţiu înaintea cifrei dacă
numarul este pozitiv. ”lăţimea” indică lăţimea maximă în care se face scrierea. ”precizia”
este un număr interpretat în funcţie de descriptorul găsit, astfel, dacă descriptorul este :
%a , %E , %f atunci precizia este egală cu numărul de cifre zecimale. Dacă descriptorul
este string ( %s ) atunci precizia este numărul de caractere din şir. Dacă descriptorul este :
%d , %i atunci precizia este numărul minim de cifre cu zerouri în faţă . Specificarea
lungimii se face prin: M( short ), l( long ), L (long double).
2. Citirea cu format
int fcanf( FILE *pf , char *format , lista_var ) ; - se citesc date din ”pf” cu format,
iniţializându-se variabilele din listă . Se întoarce numărul de câmpuri citite sau EOF la
întâlnirea lui EOF sau eroare .
Intrările/ieşirile în modul de acces binar sunt citiri/scrieri fără conversii la nivel de articol,
iar poziţia fiecărui fişier este actualizată după fiecare citire/ scriere.
unsigned fread( void *zona unsigned la unsigned na , FILE *pf ) ; - se citesc
cel mult ”na” articole, de lungime ”la”, din fişierul ”pf ” în ”zona” . Întoarce numărul de
înregistrări citite (na) sau 0 în caz de eroare sau EOF .
unsigned fwrite( void *zona , unsigned la , unsigned na , FILE *pf ) ; - se scriu
”na” articole, de lungime ”la” , din fişierul ”pf ” în ”zona”. Întoarce numărul de articole
scrise sau 0 în caz de eroare sau EOF .
Operaţii pentru fişiere cu acces direct
a) Poziţionarea în fişier
int fseek ( FILE *pf , long depl , int orig ) ;
- modifică poziţia curentă în fişierul pf cu depl octeţi relativ la cel de-al 3-lea
parametru orig ;
- astfel: *faţă de începutul fişierului: orig = 0 (SEEK_SET)
*faţă de poziţia curentă: orig = 1 (SEEK_CUR)
*faţă de sfârşitul fişierului: orig = 2 (SEEK_END);
- întoarce 0 pentru poziţionare corectă şi diferit de 0 în caz de eroare; OBS.
Procedura void rewind ( FILE *pf ); realizează o poziţionare la începutul fişierului, fiind
echivalentă cu fseek ( pf 0L , SEEK_SET ); .
b) Poziţia curentă în fişier
long ftell ( FILE *pf );
- întoarce poziţia curentă în fişier dată prin numărul de octeţi faţă de începutul
fişierului;
c) Tratarea erorilor
- int feof ( FILE *pf ) ;
- întoarce o valoare nenulă dacă s-a găsit eof;
- int ferror ( FILE *pf ) ;
- întoarce o valoare nenulă dacă s-a detectat o eroare în timpul operaţiei de I/O.
Fluxuri de I/O in C++:
OBS. Prin flux înţelegem o clasa. Astfel putem clasifica fluxurile în:
- fluxuri de I / O standard (pentru monitor , tastatură );
- fluxuri de I / O folosind fişiere;
- fluxuri de I / O în memorie .
OBS. cout<<x – cout este un obiect de tip flux de ieşire standard iar transferul informaţiei
în fişier se realizează prin operatorul << supraîncărcat .
- similar , cin este obiectul flux de intrare standard;
- ambele obiecte sunt declarate uzual în iostream.h;
Utilizatorul îşi poate defini propriile fluxuri ca obiecte în clasele:
- ofstream pentru operaţii de scriere;
- ifstream pentru operaţii de citire;
- fstream pentru operaţii mixte.
OBS. La folosirea acestor clase se include antetul fstream.h .
- asocierea fişier-flux (deschidere fişier) se face cu funcţia membru open() cu
sintaxa:
void open(char *nume_fisier int mod , int acces )
- modul în care poate fi deschis un fişier este precizat în clasa ios prin
enumeratorii:
*in – fişierul se deschide pentru citire şi trebuie să existe;
*out – fişierul se deschide pentru scriere. Dacă există deja se suprascrie;
*ate – fişierul se deschide pentru adăugare la sfarşit. Dacă nu există se creează
automat;
*app – fişierul se deschide pentru adăugare la sfarşit, dar trebuie să existe;
*trunc – dacă fişierul există va fi şters şi se va crea unul nou pentru scriere;
*nocreate – fişierul trebuie să existe;
*noreplace – fişierul este deschis însă conţinutul lui nu-i poate fi înlocuit;
*binary – fişierul deschis va fi prelucrat ca un fişier binar.
Exemple: fstream f;
f.open (“situatie.dat” ios: in) ;
Modul de acces acces poate fi 0 (fişier fără restricţii de acces), 1 (fişier protejat la
scriere) , 2 (fişier ascuns) , 4 (fişier sistem) , 8 (fişier arhivă).
Desfacerea legăturii fişier–stream se face cu close() .
OBS. Dacă în urma deschiderii variabila stream = null atunci operaţia de deschidere a
eşuat.
Exemple: fstreamf g ;
if (!g.open (“note.in ios: in )
{cerr<<” eroare la deschidere !\n “ ;
exit(1) ; }
Operatorii de inserţie şi extracţie pot fi folosiţi pentru a scrie/citi din/în fişier.
Funcţia Explicaţie
void open (char *nume, int mod, int acces);
void close ();
istream &get (char &c);
int peek ();
istream &putback ();
istream &get (char *sir, int n, char sep=’\n’);
istream &getline (char *sir, int n, char sep=’\
0’);
istream &read (char *sir, int n);
int gcount ();
int tellg ();
istream &seekg (long depl, int orig = ios ::
beg);
deschide fişierul;
închide fişierul;
citeşte un caracter din fluxul de intrare; la
întâlnirea lui eof întoarce null;
preia următorul caracter din fluxul de
intrare, fără a-l extrage;
pune înapoi în fişier un caracter;
se citesc cel mult n-1 caractere sau până la
întâlnirea lui set, care este pus în şir;
se citesc n-1 caractere până la întâlnirea lui
set, în locul căruia este pus acest terminator
‘\o’ (sfarşit de şir de caractere);
citeşte cel mult n caractere binare;
determină câte caractere s-au citit în ultima
operaţie de citire;
determină poziţia curentă a citirii;
deplasare cu depl octeţi faţă de început /
poziţie curentă / sfarşit;
ios ::
cur
ios ::
end
ostream &put (char c);
ostream &write (char *c, int n);
long tellp ();
ostream &seekp (long depl, int orig = ios ::
leg);
introduce ‘c’ în fluxul de ieşire;
scrie cel mult n caractere în fluxul de ieşire;
determină poziţia curentă la scriere;
deplasare cu depl octeţi faţă de început.
Exemplu:
void main ()
{ofstream out;
ifstream in;
out.open (“ iesire.dat ”);
out<<” Vasilica invata C ”;
out.close();
in.open (“ intrare.dat ” );
char linie[80];
in>> linie;
cout<<linie; }