05 April 2014

Programare Procedurala Avansata Curs



Pointeri (declaratia Pointerilor)
Un mod obisnuit de alocare asociere nume_variabila – zona de memorie este constanta pe toata durata executiei programului(alocarea se face in faza de compilare iar dealocarea pe parcursul executiei programului nu este posibila.
Pointerii sunt varabile in care se pot memora adrese de memorie. Ei ofera posibilitatea de a aloca dinamic memoria, adica pe parcursul executiei  unui program se pot aloca sau dealoca zone de memorie asociate lor.
Forma generala de alocare a unui pointer:
Tip *var; (pointer catre int , void..)
            Tip – tipul de date asociat variabilei pointer cu numele var
Ex: int *x, int *y;
            Void *z; double *p[20];
Obs: orice var pointer trb inintializata cu o valoare valida(0 sau o anumita adresa), obiectele au adrese diferite de 0 iar pentru 0 se foloseste constanta NULL(stdio.h)).


Operatorii & si *
Obs: La o variabila pointer putem fi interesati de :
adresa pe care o memoreaza
valoarea ( informatia memorata la aceasta adresa )
amandoua
O metoda de a obtine adresele unor variabile pentru a fi memorate intr-un pointer este oferita de operatorul &, numit operator de referentiere sau adresare.
Operatorul * este numit operator de dereferentiere sau indirectare. El permite accesul indirect la informatia memorata in zona de memorie referita de pointeri.
Daca P este un pointer si contine valoarea unei adrese de memorie, atunci *P furnizeaza continutul locatiei a carui adresa este memorata in P.
int x,*p,;
p=&x; 
Ceea ce este mai sus este corect si are intelesul ca adresa var x este memorata in p.
Obs:
Declaratiile void * se folosesc in situatiile in care nu trebuie precizat in mod expres tipurile pointerilor, tocmai pentru a permite scrierea functiilor cat mai generale din punct de vedere al timpurilor pe care le manevreaza.


Pointeri si tablouri unidimensionale
In C numele unui tablou este echivalent cu un pointer constant catre primul element al tabloului, adica sunt corecte referirile: t,&t,&t[0], unde t este pointer catre tipul de baza al tabloului si reprezinta adresa la care e memorat tabloul.


Pointeri catre tipul char si sirul de caractere
Se pot enumera constante sir la o adresa indicata si de un pointer catre un char:
char *a = “Suntem la curs” ;
Linia este valida deoarece intalnind-o, compilatorul v-a memora sirul intr-o tabela de siruri generand sirul “a” catre adresa sirului.
Daca dorim sa afisam pe ecran mesajul continut in sir, este necesar sa scriem:
printf(“a”);
printf(“/s”,a);
char *sir; in declaratie, sir poate avea mai multe interpretari:
-           sir este pointer catre char;
-           sir de caractere;
-           vector de caractere alocat dinamic.


-           Declararea unui pointer catre un tablou unidimensional de dimensiune “dim” se face sub forma:
tip (*var)[dim];
Ex:
int (*d)[10];

Pointerul “d” arata catre primul element al unui tablou format din 10 intregi, iar orice incrementare a lui cu o unitate, t++ inseamna:
t = t+10* sizeof(int)
Obs:
Nu sunt echivalente :
1)         tip *var[dim];
2)         tip (*var)[dim];
In 1) avem ca var este tablou de pointere catre tipul “tip”
in 2) avem pointeri catre un tablou cu “dim” componente de tipul “tip”.
In 1) incrementarea cu o unitate inseamna pozitionarea pe adresa urmatorului element al tabloului pe adresa urmatorului element al tabloului, adica :
1)         var++ ↔ var = var + sizeof(tip)
2)         var++ ↔ var = var = var + 10 * sizeof(tip)


Au sens operatii de adunare si scadere a unui pointer cu un nr. intreg, astfel:
p,n
p+n → adresa lui p + n*sizeof(tip) → tip este tipul pointerului.
p-n → adresa lui p – n*sizeof(tip)
int *p1,*p2;
float *p;
1)         p2=p1+3;
2)         p-=5          ( alta scriere: p=p-5)

p2 contine p1+3*sizeof(int)  sizeof(int)=2
p2=p1+3*2
p-=5
p=p-5*4
Daca x[n] este un tablou cu n componente, atunci pentru orice i=0, i≤n
x=i ↔ &x[i]
*(x+i) ↔ x[i]

Scaderea a doi pointeri P1 si P2 are sens in cazul in care P1 si P2 au acelasi tip de baza si se refera la elementele aceluiasi tablou.
t=tablou
P1=&t[i1];
P2=&t[i2];
P1-P2→i1-i2


Structuri – reprezinta colectii de date neomogene, grupate sub acelasi nume intr-o zona de memorie compacta.      Declaratia unei structuri are forma generala:
Struct nume_struct
{           Tip 1 camp 1
            Tip 2 camp 2
            Tip n camp n}
 Lista variabila; - este o lista de variabile a carui tip este dat de tip struct_nume struct
            Obs: nume_struct si lista_variabile sunt optionale, dar nu pot lipsii in acelasi timp.
            Operatorul „.” – selectarea unui camp se face utilizand operatorul „.” Astfel:
                        Nume_variabila structura.nume camp
Ex: pers1.nume; pers2.tel    Obs: asupra unui camp selectat se pot aplica toate operatiile care se pot aplica unei variabile de acelasi tip cu campul.
            Operatorul „->” – daca o variabila este un pointer catre o structura accesul la un camp al structurii se face utilizand operatorul sageata, sub forma:
            Nume_pointer structura->nume camp
Ex:       struct rand telefon *pers3;   Pers3->nume
Obs: se remarca faptul ca operatorul sageata este o sinteza a operatoriilor * si „.”. astfel expresia pers3->nume ↔(*pers3)nume
            Operatorul sizeof – marimea unei structuri se calculeaza folosiind operatorul sizeof.
Ex: sizeof(struct rand_tel)
Obs: este recomandata folosirea acestui operator si nu calculul manual atat din motive de portabilitate cat si de corectitudine(in unele situatii compilatorul pri aliniierile pe care le face obtine un necesar de memorie mai mare decat dimensiunea obtinuta manual).
            Initializarea unei variabile de tip structura
            O var de tip structura poate fi initializata astfel:
            Declaratie_structura={lista_valori initiale};
Ex: struct rand_tel pers1={„ionescu”.”ion”.”ploiesti str republicii”, 12345};
            Copierea unei informatii dintr-o structura in alta structura de acelasi tip este posibila printr-o simpla instructiune de atribuire:
Ex:       pers1=pers2;  pers1 nume <- nume="" p="" pers2="">
                                       Pers1 pren <- p="" pers2="" pren="">
            Structuri implicate – o structura poate fi inclus in alta structura obtinandu-se structuri implicate.
Ex:       struct info_pers
            {
                 Struct rand_tel info;
                  Int varsta;
                  Float salariu;        }     angajat;
            Angajat.info.nume
Obs: in interiorul unei structuri, numele campurilor trb sa fie diferite , insa 2 structuri diferite pot avea nume de campuri identice.
Obs: atat numele structuri cat si numele unui camp al structurii pot coincide cu numele unei variabile
Obs: o structura nu poate contine campuri care sunt de acelasi tip cu structura in care apar, totusi campurile unei structuri pot fi pointeri catre structura din care fac parte, acest lucru permite crearea unor structuri recursive foarte utile in implementarea dinamica a cozilor, stivelor, arborilor, graurilor.
in C exista posibilitatea sa accesam un bit din memorie prin intermediul campurilor de biti.
            Forma generala a declaratiei unui camp de biti este:
            Struct nume_struct
            {
                        Tip nume_camp1: lungime;
                        Tip nume_camp2: lungime;
                        Tip nume_campn: lungime;
            }lista variabile;
Unde,
            Lungime – reprezinta numarul de biti al campului
            Tip – poate fi unsigned sau signed.
Obs: un camp de biti este defapt membrul unei structuri caruia i se precizeaza lungimea(nr de biti). Din acest motiv accesul la informatia obtinuta intr-un camp se face cu operatorii .(punct)(static) si ->(sageata)(dinamic)
Obs: nu toate facilitatiile oferite de structuri sunt valabile si in cazul campurilor de biti. Astfel:
            -nu se poate utiliza operatorul & pt a lua adresa unui camp;
            -numele unui camp nu poate fi numele unui tablou;
            -ordonarea campurilor este dependenta de implementare.
            Importanta utilizarii campurilor de biti  - is gasesc utilizarea inspecial in programarea de sistem, deoarece permit gestionarea regristriilor hardwear. Cu ajutorul lor se pot descrie eficient anumite atribute de stare ale unor dispozitive. Ex: consideram un dispozitiv cu 6 componente , daca fiecarui componenta ii atasam un bit de stare (1 – functioneaza, 0 – nu functioneaza), atunci starea intregului dispozitiv poate fi descrisa prin structura urmatoare:
            Struct stare_disp
            {
                        Unsigned camp1:1;
                        Unsigned camp2:1;
                        Unsigned camp6:1;
            }stare;
            Stare.camp4 – furnizeaza starea acestei componente;
Avantaj: in loc sa foloseasca 6 octeti pt codificare se foloseste doar 1 octet
            O structura poate contine atat campuri obisnuite cat si campuri de biti.
Ex: struct stare_student
            {char nume[40];
             Unsigned nota:4;
            Unsigned adm:1;
              Unsigned rest:3;
            }student;


o uniune este o structura de date care permite folosirea in comun a aceleiasi zone de moemorie de doua sau mai multe variabile diferite la momente de timp diferite.
            Forma generala de declarea a unei uniuni:
                        Union nume_union
                        {tip nume_camp1;
                        Tip nume_campn;
                        }lista_variabile uniune;
            Precizarile facute la structuri referitaore la relatiile dintr uniuni, numele uniuni, numele campurilor numele variabielelor din lista_var_uniune si numele oricareai variabile raman valabile si aici.
            Pentru selectarea campurilor vom folosii operatorii „.” Si „->”. Operatorul sizeof aplicat tipuli de date union v-a da lungimea uniunii. In acest caz sizeof va da o valoare mai mare sau egala cu cea mai mare lungime a camporilor uniunii.
            Deosebiea fundamentala intre o uniune si o structura este modul in care capurile utilizeaza memoria. La structura zonele rezervate campurilor diferite sunt si ele diferite; la uniuni toate campurile impart aceiasi zona de memorie din acest motiv datele memorate intr-o uniune pot fi referite diferit in functie de tipul membrului pe care i-l avem in vedere.
Ex: union una
            {int i;
             Float f;
            }v;
Datele din variabila v vor f privite ca intregi daca selectam v.i si ca reale daca selectam v.f. campurle i si f se refera la aceiasi zona de memorie. In v.i se memoreaza sizeof(int) iar in v.f se memoreaza sizeof(float).
Obs: este posibila intitializarea unei uniuni cu o constanta, care trb sa fie de tipulr primului camp declarat.
Ex: union ceva
            {int i;
              Float f;
            }={375};
            Folosind unuiunile si campurile de biti se poate accesa cu usurinta inormatia la nivel de bit a unei variabile.
            Pentru interpretarea corecta a informatiei dintr-o uniune deobicei se pastreaza intr-o varaibila ajutatoare, informatii despre continutul curent al uniunii.


O enumerare reprezinta o lista de constante intregi cu nume
Sintaxa:
enum nume_enumerare { lista enumerare } lista de variabile;
nume_enumerare si lista enumerare sunt optionale
Lista enumerare reprezinta toate valorile pe care le pot lua variabilele din lista de variabile.
Ex:                       0      1       2          3       
enum culoare { rosu, alb, verde, albastru } culoarea_mea;
culoarea_mea = verde;
Elementele din lista de enumerare sunt constante intregi cu valorile implicite 0,1,2……etc. Aceste constante nu se pot citi si nu se pot scrie in mod nemijlocit.
Ex:
Numerele prezente in lista enumerare pot primi in mod explicit anumite valori.
enum saptamana (luni=1, marti, joi=4, vineri, sambata, duminica) zi;
                                             2                   5           6              7
   zi=vineri;
   switch (zi)
   case luni:printf (“\n luni”);break;
   …..
   case vineri:printf (“\ vineri”);break;


scopul typedef este de a atribui denumiri alternative la tipurile existente. De cele mai multe ori se foloseste la tipurile a caror declaratie este greoaie sau poate varia de la o implementare la alta.
Typedef struct { tip_camp1 nume_camp1;
                         Tip_camp2 nume_camp2;
                                      ............................................
                          Tip_campn nume_campn;
            } nume_tip_nou;
Nume_tip_nou nume_var;
Nume_tip_nou *nume_pointer;


O functie poate fi definita sau declarata. Definirea functiei cuprinde antetul functiei (declaratorul) si corpul functiei. Declararea unei functii se refera doar la elementele din antetul ei.

            Definirea unei functii
In limbajul C exista 2 forme de definire a unei functii: forma moderna si cea clasica. Desi strandardul ANSI C recomanda folosirea formei moderne, totusi, din motive de portabilitate, standardul accepta si forma clasica de definire a functiei

In definirea moderna are forma:
tip nume_functie (liste declaratii parametrii)
{
corpul functiei
}
Tip reprezinta rezultatul intors de functie.
Se impart in: functii care nu intorc un rezultat (void) si functii care intorc un rezultat
Functiile care intorc un rezultat se impart in: functii care intorc valori intregi si functii care nu intorc valori intregi.
Functiile care intorc un rezultat de tip intreg trebuie sa aiba precizat in mod explicit cuvantul int sau sa nu aiba precizat nimic.
Lista declaratii parametrii trebuie sa contina cel putin tipurile parametrilor. In mod curent lista contine numele parametrilor precedati de tipurile lor.
f(int, int);
float f(int x, float y);
{ …. }
Nu pot sa am numai x si y, nu pot sa am numai f(int x,y)
Cand lista de parametrii este vida trebuie pus intre paranteze cuvantul (void). Corpul functiei este format din declaratii locale si instructiuni. O functie care intoarce o valoare trebuie sa contina cel putin o instructiune return.
Intructiunea return are forma return (expresie), unde expresie poate sa lipseasca. O functie poate sa contine mai multe instructiuni return.
In cazul in care return lipseste, revenirea in functia apelanta se face in momentul in care se intalneste acolada de sfarsit.
Expresia din return (expresie) se atribuie practice numelui functiei. Din acest motiv numele functiei si tipul expresiei trebuie sa fie compatibile sau de acelasi tip.
Conversiile necesare se fac exact dupa regulile folosite la atribuire.
Sintaxa unei definitii clasice pentru o functie este urmatoarea:
tip nume-functie (par1, par2, … parn)
  tip par1;
  tip par2;
 
  tip parn;
{ instructiuni }
float f(x,y) int x; float y; { if (x   
return y; else    return x; }
float (x,y) int x,y; { … }

Orice functie care returneaza valori de tip diferit de int trb declarata sau definita inainte de a fi apelata.
            Declaratiile trb facute la inceputul programului(inainte de definirea oricarei functii pt a informa compilatorul asupra tipului rezultat si a putea genera un cod corect).
            Exista doua modalitati de a declara o functie:
1.         traditionala
tip_nume_functie(); - declaratie
ex:       double aria();
            .......................
            Double aria(float a)
            {
                        Const pi=3,1415
                        Return pi *r*r;
            }
Obs: in forma traditionala lipseste orice referire la parametrii functiei.
2.         moderna
tip_nume_functie(lista_declaratii_parametrii);
unde, lista_dec_parametrii poate sa fie vida, caz in care intre paranteze se va scrie cuvantul void(void) sau poate sa contina numai lista tipurilor parametrilor.
Permite compilatorului se verifice corectitudinea apelului unei functii(se fac veriicari privind identitatea intre numarul parametrilor prototipului si numarul parametrilor actuali, iar daca este necesar, parametrii actuali se convertesc la tipul parametriilor corespunzatori din prototip inainte de a fi plasati in stiva)



Nume_functie(lista_parametrii),
Unde lista parametrii – lista de valori actuale(efective), care vor fi transmise functiei. Din acest motiv parametri din aceasta lista se numesc actuali sau efectivi.
Obs: la apelul functiei intre parametrii actuali si cei formali trb sa exista o corespondenta pozitionala(p actuali si formali situati pe pozitii indentice trb sa aiba tipuri identice sau compatibile). Compilatorul va sesiza lipsa de identitate dintre numarul parametrilor actuali si cei formali.
Conversile permise sunt cele considerate la operatiile de atribuire.
Transferul informatiei intre functia apelanta si unctia apelata se poate face prin valoare sau prin referinta.
Transferul prin valoare – consta in copierea valorilor parametriilor actuali in zona de memorie a parametrului formal corespunzator in momentul efectuarii apelului.
Obs: val parametrului actual in aces caz nu este afectata de prelucrarile din cazul functiei apelate(aceste prelucrari vizeaza copii ale parametrilor actuali si nu parametrii insasi).
Transferul prin referinta – pentru ca functia apelata sa paote modifica valoarea unei variabile indicata ca parametru actual trb sa i se cunoasca adresa. Solutia este ca parametru formal corespunzator sa fie declarat pointer si sa i se transmita la apel adresa variabilei si nu valoare.
Apelul functiilor cu parametrii actuali-tablouri
O exceptie de la regula transmiterii prin valoare o reprezinta cazul cand parametrul actual este un tablou. Deoarece copierea valoriilor componentelor tabloului intr-un parametru formal ar fi constituit un consum mare de timp s-a adoptat solutia transmiterii catre fucntie doar a adresei de inceput a tabloului. In consecinta parametrul transmis poate fi numele tabloului care este un pointer catre primul element al tabloului.
Parametrul corespunzator poate fi declarat intr-una din modalitatiile urmatoare:
a)         este declarat ca tablou cu dimensiunea egala cu dim tabloului transmis;
b)         este declarat ca tablou fara a da dim primei componente;
c)         este declarat ca pointer.


Functii recursive – recursivitatea inseamna procesul prin care o entitate de un anumit tip se poate descrie , definii sau prelucra folosid entitatii de acelasi tip.
Pe vom referii la functii recursive: care au proprietatea de a se autoapela.
Exista 2 tpuri de functii recursive:
1.         Direct recursive – f() se numeste functie recursive daca in corpul ei apar apeluri la ea insasi adica este de forma:
Tip f(lista_declaratii_parametrii);
{
Apel f()
}
2.         Indirect recursive – functile f() si g() sunt mutal recursive daca f() contine apeluri la g() iar g() contine apeluri la f()
Tip f(lista_declaratii_parametrii);
{
Apel g()
}
Obs: intelegerea notiunii de functie recursive se sprijina pe cunoasterea modului in care se face apelul unei functii.
Orice programa C compilat imparte spatiu de memorie destinat in patru zone distinct:
1-zona cod program
2-zona variabile globale
3-zona de manevra (heap) destinata alocarii dinamice a variabilelor
4-zona de stiva(stak)
Stiva este un caz particular de lista ale carei principale operatii de introducere si extragere sunt guvernate de disciplina LIFO(last in first out),

Functile direct recursive
Cazul de recursivitate cel mai des intalnit este cazul functilor direct recursive(in aceasta situatie functia apelanta este identical cu functia apelata).
Adancimea recursivitatii este data de numarul de autoapelari. Pt a nu se autoapela la infinit corpul functiei trb s acontina cel putin o instructiune “if” care pe baza testarii unei conditii asigura dupa un timp oprirea autoapelului si executia instructiuniilor amanate prin autoapel.
Ex: int f(int n)
{if(n==0) return 1;
Return n+f(n-1);}
Obs: pt o serie de problem , rezolvarea folosind functii recursive reprezinta singura soluie viabila din punct de vedere practica. Ex: quick sort, problema turnurilor din Hanoy
Problema turnurilor din Hanoy:
Se dau trei tije notate a, b, c, pe tija a se ala n discuri perforate de diameter diferite asezate unul peste celalalt asezate in ordine descrescatoare a diametrelor. Sa se gaseasca toate mutarile prin care toate cele n discuri de pe tija a sunt aduse pe tija b in aceiasi ordine utilizand tija c ca o tija ajutatoare. O mutare inseamna depplasarea unui singur disc de pe o tija pe alta peste un disc de diametru mai mare.


Clasa de memorare "auto"
Variabilele declarate in interiorul functiilor sunt implicit automate. De aceea, clasa "auto" este cea mai cunoscuta dintre toate. Daca o instructiune compusa (bloc) incepe cu declararea unor variabile, atunci aceste variabile sunt in domeniu in timpul acestei instructiuni compuse (pana la intalnirea semnului }).
Exemplu:
auto int a, b, c;
auto float f;
Declaratiile variabilelor in blocuri sunt implicit automate.
La executie, cand se intra intr-un bloc, se aloca memorie pentru variabilele automate. Variabilele sunt considerate locale acestui bloc. Cand se iese din acest bloc, sistemul elibereaza zona de memorie ocupata de acestea si deci valorile acestor variabile se pierd. Daca intram din nou in acest bloc, atunci se aloca din nou memorie pentru aceste variabile, dar vechile valori sunt necunoscute.

Clasa de memorare "register" spune compilatorului ca variabilele asociate trebuie sa fie memorate in registri de memorie de viteza mare, cu conditia ca aceasta este fizic si semantic posibil. Daca limitarile resurselor si restrictiile semantice (cateodata) fac aceasta imposibila, clasa de memorare register va fi inlocuita cu clasa de memorare implicita "auto". De obicei, compilatorul are doar cativa astfel de registri disponibili. Multi sunt folositi de sistem si deci nu pot fi alocati.
Folosirea clasei de memorare "register" este o incercare de a mari viteza de executie a programelor. De regula, variabilele dintr-o bucla sau parametrii functiilor se declara de tip "register".

Exemplu:
{
register int i;
for (i = 0; i < LIMIT; ++i)
{
. . . . .
}
} /* la iesirea din bloc, se va elibera registrul i */
Declaratia
register i;
este echivalenta cu
register int i;
Daca lipseste tipul variabilei declarata intr-o clasa de memorare de tip "register", atunci tipul se considera implicit "int".


Declaratiile "static" au doua utilizari distincte si importante:
a) permite unei variabile locale sa retina vechea valoare cand se reintra in bloc (sau functie) (caracteristica ce este in contrast cu variabilele "auto" obisnuite);
b) folosita in declaratii externe are alta comportare (vom discuta in sectiunea urmatoare);
Pentru a ilustra a), consideram exemplul:
Exemplu:
void f(void)
{
static int contor = 0;
++contor;
if (contor % 2 == 0)
. . . . .
else
. . . . .
}
Prima data cand functia este apelata, "contor" se initializeaza cu 0. Cand se paraseste functia, valoarea lui "contor" se pastreaza in memorie. Cand se va apela din nou functia "f()", "contor" nu se va mai initializa, ba mai mult, va avea valoarea care s-a pastrat in memorie la precedentul apel. Declararea lui "contor" ca un "static int" in functia "f()" il pastreaza privat in "f()" (adica numai aici i se poate modifica valoarea). Daca ar fi fost declarat in afara acestei functii, atunci si alte il puteau accesa.

Clasa de memorare "extern"
O metoda de transmitere a informatiei in blocuri si functii este folosirea variabilelor externe. Daca o variabila este declarata inafara functiei, atunci acesteia i se aloca permanent memorie si spunem ca ea apartine clasei de memorare "extern". O variabila externa este considerata globala tuturor functiilor declarate dupa ea, si chiar dupa iesirea din blocuri sau functii, ea ramane permanent in memorie.
Exemplu:
#include
int a = 1, b = 2, c = 3;
int f(void);
void main()
{
printf("%3d\n", f());
printf("%3d%3d%3d\n", a, b, c);
}
int f(void)
{
int b, c; /* b si c sunt locale, deci b, c globale sunt
mascate */
a = b = c = 4; /* valoarea lui a se modifica */
return(a + b +c);
}


Pt tratarea lor unitara, fisierele pe astfel de dispozitive sunt private ca secvente de octeti. Pozitia octetului current este memorata intr-o variabila speciala numita indicator de pozitie. Pe baza indicatorului de pozitie se poate face modificarea octetului current, citirea sau scrierea la o anumita pozitie in fisier. Dupa efectuarea operatiilor de citire sau scriere, idicatorul de pozitie este incrementat cu un numar de octeti, practic un dispozitiv fizic este transformat de sistemul de fisiere al lb C intr-un dispozitiv logic denumit flux.
Un flux reprezinta un pointer la o entitate de tip FILE care contina informatii despre: pozitia currenta in flux, idicatori de eroare, indicatori de sfarsit de fisier, zone tampon associate. Exista 2 categorii de fluxuri:
1.         Text – presupune transferul de caractere organizate in linii de caractere (o linie se termina prin caracterul newline) intr-un flux text pot intervenii anumite conversii de character si de aceea este posibil sa existe anumite nepotriviri intre caracterele introduce in flux si cele rezultate in urma transferului.
2.         Binary – reprezinta o succesiune de octeti care nu suporta nici o conversie in timpul transferului




Obs.: lansarea in executie a unui program C are drept consecinta si creearea in mod automtat a trei fluxuri standard: stdin, stdout, stderr sunt pointeri constanti catre tipul file. Celelate fisire ale programului trb deschise in mod explicit cu ajutorul functiei fopen() care conecteaza un flux la un anumit fisier.
Prototipul functiei fopen() este:
            FILE * fopen(const char * nume, const char * mod);
Unde, nume – numele fisierului, precedat eventual de calea de acces
            Mod – un sir de caractere care precizeaza modul deschiderii, astfel, caracterul text sau binar al fisierului si respective scopul deschiderii: pt citire, scriere, adaugare sau citire-scriere.
-text
            Mod= “r” citire;
                        “s” scriere;
                        “a” adaugare;
                        “r+” citire si scriere;
                        “w+” citire si scriere;
                        “a+” citire si scriere rin adaugarea la sfarsitul fisierului
-binar
            Mod= “sb”;”ab”…..
Obs.: pt a indica explicit modul text se poate adauga sufixul “t”. valorile mod de tipul “r+b” “r+t” sunt echivalente cu “rb+”, “rt+”…
            Incercarea de a deschide un fisier care nu exista in mod citire conduce la eroare;
            Daca un fisier este deschis pt scriere in modul “w”, atunci informatile continute in el va fi distrusa.
            Daca fisierul este deschis pt scriere si acel fisier nu exista atunci el va fi creat;
            Daca se deschide un fisier in modul “a” , datele vor fi adaugate la sfarsitul fisierului, in cazul in care fisierul exista, iar daca acesta nu exista el va fi creat;
            Daca operatia de deschidere a unui fisier este realizata cu success atunci functia fopen() creaza o structura FILE si intoarce adresa sa. Indicatorul de pozitie ia valorea 0 daca fisierul este deschis in modurile “r” sau “w” si o valoare egala cu numarul de octeti ai fisierului in cazul in care fisierul este deschis in mod “a”;
            Daca operatia de deschidere nu a avut success – ori nu exista ori e protejat la scriere sau riscul sa fie plin, in cazul acesta fopen() intoarce valoarea NULL.
            Operatia simetrica de deschidere a unui fisier, anume ceea de inchidere este realizata cu ajutorul functiei fclose(), care are prototipul:
                        Int flclose(FILE *fp);
            Fp – pointerul returnat de functia fopen;
Operatia de inchidere presupune:
            Deconectarea fluxului de fisiere(fapt important deoarece nu pot fi deschise un numar infinit de fisiere simultan)
            Golirea buff-erului de iesire in fisier, daca fisierul a fost deschis in mod scriere sau in mod actualizare.
            Abandonarea datelor necitite din buff-erul de actualizare daca fisierul este deschis pt citire sau actualizare.
Daca operatia de inchidere are success functia va intoarce valoarea 0. In caz contrar EOF(are valorea -1)


Functia de citire a unui carcter dintr-un fisier: int fgetc(FILE *fp); intoarce valorea carcterului citit daca operatia a avut success sau EOF cand s-a atins sfrasitul fisierului sau cand operatia nu are success
Functia de scriere unui carcter intr-un fisier: int fputc(int ch, FILE *fp); scrie in fisier un carcter pe care i-l returneaza daca operatia a avut success in caz de eroare intoarce EOF
Functii pt citirea si scriere sirurilor de caractere(intr-un fisier)
Scriere: int fputs(const char *sir, FILE *fp); - scrie in fisier la adresa sirului, in caz de success intoarce ultimul carcter scris, in caz de fail da EOF
Citire: char * fgets(char *str, int lg, FILE *fp); - citeste un sir de lungimea cel mult lg-1 carctere si la transfera in siruri str, daca intalneste un character new line, citirea este oprita iar carcterul va fi incorporate in str, sirul va fi completat automat cu carcterul \0 in caz de success functia intoarce adresa lui str iar in caz de insucces sau sfarsit de fisier se va intoarce valoarea NULL.


Fscanf() –citire
Fprintf() – scriere
O modalitate simpla de a realize operatii de transfer cu format este oferita de functiile de mai sus. Ele functioneaza exact ca functiile scanf() si printf() la nivelul consolei.
Prototipuri:
 Int fscanf(FILE *fp, const char*sir_format); - intoarce numarul de valori pt care citirea, conversia si memorarea datelor a fost facuta correct, daca apare eroare inainte a incepe citirea functia intoarce EOF
Int fprintf(FILE *fp, const char*sir_format); - intoarce numarul de caractere scrise efectiv in cazul in care operatia a avut success sau o valorea intreaga negativa in caz contrar.


Functiile fread si fwrite – pentru tranferul blocurilor de date
In ciuda avantejelor evidente, transferul cu format al datelor este mai lent decat transferul datelor sub forma binara datorita conversilor in format ASCII. De asemeni , n general, fisierul creat cu date ASCII formatate foloseste memorie mai multa decat un fisier binary.
O modalitate eficienta pentru transferul unui volum mare de date o reprezinta folosirea acestor functii fread si fwrite.
Size_t fread(void *buffer, size_t nr_oct, size_t nb, FILE *fp); - citeste din fisierul asociat pointerului fp nb blocuri , fiecare avand lungimea nr_oct octeti si le transfera in zona de moemorie indicata de pointerul buffer. Functia intoarce numarul de blocuri citite efectiv. In cazul in care s-a ajuns la sfarsitul fisierului sau daca a aparut o eroare valoarea intoarsa este strict mai mica decat acest nb
Size_t fwrite(const void *buffer, size_t nr_oct, size_t nb, FILE *fp); - scrie in fisierul fp  din zona buffer nb blocuri , fiecare avand lungimea egala cu nr_oct octeti. Valoarea intoarsa de aceasta functie este egala cu numarul de blocuri scrise efectiv daca operatia a avut success sau un numar mai mic decat nb in cazul in care functia da eroare.
            Size_t este de tip “stdio.h” – au semnficatia unui intreg fara semn


#define numere_macro sir caractere
Nume macro – identificatorul care v-a fi inlocuit in text de secventa de character
Ex: #define M 20 =/= m=20; – m v-a fi inlocuit cu 20
For(i=0;i
            Y=x[i]+7;
Ex:       #define b 20
            #define c 30
#define d 40
#define ARIA b*c
#define VOLUM ARIA*d
v=VOLUM
!!!!!!!Nu trebuie confundata substitutia in text care se face utilizand directive define cu o atribuire.
A=(B+5)*D => A=25*20=500
#define B 20
#define C B+5
#define D 20
A=C*D   =>  A=B+5*20=120
!!!! directive #define poate fi parametrizata obtinanduse o macrodefinitie
#define F(x) ((x*x)+1) – va conduce la inlocuirea secventei cu textul din partea dreapta unde parametrii formali sunt inlocuiti cu functii effective
            #define nume_macro(parametrii)
Y=f(3-1)=(3-1*3-1+1)=0 gresit
Y=f(2)=((2*2)+1)=5 bun

#include „nume_fisier” sau #include
Efectul directive consta in includerea fisierului in codul sursa unde este activate directive
In cazul in care are o specificatie si o cale de cautare completa preproc cauta direct in calea respectva indifferent de “” sau de <>, altfel el tine cont de ele, <>- fisierul va fi cautat intr-unul sau mai multe directoare standard, “”-intai se cauta in directorul current apoi in cele standard.





Un fisier antent poate contine prototipuri de functii, declaratii de varaiabile si de constante, macro definitii si directve de includere.
Exemplu .h:
Typedef struct pers
{char num[35];
Int varsta;} persoana;
Float copiere(int nume, float ..)
#define LMIN=50
#include „ante.h”

#if - #if expresie constanta
            Sectiune program
     #endif
Efectul – consta in copilarea sectiunii program numai daca expresia constanta este adevarata(=/= 0), in caz contrar sectiunea program este ignorata.
Se poate inlocuii cu comentarii.

 

#if expresie constanta
            Sectiune prgram 1
#else   
            Sectiune progra 2

#if expresie constanta 1
            Instructiuni
#elif expresie_const 2
            Instructiuni
#elif expresie_constanta n
            Instructiuni

#ifdef - #ifdef nume_macro
                   Sectiune program
            #endif
Daca nume_macro este definit atunci se executa sectiunea program, daca nu este definit nu se executa. Definit = #define M10
                                    #idfed M
                                                Sectiune program
                                    #endif
 

 
Functii video (prezentare generala)
Functii grafice – in c nu s-au standardizat functiile grafice.
Pentru borland c
Tinta oricarei reprezentari grafice este sa aduca imaginea de pe ecran la nivelul de performanta al unei fotografii. Grafica se poate realiza cu ajutorul interetelor grafice sau al adaptoarelor video.
Acestea contin memorie ram video care permite reinprospatarea permanenta a imaginii de pe vdeo monitor. In mod traditional exista 2 moduri de lucruri:
1.         Text
2.         Grafic
Adaptoare video: MDA (monochrome display adaptor);
CGA (color graphyics adpater);
EGA (Enchanced Graphycs Adapter);
VGA (Video Graphics Arrey Adapter)
1.In modul TEXT se lucreaza cu caractere iar carcterul este reprezentat prin 2 octeti.Primul contine codul ASCII iar al doilea atributele de afisare. BFFFFCCC – F=codul culorii backgroudul; C-codul cuorii;B-blink
            Ecranul este privit ca o retea celulara , fiecare celula poate memora un carcter. Originea ecranului este in coltul din stanga sus (1:1).
1:1
2:1
3:1




1:2

3:2




1:3






1:4







O modalitate foarte rapida de afisare si care nu consuma multa memorie.
2.In modul grafic ecranult este vazut k o retea foarte fina in modul PIXEL (picture element). Pixelul este ceea mai mica zona care poate fi „aprinsa” pe ecran. Culoarea pixel este reprezentata intr-un numar de biti in memoria video.
Orginea este tot in coltul stanga sus si are coordonatele (0:0).
Adaptoarele video sunt carcterizate prin rezolutie spatiala si rezolutie de culoare. Rezolutia spatiala in modul text se refera la numarul de linii si numarul de coloane, iar in modul grafic inseamna numarul de linii si numarul de pixeli pe linie
Rezolutia de culoare – are in vedere numarul de culorii afisate simultan.
Modul grafic necesita procesoare de mare performanta si capacitatea de memorie sporita pt a reprezenta pixelii.
Modul text permite reprezentari grafice rudimentare, iar modul grafic permite reprezentari grafice de mare finete. In ambele moduri exsta posibilitatea de apreciza zone dreptunghiulare pe ecran unde se pot afisa texte, grafice, acestea se numesc ferestre. Definirea ferestrelor se poate face cu niste functii grafice speciale in care se precizeaza coltul din stanga sus si coltul din dreapta jos.

CCSuite - CC Monitoring, CC Reports and AliveCheck

CC Monitoring, CC Reports and AliveCheck Create together a powerful application, user friendly, that helps managing, monitoring ...