Sunteți pe pagina 1din 270

De ce sa invat un limbaj de programare?

 Programele comerciale sunt scumpe


 Nu exista un program (comercial sau gratis) pentru fiecare problema particulara
 Dezvoltarea gandirii logice, algoritmice
 Intelegerea mai profunda a functionarii dispozitivelor electronice
 Cresterea numarului optiunilor pentru obtinerea unui job
 Foarte multe probleme de fizica pot fi rezolvate (numai) cu ajutorul
computerelor => necesitatea unui program
 Echipamentele de cercetare folosesc rutine de calcul pentru prelucrarea datelor
=> intelegerea modului de lucru si folosirea eficienta a infrastructurii
 Cresterea productivitatii folosirii pachetelor software disponibile (de ex. Macros
in Excel)
Pentru ca exista in planul de invatamant ...
De ce C?
 Exista de peste 30 de ani
o multe programe disponibile
o probleme legate de limbaj au fost rezolvate
 Limbaj puternic si versatil
 Precursor pentru C++, Java, C#
 Folosit pe scara larga de catre comunitatea stiintifica
 Eficienta sporita in programare (pointeri, lucrul pe biti,
alocare dinamica a memoriei, etc.)
 Resurse bibliografice multiple, numar mare de librarii existente
 Multe instrumente stiintifice sunt programate in C (de ex. Camere CCD)
 Compilatoare “free”

De ce nu C++? http://www-pnp.physics.ox.ac.uk/~tseng/teaching/lab/handbook_C.pdf

Programarea “orientata obiect” este o complicatie ne-necesara pentru calculul


stiintific in fizica
Evaluare: acordarea notei
2.5 p – proba orala teoretica (in sesiune)
2.5 p – proba practica (in sesiune)
2.0 p – doua teste pe parcurs
(saptamana 5 (29.10) si saptamana 10 (03.12), 1 p pt. fiecare)
1.0 p – bonus prezenta si activitate la curs si laborator
1.0 p – teme
1.0 p – proiect individual, la alegere (optional)

Syllabus

FLR1304
Link-uri utile
Functii matematice: http://en.wikipedia.org/wiki/C_mathematical_functions

Functii grafice: http://www.programmingsimplified.com/c/graphics.h


CURS 1
Definitii

Fujitsu-Siemens Server
Dell , i7-2600 4 procesoare Intel Xeon
3.4GHz, MP@3.00GHz,
8 cores 16 cores
6GB RAM 40GB RAM
1TB HDD 538 GB HDD

HPC@UBB
Intel Xeon @ 2.2 GHz
~ 2000 cores
~ 80 TB RAM
~ 2000 TB HDD 7.2K
48°51′24″N 2°21′03″E
Se va tine
cont de
situatii
neuzuale!!
int cmmdc( int a, int b) //functia fact cu instructiune for
{
int r, cmmdc; double fact(int n)
{
do double f=1.0;
{ int i;
r=a%b;
cmmdc=b; if(n>1)
a=b; for(i=2;i<=n;i++)
b=r; f=f*i;
} return f;
while(r!=0); }
return cmmdc;
}
CURS 2
Reprezentarea numerelor intregi si reale
F.Boian, Bazele matematice ale calculatoarelor, UBB Cluj-Napoca, 2002

Sistem de numeraţie
- totalitatea regulilor folosite pentru scrierea numerelor cu ajutorul unor simboluri
(cifre).

Palatul Josika (Casa cu picioare) este înălţat pe locul fostei reşedinţe


clujene a principilor Transilvaniei. Clădirea a devenit reşedinţa lui Anton
Josika, comite al Clujului, la mijlocul secolului al XVIII-lea. Clădirea în stil
neoclasicist a căpătat înfăţişarea de astăzi în anul 1828, când a fost
refăcută de Josika Janos, guvernator al Transilvaniei.
Elementul caracteristic în faţadă este porticul sobru cu coloanele dorice.
Atica poartă inscripţia MDCCCXXVIII (1828), anul renovării clădirii.
2. Sistemul de numeraţie arab
- sistem poziţional
- aportul unei cifre în stabilirea valorii unui număr depinde de valoarea cifrei şi de
poziţia ocupată în şirul de cifre folosit.
Trebuie cunoscute cifrele numărului care se transformă!
Bit - unitatea de informaţie folosita pentru stocarea si transmiterea informatiei

Mbps (Mb) – unitatea de masura pentru viteza de transmisie (download si upload) in internet

Byte (octet) - unitatea de adresare (8 biţi)


MB  Mb
1KB = 210 (1024) biti
1MB = 220 (1048576) biti
etc.

65
A
01000001 = ? . Depinde de codificare si dispozitivul catre care se trimite data

etc.
Locaţie de memorie - unitatea de reprezentare a unei date, formată din unul sau mai mulţi octeţi

Word – număr de octeţi prelucraţi simultan de către procesor


- numerele reale se reprezintă de obicei pe un cuvânt = lăţimea de bandă

Nyble
- grup de 4 biti (jumatate de octet)
- poate stoca 16 valori (0-15)
- corespunde unei cifre hexa ("hex digit"
sau "hexit“)
 În memoria computerelor, numerele sunt reprezentate ca şi numere binare, pe un anumit număr
(finit) de biţi.
 Valorile care pot fi reprezentate depind de numărul de biţi folosiţi pentru respectiva reprezentare.

Exemple
2 biti 0 0 0 1 1 0 1 1 valoarea maxima: 3
8 biti 1 1 1 1 1 1 1 1 valoarea maxima: 255

Dacă trebuie reprezentate numere întregi cu semn, atunci un bit din numărul total de biţi ai
reprezentării va fi folosit pentru semnul numărului
->bitul de rang maxim (cel mai din stânga):
Reprezentarea numerelor pozitive in complement fata de 2
Reprezentarea numerelor negative in complement fata de 2

Pentru a reprezenta în complement faţă de 2 un număr întreg negativ


- se reprezintă modulul său
- începând de la bitul de ordin zero spre stânga toţi biţii 0 şi primul bit 1 se păstrează
- toţi ceilalţi îşi inversează valoarea (0->1 şi 1->0)
27 numere pozitive
27 numere negative
Cel mai mare nr. pozitiv

Cel mai mic nr. pozitiv


Cel mai mare nr. negativ

Cel mai mic nr. negativ


Se obtine din cel mai mare nr. pozitiv reprezentabil,
prin rasturnarea tuturor bitilor
Alte coduri de reprezentare a valorilor întregi sunt:
1. Codul direct
Bitul de rang n-1 (cel mai din stânga) este rezervat pentru semn.
Un număr negativ se reprezintă în cod direct reprezentând modulul său după care bitul de
semn ia valoarea 1.

2. Codul invers
Bitul de rang n-1 (cel mai din stânga) este rezervat pentru semn.
Un număr negativ se reprezintă în cod invers reprezentând modulul său după care se
inversează valorile tuturor biţilor reprezentării.

Avantajele codului complementar


- circuitele electronice pentru adunare şi scădere nu trebuie să examineze semnul
numărului (vor efectua întotdeauna adunări)
- valoarea 0 (zero) are reprezentare unică.
Reprezentarea numerelor reale
 în virgulă fixă
 în virgulă mobilă
Reprezentarea numerelor reale în virgulă fixă
- se foloseşte bitul cel mai semnificativ ca bit de semn. Modulul părţii întregi şi partea fracţionară
au un număr prefixat de biţi pe care se reprezintă şi se aplică următoarele reguli:

•alinierea în locaţia de memorie se face la virgula virtuală.

•dacă valoarea părţii întregi este mai mică decât valoarea maximă ce poate fi reprezentată pe biţii alocaţi
părţii întregi se adaugă la stânga zerouri suplimentare.

•dacă valoarea părţii întregi este mai mare decât valoarea maximă ce poate fi reprezentată pe biţii
alocaţi părţii întregi se pierd cifrele cele mai semnificative.

•dacă valoarea părţii fracţionare este mai mică decât valoarea maximă ce poate fi reprezentată pe biţii
alocaţi părţii fracţionare se adaugă la dreapta zerouri nesemnificative.

•dacă valoarea părţii fracţionare este mai mare decât valoarea maximă ce poate fi reprezentată pe biţii
alocaţi părţii fracţionare se pierd cifrele cele mai nesemnificative.
Reprezentarea numerelor reale în virgulă mobilă
- un tip superior de reprezentare, astfel concepută încât la depăşire se pierd
cifrele cele mai puţin semnificative.
- se bazează pe faptul că orice număr real x se poate scrie sub forma:

x  0.m  be
unde 0.m este mantisa numărului, b este baza de numeraţie, iar e este exponentul.
Pentru reprezentarea valorilor reale în virgulă flotantă trebuie folosit un anumit număr
de biţi, care să permită reprezentarea:
1. semnului numărului
2. mantisei
3. exponentului
4. semnului exponentului (de fapt semnul exponentului se include în valoarea
reprezentată pe biţii alocaţi, ţinându-se cont de caracteristica reprezentării)

standardul IEEE (Institute of Electrical and Electronics Engineers), pentru


reprezentarea numerelor în simplă precizie (pe 32 biţi) sau în dublă precizie
(pe 64 biţi)
Bitul de semn:
- 0 corespunde unui număr pozitiv şi 1 corespunde unui număr negativ

Exponentul
- trebuie reprezentate atât numere pozitive cât şi negative.
- exponentului propriu-zis al numărului care se reprezintă i se adaugă o anumită
valoarea care depinde de tipul de precizie folosită (simplă sau dublă), numită caracteristică.

IEEE simplă precizie: 127 (27-1) 0 1 1 1 1 1 1 1


IEEE dublă precizie: 1023 (210-1). 0 1 1 1 1 1 1 1 1 1 1

Pentru un număr al cărui exponent este 0, pe biţii alocaţi exponentului se stochează valoarea
127 (în binar 01111111).
O valoare de 200 (în binar 11001000) stocată pe biţii exponentului înseamnă de fapt
exponentul 200-127=73.
Exponenţii cu toţi biţii 0 sau toţi biţii 1 sunt rezervaţi pentru numere speciale (, 0, NaN).
Pentru standardul dublă precizie se alocă 11 biţi pentru exponent, iar caracteristica este 1023.
Reprezentarea exponentului
în simplă precizie:
Mantisa
- biţii de precizie ai unui număr
- compusă dintr-un bit implicit principal (întotdeauna 1 în scrierea cu mantisă între 1 şi 2) şi biţii fracţiei.
Pentru a afla bitul implicit principal se ţine cont de faptul că în notaţia ştiinţifică orice număr poate fi
reprezentat în mai multe feluri. Astfel, numărul 5 poate fi reprezentat într-unul din modurile următoare:
5.00·100
0.05·102
5000·10-3
În scopul maximizării cantităţii de numere reprezentabile, numerele floating point sunt stocate în formă
normalizată, formă care se obţine punând punctul zecimal după prima cifră nenulă. În formă normalizată,
numărul 5 este reprezentat sub forma: 5·100. In baza 2, singura cifră nenulă nu poate fi alta decât cifra 1,
astfel încât nu este necesar ca ea să fie reprezentată explicit şi în simplă precizie de exemplu, toţi cei 23 de
biţi sunt folosiţi pentru reprezentarea părţii fracţionare a mantisei, obţinându-se practic o precizie de 24 biţi
folosind doar 23 de biţi.

1/2^24= 1.19209-07

1/2^52= 2.22045E-16
Diferenta: 2-23 – 0 = 0.0000001192 = 1.192 10-7
Numerele reale nu sunt reprezentate continuu ci discret!
Pasul: 1.19210-7

http://www.h-schmidt.net/FloatConverter/IEEE754.html
Valoarea "Not A Number"
- folosită pentru a reprezenta valori care nu reprezintă un număr real.
- reprezentate printr-o succesiune de biţi cu exponentul având toţi biţii 1 şi o fracţie nenulă.
Există două feluri de valori Nan: QNaN (Quiet NaN) şi SNaN (Signalling NaN).
QNaN este un NaN cu cei mai semnificativi biţi ai fracţiei setaţi şi rezultă din operaţii
aritmetice când rezultatul matematic nu este definit -> operaţie nedeterminată

SNaN este un NaN cu cei mai semnificativi biţi a fracţiei şterşi şi astfel de valori sunt folosite
pentru a semnala excepţii -> operaţie invalidă.

CORE-STREPTAVIDIN MUTANT W120A IN


COMPLEX WITH BIOTIN AT PH 7.5
Exemplu:
Care va fi reprezentarea numărului -10.375, în virgulă flotantă, simplă precizie?
1. Numărul pozitiv se transformă în binar şi se obţine: 1010.011
2. Se scrie numărul obţinut în binar sub formă normalizată: 1.010011·23
3. Se determină valoarea exponentului: 3+127=130
4. Se transformă noul exponent în binar: (130)10=10000010
5. Se determină bitul de semn al mantisei: 1
6. Se scrie numărul:

Exercitii
Ce valoare au numerele a caror reprezentare este:

Tema
Care este diferenta dintre valoarea 2 si primul numar > 2 reprezentat in
standardul IEEE, simpla precizie?
http://homepage.cs.uiowa.edu/~atkinson/m170.dir/overton.pdf
CURS 3
Limbajul C
- dezvoltat între anii 1969-1973 (D.M.Ritchie), o dată cu
dezvoltarea sistemului de operare Unix. (Ken Thompson &
D.M.Ritchie);
- 1972 - anul "naşterii" limbajului C.
- 1973 - elementele esenţiale ale limbajului C au fost complete
- 1977-1979 schimbari majore
- 1978 – apare cartea "The C programming language" scrisă de
către B.W.Kernighan, D.M.Ritchie
- 1983 incepe standardizarea limbajului C de către ANSI
(American National Standards Institute)
- 1989 - a apărut ANSI C.
Avantaje
1. limbaj de programare de scop general
=> dezvoltarea de aplicaţii diverse:
soft ştiinţific,
soft pentru gestiunea bazelor de date,
editoare de texte,
jocuri, etc.
- nu este specializat pe un domeniu particular de aplicaţii
- control modern al funcţiilor şi al structurilor de date
- set bogat de operatori

2. permite o foarte bună portabilitate a programelor

3. permite programarea structurată (modulară)

4. permite scrierea softului de bază (programare de sistem)

5. oferă posibilitatea lucrului pe biţi şi a calculului adreselor


Elementele limbajului C
Exemple
Categorii de elemente
Comentarii
- note explicative (adnotări) în program
- complet ignorate de către compilator
- şiruri de caractere (pot fi şi caractere speciale sau cuvinte cheie) cuprinse între
/* */ sau care se găsesc pe un singur rând după caracterele //
Cuvinte cheie
- cuvinte rezervate limbajului de programare, cu utilizare predefinită
- nume cu destinaţii speciale
- se scriu cu litere mici
Exemple
Identificatori (nume)
- folosiţi pentru a denumi variabile, constante, funcţii, structuri de date, etc.
- = succesiuni de caractere alfanumerice, primul caracter trebuind să fie literar
- in C, de ex., S  s
- un identificator poate conţine oricâte caractere dar sunt luate în considerare doar
primele 32 caractere
- nu pot conţine caractere speciale:

+ - / ^ < > ( ) [ ] { } . , : ; ' # $ @ - spatiu

Recomandare
- sa fie sugestivi
- x2: x2, xx, xla2, xp, etc.

Exemple:
a, suma, SUMA, m2, nr_stud_an1f, NrStudAn1F

2x, a*b, if

Obs.
Identificatorii care încep cu _ sau conţin _ _ sunt folositi pentru implementare şi pentru
librăriile standard în C şi C++.
Variabile
- nume simbolice asociate unor locaţii de memorie
- valorile lor pot fi modificate prin instrucţiuni ale programului
- declararea (definirea) variabilelor constă în precizarea tipului şi numelui lor.

Exemple:
Variabile globale
- variabile declarate in afara functiei main
- se initializeaza automat cu zero

Exercitiu
Scrieti programul pentru transformarea oC->oF
Constante
- valori care nu pot fi modificate în decursul programului
constante simbolice
constante obiect

Constante simbolice
- se definesc cu directiva define
- constante fara tip
Directiva define
- stabileşte (defineşte) un nume simbolic pentru o anumită valoare
- se compune din: cuvântul cheie #define, o denumire simbolică, o valoare
- nu se termină cu ;
- autorizează substituţia pe care o defineşte din punctul în care este scrisă până
la sfârşitul fişierului sursa sau până la întâlnirea unei directive undef.
Constantele obiect
- constante cu tip
- Se declara folosind cuvântul cheie const urmat de tipul constantei şi de un
identificator iniţializat.
- declararea acestor constante se termină cu caracterul ;

Exemplu

O constantă de tip char (caracter) este un


întreg, scris ca un singur caracter între două
simboluri '. Valoarea constantei caracter este
valoarea caracterului respectiv în setul de
caractere ASCII (American Standard Code for
Information Interchange).
Astfel, de exemplu, '0' are valoarea 48, 'A' are
valoarea 65, iar 'a' are valoarea 97.
Instrucţiuni
- părţi (linii) de program care prin compilare produc acţiuni (coduri) executabile
- se termină cu caracterul ; - terminator de instrucţiune
- lipsa caracterului ; este semnalata la începutul liniei următoare
Exemple

► In urma execuţiei programului se tipăresc valorile de la 5 la 105


► Dacă nu se pun acolade la while se va tipări doar valoarea 105
Expresii
- construcţii formate din operanzi şi operatori.
- au valori şi tipuri
- valorile şi tipurile expresiilor sunt determinate de către valorile şi tipurilor
operanzilor şi de către operatorii care compun expresia.
Exemplu
b*b-4*a*c expresie
a,b,c operanzii expresiei
*, - operatorii expresiei

delta = b*b - 4*a*c ; instrucţiune prin care se atribuie variabilei


delta rezultatul evaluarii expresiei b2 - 4ac

Operanzii pot fi :
- constante
- identificatori (nume) de variabile
- nume de tipuri de date
- apeluri de funcţii
- expresii cuprinse între paranteze rotunde
Funcţii
- grupuri de instrucţiuni recunoscute sub un anumit nume
- realizează acţiuni şi întorc (returnează) valori programului principal (funcţiei
principale) sau altei funcţii apelante.
- se apelează prin nume şi lista lor de parametri.

 Parametrii funcţiilor sau valorile cu care sunt apelate transferă informaţia din exteriorul funcţiilor în
interiorul lor.
 Valorile pe care le returnează funcţiile nu trebuie folosite în mod obligatoriu (vezi de ex. funcţiile
scanf() şi printf())
 Funcţia principală returnează valori sistemului de operare, acesta fiind programul apelant al ei.
 Anumite funcţii standard sunt gata scrise şi prototipurile lor se găsesc în bibliotecile limbajului
(header files).

<stdio.h> - conţine funcţii standard de intrare ieşire (I/O): printf, scanf, getch, ...
<stdlib.h> - conţine funcţii standard precum: abort, exit, rand, atoi, itoa,...
<string.h> - conţine funcţii pentru prelucrarea şirurilor de caractere: strcpy, strlen, strcmp, strcat,...
<math.h> - conţine funcţii matematice: cos, sin, pow, fabs, abs, ...
<graphics.h> - conţine funcţii pentru gestiunea ecranului în mod grafic
(initgraph, putpixel, line, outtext, outtextxy , cleardevice, ...)
<conio.h> - conţine funcţii standard de intrare ieşire de la consolă
(clrscr, getch, getche, gotoxy, putch, wherex, wherey,...)
<time.h> - conţine funcţii pentru gestiunea orei şi a datei sistemului de calcul
(gettime, settime, ctime,...)
<dos.h> - conţine funcţii pentru interacţiunea cu sistemul de operare DOS
(setdrive, inport, outport)
… etc.
Funcţia itoa (nu este suportată de toate compilatoarele)
Structura funcţiilor

Antetul
- tipul valorii pe care o returnează funcţia + numele funcţiei + lista parametrilor funcţiei
(tipul şi numele variabilelor funcţiei)

Corpul de instructiuni
- grupul de instrucţiuni care se execută la apelul funcţiei respective.
Apelul functiilor
- prin nume şi lista de parametri.

La apelul funcţiei, controlul programului este pasat acelei funcţii.


La întâlnirea instrucţiunii return în interiorul unei funcţii se face saltul în afara
funcţiei, controlul fiind preluat de către funcţia main, din locul imediat următor celui
în care a fost apelată funcţia din care se face saltul.
Funcţia main
- partea principală a unui program C
- este apelată şi lansată în execuţie de către sistemul de operare.

Funcţii recursive
- functii care se autoapelează
- se folosesc la definirea proceselor recursive.

Proces este recursiv


- proces care are o parte care se defineşte prin el însuşi.
Exemple
Funcţia factorial
dacă n==0 fact(n)=1 <- aceasta este partea apelului recursiv care nu se defineşte prin el însuşi
(partea definită direct)
altfel
fact(n)=n*fact(n-1) <- se defineşte funcţia fact prin ea însăşi

Funcţia fact recursivă:

Cel mai mare divizor comun


dacă a%b==0 cmmdc(a,b)=b
altfel
cmmdc(a,b)=cmmdc(b,a%b)
Funcţia cmmdc recursivă: Recursivitatea nu conduce la coduri mai rapide şi nici la necesităţi
de memorie mai mici.
- convenabila pentru structuri de date definite
recursiv (arbori)

Codurile recursive sunt mai compacte şi uneori mai uşor de înţeles.


Tablouri
- colecţii de valori de acelaşi tip
- plasate in zone contigue de memorie
- elementele
- pot fi referentiate si accesate individual folosind un index
- sunt indexate de la 0 la n-1 unde n reprezintă dimensiunea tabloului

Exemple
Este declarat un tablou unidimensional float medii[10];
de 5 elemente şi elementele tabloului medii[10]=9.85;
sunt apoi iniţializate cu valoarea 0.
int a[5];
int i; float x[6];
for(i=0;i<5;i++) x[1] = 12; x[2]=34; … x[5] = 14; //x[0] = nedefinit !!
a[i]=0;

float x[6] = {12, 34, 1, 9, 14}


//rezultă: x[0] = 12; ... x[4] = 14; şi x[5] = nedefinit !!
Care va fi output-ul urmatorului program
Care va fi output-ul urmatorului program

Fara _kbhit() si fara <conio.h>


Tema: Modificati programul de mai sus astfel incat sa se tipareasca notatia tablei de sah:
Şiruri de caractere Citirea şi tipărirea şirurilor
- tablouri cu elemente de tip char (caractere). - cu funcţiile gets( ) şi puts( )

Exemple: #include <string.h>


.....................
char nume[20], prenume[20]; char nume[20];
char nume[20] = "Popescu"; .....................
gets(nume);
Şirurile de caractere trebuie cuprinse între " ". ....................
puts(nume);
Dacă avem declaraţia: ....................
char nume[20] = "Popescu"

Atunci o reiniţializare de forma:


nume = "Ionescu"
va produce o eroare.

Iniţializare şirurilor:
- la declararea lor
- folosind funcţia strcpy (string copy)

# include <stdio.h>
.................
char nume[20] = "Popescu";
.................
strcpy (nume, "Ionescu");
.................
Un şir de caractere este terminat cu caracterul NULL (caracterul '\0').

Exemplu
Sirul de caractere "Programare" este stocat în tabloul de caractere sircar[] după cum
urmează:
char sircar[DIM]
sircar[0]='P'; sircar[1]='r'; sircar[2]='o‘;
sircar[3]='g‘ sircar[4]='r' sircar[5]='a';
sircar[6]='m'; sircar[7]='a'; sircar[8]='r’
sircar[9]='e'; sircar[10]='\0';
Caracterul NULL
- este scris folosind secvenţa escape '\0’
- este definit în <stdio.h>
- valoarea sa ASCII este 0.
Exemple
printf("String1:\t"); printf("String1:\t");
strcpy(S1,"testare\0siruri"); //’\0’ = NULL strcpy(S1,"testare\\0siruri"); //’\0’ = NULL
printf("\n%s",S1); printf("\n%s",S1);
l1=strlen(S1); l1=strlen(S1);
printf("\nLungimea sirului 1: %d\n",l1); printf("\nLungimea sirului 1: %d\n",l1);
Exemplificare strcmp() si strlen()

http://www.cplusplus.com/reference/
int strcmp ( const char * str1, const char * str2 );

Compare two strings


Compares the C string str1 to the C string str2.

This function starts comparing the first character of each string. If they
are equal to each other, it continues with the following pairs until the
characters differ or until a terminating null-character is reached.

This function performs a binary comparison of the characters.

Parameters
str1
C string to be compared.
str2
C string to be compared.

Return Value
Returns an integral value indicating the relationship between the strings:
A zero value indicates that both strings are equal.
A value greater than zero indicates that the first character that does not
match has a greater value in str1 than instr2; And a value less than zero
indicates the opposite.

strcmp este utila la ordonarea alfabetica a cuvintelor!


http://www.cplusplus.com/reference/
strlen
size_t strlen ( const char * str );
Get string length
Returns the length of the C string str.

The length of a C string is determined by the terminating null-


character: A C string is as long as the number of characters between
the beginning of the string and the terminating null character
(without including the terminating null character itself).

This should not be confused with the size of the array that holds the
string. For example:

char mystr[100]="test string";

defines an array of characters with a size of 100 chars, but the C


string with which mystr has been initialized has a length of only 11
characters. Therefore, while sizeof(mystr) evaluates
to 100, strlen(mystr) returns 11.

In C++, char_traits::length implements the same behavior.

Parameters
str
C string.

Return Value
The length of string.
Secvenţe escape
- coduri de control (spaţii albe), folosite pentru specificarea formatelor de scriere a datelor
- constau din combinaţii dintre un caracter backslash \ urmat de o literă sau de o combinaţie de cifre .

Setul de secvente escape în C: Unele secvenţe escape sunt specifice perifericelor


folosite.
\v (tabulator vertical) şi \f (pagină nouă la imprimantă)
nu afectează formatul de ieşire al datelor pe monitor ci
numai la imprimantă.

Exemple:
printf("\nSuma celor %d numere este %g\t\a“,n,s);

Suma celor 5 numere este 43.75 ♫_ (cursor)


printf("\n\tSem I\t\tSem II");
for(i=1; i<=nrstud; i++)
printf("\n%d:\t%5.2f\t\t%5.2f",i,medsem1[i],medsem2[i]);

Sem I Sem II
1: 8.75 5.25
2: 10.00 10.00
3: 5.30 6.67
...................................................

#define fis_intrare "d:\\fiz1r\\centru.dat“

Pentru despărţirea directoarelor într-o cale de directoare scrisă într-un program C


trebuie folosite două caractere backslash (\\).
Codul ASCII (American Standard Code for Information Interchange)
- cod standard de reprezentare a caracterelor ca valori întregi pe 7 biţi.
- introdus pentru a se obţine o compatibilitate între tipuri diferite de echipamente folosite la procesarea
datelor.
- ASCII standard
- constă din 128 de numere întregi (reprezentate pe 7 biţi, cu valori între 0 şi 127) atribuite unor
caractere (cele englezeşti), numere, semne de punctuaţie, celor mai uzuale caractere speciale
şi unor coduri de control (comenzi) netipăribile (primele 32 de caractere).
- Codul ASCII extins
- constă de asemenea din 128 numere întregi, cu valori între 128 şi 255 (pentru reprezentarea
lor folosindu-se toţi cei 8 biţi ai unui octet), care reprezintă caractere suplimentare din alte
limbi, simboluri matematice, grafice, caractere speciale sau sau simboluri ale unor monede
străine.
- Folosirea acestor coduri face posibilă şi prelucrarea caracterelor, nu numai a numerelor.
Codul ASCII standard
Codul ASCII extins
CURS 4
Structura generală a unui program " C “
Program C
Program
- ansamblu de instrucţiuni incluse în una sau mai multe 0. Documentatie
funcţii, care specifică operaţiile ce trebuie efectuate asupra
unor date pentru a fi prelucrate în sensul dorit de către
1. Directive de preprocesare
utilizator.
a) Includeri de fişiere cu text sursă
b) Macrosubstituiri
c) Includeri conditionate

2. Sectiunea de declaratii
a) variabile
b) tipuri utilizator
c) functii
....

3. Functia principala
int main()
{
...
return 0;
}

4. Definirea functiilor utilizator


0. Documentatii

- set de comentarii care conţin numele programului şi alte detalii utile programatorului.
Exemple
//Program: easycalc
//Calculator pentru operatii elementare
//Exemplu de folosire a instructiunii switch
//Introducerea functiei system
//system("C:\\windows\\system32\\calc.exe");
// - apeleaza aplicatia calc.exe
1. Directive de preprocesare
a) Includeri de fişiere cu text sursă
b) Macrosubstituiri
c) Includeri conditionate

Preprocesare
- prelucrarea unui fişier sursă înainte de a fi supus compilării
=> un fişier temporar care conţine un cod sursă provenit în urma traducerii directivelor de
preprocesare.

Preprocesorul C
- program separat, invocat de către compilator în prima parte a procesului de compilare
a) Includeri de fişiere cu text sursă
- se fac cu directiva # include printr-o construcţie de forma :
#include <nume_fisier.h>
#include "nume_fisier.c“

nume_fisier = fişier cu text sursă păstrat pe disc


În faza de preprocesare textul fişierului inclus se substituie construcţiei #include şi apoi ia parte
la compilare împreună cu textul fişierului în care a fost inclus

#include <nume_fisier.h>
- se foloseşte pentru includerea fişierelor standard care conţin prototipuri pentru funcţiile de
bibliotecă (librării).
- instruiesc preprocesorul să trateze fişierele header ca şi cum ar face parte din codul sursă care
se compilează.

Librăriile sunt coduri gata compilate care se adaugă programului sursă C la compilarea acestuia.
Parantezele unghiulare instruiesc compilatorul să caute fişierele care trebuie incluse în directorul
cu fişiere antet (de exemplu, C:\BorlandC\include).
Exemple:
#include <stdio.h>
#include <math.h>

Construcţia #include "nume_fisier.c" se utilizează la includerea fişierelor nestandard care conţin prototipuri ale
eventualelor funcţii definite de către utilizator.
Fişierul care trebuie inclus se caută în directorul curent dacă nu este specificată nici o cale.

Exemple:
# include "factorial.c"
# include "C:\\BORLANDC\\PERSLIB\\persmat.c"
b) Macrosubstituiri
-substituirea unor nume prin succesiuni de caractere şi se fac cu directiva #define sub forma:
#define succesiune_de_caractere (vezi constante simbolice).

Macroprocesorul poate efectua şi substituţii de argumente în macrodefiniţii.

Exemplu:
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
#define grade_rad (x) ((x)*M_PI/180.0)
Program exemplu: macrodefiniţii
#include <stdio.h>
#include<conio.h>
#define max2(a,b) (a>b?a:b)
#define min2(a,b) (a<b?a:b)
#define max3(a,b,c)(MAX2(a,b)>c?MAX2(a,b):c)
#define schimb(a,b) {t=a;a=b;b=t;}
#define moddif(a,b) ((a>b)?(a-b):(b-a))
#define suma(a,b) (a+b)
int main()
{
int a,b,t;

printf("a= ");
scanf("%d",&a);
printf("b= ");
scanf("%d",&b);
printf("\nMaximul este %d",max2(a,b));
printf("\nMinimul este %d",min2(a,b));
printf("\nModulul diferentei este %d",moddif(a,b));
printf("\nSuma numerelor este %d",suma(a,b));
schimb(a,b);
printf("\nDupa schimbare valorile a si b sunt %d si %d",a,b);
while(!_kbhit());
return 0;
}
c) Includeri condiţionate
- se folosesc pentru includerea unor fişiere numai atunci când este îndeplinită o anumită
condiţie
Exemplu:
#if SYSTEM == MSDOS // daca sistemul de operare este MS-DOS
#include <dos.h> // se foloseste headerul <dos.h>
#else
#include <windows.h> // altfel, se foloseste headerul <windows.h>
#endif

Includerile condiţionate se mai pot folosi pentru construirea grupurilor condiţionate sub forma:
#ifdef MACRO text controlat #endif /* MACRO */

Textul controlat va fi inclus numai dacă este definită macrocomanda MACRO şi acest text poate include
directive de preprocesare.

Exemplu:
#ifdef TURBOC // in TurboC valorile intregi
#define INT_SIZE 16 // se stocheaza pe 16 biti iar in SO Unix
#else // acestea se stocheaza pe 32 biti
#define INT_SIZE 32
#endif // orice includere condiţionată se încheie cu #endif.
2. Sectiunea de declaratii
a) variabile
b) tipuri utilizator
c) functii
....

În această secţiune se stabilesc numele şi atributele variabilelor, a tipurilor de


date utilizator sau ale funcţiilor

3. Functia principala
int main()
{
...
return 0;
}

4. Definirea functiilor utilizator


Tipuri de date în C
-descriu tipurile valorilor diverselor variabile, constante, funcţii, etc. ale unui program.
- fiecare variabilă folosită într-un program C trebuie să fie declarată compilatorului.
- declaraţia va conţine numele variabilelor şi tipul acestora.

Exemplu:
...........
int zi,luna,an:
..........
zi = 14;
luna = 11; //variabilele zi, luna şi an au valori diferite dar au acelaşi tip
an = 2013;
float medie;
..........
medie = 11; //variabilele luna şi medie au aceeaşi valoare dar tipuri diferite

1) Fiecarui tip de dată îi corespunde o denumire (un cuvânt cheie) care este utilizată pentru
crearea în memorie a obiectelor ce vor conţine valori corespunzătoare tipului respectiv.

2) Fiecărui tip de date îi corespunde o anumită mărime a zonei de memorie în care se


păstrează valoarea unei date de tipul respectiv.

3) Fiecărui tip de date îi corespunde o anumită gamă de valori, determinată de mărimea


locaţiei de memorie corespunzătoare datelor de tipul respectiv.
Tipuri de date de bază (tipuri predefinite)
- puse la dispozitie de catre limbajul de programare

Tipuri de date derivate (tipuri utilizator)


- se construiesc cu ajutorul tipurilor de bază
Tipuri de date de bază
- tipurile predefinite in C:
char - tip de date ale căror valori sunt reprezentate pe un singur octet (byte)
int - tip de date ale căror valori sunt reprezentate pe 2 octeţi
float - tip de date reale reprezentate în virgulă mobilă, în simplă precizie
double - tip de date reale reprezentate în virgulă mobilă, în dublă precizie

În plus, există câţiva calificatori care pot fi aplicaţi acestor tipuri de bază:

unsigned, short şi long


Structura functiilor
Functii in C
- încapsulează una sau mai multe instrucţiuni, variabile şi parametri într-un pachet unificat care poate fi
apelat din interiorul programului
- împart sarcinile mari de calcul ale unui program în sarcini de complexitate mai mică
Definirea functiilor
tip nume (listă parametri formali) tip = tip de baza sau tipul void
{
declaraţii
instrucţiuni
}
Funcţiile pot returna valori având ca tip: Funcţiile nu pot returna:
tipuri de bază tablouri
pointeri
structuri
pointeri la structuri
pointeri la tablouri
Parametrii functiilor
-o funcţie poate avea unul sau mai mulţi parametri, dar poate de asemenea să nu aibă nici
un parametru.
- sunt folosiţi pentru a face transferuri de date între funcţii
- sunt de două feluri:
a) parametri formali
- nu reprezintă valori concrete ci ţin doar locul unor valori pentru a se
putea exprima procesul de calcul realizat de către funcţie în
momentul apelului ei
- vor fi înlocuiţi de către cei actuali în momentul apelului funcţiei.
b) parametri actuali
- parametrii transmişi unei funcţii şi care reprezintă valori concrete cu
care sunt apelate funcţiile.
- pot fi constante, variabile, expresii
- nu este obligatoriu ca numele parametrilor actuali să fie identice cu
cele ale parametrilor formali.

Transmiterea parametrilor între funcţii


Exemple:
char ascii (int valoare) int cod (char c)
{ {
char c; int codc;
c = (char) (valoare) codc = (int) (c)
return c; return codc;
} }
int cod (char c)
{
return (int) (c);
}

Variabilele din interiorul unei funcţii se numesc


variabile locale şi aparţin clasei automatic.
- sunt "vizibile" numai în corpul funcţiei în care au fost declarate şi există doar atâta timp cât
funcţia în care au fost declarate se află în execuţie
- la ieşirea din funcţie valorile lor sunt şterse din memorie (sunt volatile)

Exemple:

Variabile c este de tip automatic şi va fi alocată în memorie de fiecare dată când se execută funcţia suma. Compilatorul va crea un cod
pentru alocarea dinamică a variabilei, pentru iniţializarea ei şi pentru eliminarea ei din memorie la încetarea execuţiei funcţiei suma.
Variabile statice
- variabile locale care nu se alocă pe stivă ci într-o zonă specială de memorie, rezervată acestui tip de
variabile
- trebuie să fie precedate la declarare de cuvântul cheie static
- spre deosebire de variabilele automatic ele există tot timpul şi nu numai atunci când este executată
funcţia (nu îşi pierd valoarea între două apeluri ale funcţiei în care sunt declarate)
Exemplu:
static int c;
Variabilele globale
- variabile declarate în afara oricărei funcţii a programului
- sunt iniţializate automat cu zero şi pot fi utilizate de către orice funcţie a programului
- sunt variabile externe, adică pot fi utilizate într-o anumită funcţie a programului chiar dacă nu au
fost declarate în funcţia respectivă
- au tipul static automat.
Recomandare:
1. Este recomandabilă folosirea variabilelor locale deoarece acest lucru conduce la urmărirea mai uşoară a codului unei funcţii
particulare.
2. Dacă folosirea variabilelor locale conduce la transmiterea multor parametri sau la reproducerea inutilă a mai multor variabile, atunci
este recomandabil să fie folosite variabile globale.
Apelul funcţiilor
O funcţie se apelează printr-o construcţie de forma:

nume (listă parametri efectivi)


Parametrii efectivi
- argumentele funcţiei (adică parametrii cu care se apelează funcţia)
- trebuie să corespundă cu cei formali (folosiţi la declararea funcţiei) în ordine şi tip.
- sunt pasati funcţiilor prin valoare, astfel încât funcţia primeşte o copie a argumentului şi deci ea poate
modifica argumentul său fără a modifica originalul. Pentru ca o funcţie să poate modifica argumentul
original i se va transmite un pointer la acesta.

Valorile returnate de # include <stdio.h>


către funcţii pot fi int f(int n)
{
folosite ca şi
return 2*n;
argumente ale altor }
funcţii int g(int n)
{
return n*n;
}
int main()
{
int m;
printf("Introduceti o valoare intreaga: ");
scanf("%d",&m);
printf("f(x)=%d \t f(g(x))= %d", f(m),f(g(m)));
printf("\nf(x)=%d \t g(f(x))= %d", f(m),g(f(m)));
return 0;
}
Program exemplu: calculul mediei valorilor unui şir de elemente
//exemplu functie avand ca parametru un tablou
#include<stdio.h>
#include<conio.h>
float medie (int n, float sir[]) Dimensiunea şirului poate fi omisă în
{ prototipul funcţiei. De asemenea,
int i; valoarea primei dimensiuni a unui tablou
float m,s=0;
multidimensional este opţională deoarece
for(i=0;i<n;i++)
compilatorul nu are nevoie de valoarea
s=s+sir[i];
m=s/n;
primei dimensiuni pentru a calcula
return m; adresele elementelor tabloului ci numai de
} dimensiunile următoare. Astfel, dacă avem
int main() declaraţia:
{
int n,i; char Mat[6][8];
float note[10],med;
printf("n= "); Adresa elementului Mat[2][3] va fi adresa
scanf("%d",&n); lui Mat+2*8+3 deoarece Mat (numele
for(i=0;i<n;i++) tabloului) este un pointer având ca valoare
{ adresa primului sau element .
printf("n%d: ",i);
scanf("%f",&note[i]);
}
med=medie(n,note);
printf("\nMedia: %.2f",med);
return 0;
}
Prototipul funcţiilor
O funcţie poate fi apelată într-un anumit punct al unui program dacă a fost în prealabil definită în acel
program. Totuşi, o funcţie poate fi apelată şi în cazul în care corpul de instrucţiuni urmează apelului ei.
In acest caz, în secţiunea de declaraţii a programului trebuie declarat prototipul functiei.

Prototipul unei funcţii = antetul ei urmat de ;


- se foloseşte pentru declararea unei funcţii înainte de definirea ei
- poate conţine doar tipul parametrilor formali ai funcţiei, fără numele lor

Compilatorul utilizează datele din prototip pentru a verifica tipul parametrilor de la apel. În cazul în care
un parametru efectiv are un alt fel de tip decât cel din prototip compilatorul converteşte automat
valoarea parametrului efectiv spre tipul indicat în prototip. Fişierele header sunt fişiere cu astfel de
prototipuri de funcţii predefinite ale limbajului.
Exemplu:
int main ( )
{
long n, k, cnk ;
double fact (long val); // ← prototip fact
cnk = fact(n)/(fact(k)*fact(n-k)); // ← 3 apeluri ale lui fact
return 0;
}

//exemplu de funcţie factorial mai rapidă decât cele prezentate anterior

double fact (long val) // ← antet fact


{
long rez=val; // ← corp fact

while(--val>1)
rez*=val;
return rez;
}
int decidebisect(...)
{
int i;
.....
i=(an%4==0 && an%100!=0)an%400==0);

//un an este bisect dacă este divizibil cu 400


//sau dacă este divizibil cu 4 dar nu şi cu 100
//anii de sfârşit de secol nu sunt bisecţi chiar dacă urmează la 4 ani după un an bisect,
//cu excepţia celor care sunt divizibili cu 400
//ani bisecţi "obişnuiţi": 1872, 1912, 1960, 1996, 2008... – anii divizibili cu 4
//excepţii: 1800, 1900, 2100, 2200... – anii de sfârşit de secol divizibili cu 100
//sunt totuşi ani bisecţi: 2000, 2400... – anii de sfârşit de secol divizibili cu 400

int b, an;
FILE *f;
f=fopen("d:\\anibis.dat","w");
for(an=1872;an<=2110;an++)
{
if(an%400==0)
b=1;
else
if(an%100==0)
b=0;
else
if(an%4==0)
b=1;
else
b=0;
fprintf(f,"\nan: %d\tbisect: %s",an,b==1?”DA”:”NU”);
CURS 5
Funcţii de intrare/ieşire
Funcţia printf
- folosită pentru a scrie date la dispozitivul standard de ieşire (monitor), sub un anumit format.
- converteşte, formatează şi tipăreşte argumentele cu care este apelată, în conformitate cu
formatul specificat
- returnează numărul de caractere tipărite.

Şirul care defineşte formatul funcţiei conţine două tipuri de obiecte:


a) caractere ordinare - copiate ca atare la ieşirea standard
b) specificatoare de conversie şi formatare
Prototipul funcţiei printf
- se găseşte în <stdio.h>

int printf(char *format, arg1, arg2, ...);

Apelul functiei printf


printf("control",arg1,arg2,.....,argn);

arg1, arg2,...,argn - variabile sau expresii ale căror valori se tipăresc în conformitate cu
specificatorii de format prezenţi în parametrul "control" al funcţiei.
Parametrul “control” - şir de caractere care defineşte textele şi formatele datelor care se scriu.
- poate conţine fie numai specificatori, fie numai carcatere.
1. Numărul specificatorilor din parametrul control trebuie să fie egal cu
numărul argumentelor funcţiei şi să corespundă tipului acestora.

2. Datele tipărite se încadrează într-un câmp (un anumit număr de


caractere) şi se aliniază implicit în dreapta acestui câmp.

Specificator de format

- începe întotdeauna cu caracterul % şi se termină cu una sau două litere, dar mai
poate conţine:
[-]
- are ca efect încadradrea datelor scrise în stânga câmpului

[şir de cifre zecimale]


- defineşte dimensiunea minimă a câmpului în care se afişează datele
Litera g este folosită ca şi litera f pentru conversia valorilor care se afişează la tipul
real şi tipărirea valorilor respective fără zerourile nesemnificative.

[.şir de cifre zecimale]


- defineşte precizia datei care se scrie, adică numărul de cifre zecimale sau numărul de
caractere care se scriu dacă data este un şir de caractere
% [ - , 0 , cifre.cifre ]l [l]
Litera c este folosită pentru afişarea unui caracter.
Litera s este folosită pentru afişarea unui şir de caractere.
Litera d se foloseşte pentru afişarea valorilor variabilelor de tip întreg, în sistemul de numeraţie zecimal.
Litera o se foloseşte pentru afişarea valorilor variabilelor de tip întreg, în sistemul de numeraţie octal.
Literele x şi X se folosesc pentru convertirea şi afişarea valorilor unor variabile de tip întreg în sistemul de
numeraţie hexazecimal.
Litera u este folosită pentru conversia valorilor la tipul întreg unsigned şi tipărirea lor.
Litera f este folosită pentru conversia la tipul float şi afişarea valorilor cu 6 cifre zecimale.
Literele e şi E sunt folosite pentru tipărirea valorilor de tip float, double sau long double în format ştiinţific.
Literele g şi G sunt folosite pentru afişarea datelor de tip float, double sau long double pe un număr minim
de caractere (fără zerouri nesemnificative).
Literele l şi L realizează conversii la tipul long, respectiv la tipul long double şi se folosesc împreună cu
literele f, e, E, g sau G.
lf, Lf – realizează afişarea datelor fără exponent, cu 6 cifre zecimale.
le, lE, Le, LE – realizează tipărirea valorilor în format ştiinţific.
lg, lG, Lg, LG – realizează tipărirea datelor într-unul din formatele precedente care asigură o afişare cu un
număr minim de caractere.
Specificatorul %c este folosit pentru citirea unui caracter.
Specificatorul %s este folosit pentru citirea unui şir de caractere.
Un şir citit cu specificatorul %s se încheie la primul caracter citit după care urmează un caracter
alb (spaţiu, tab (\t), rând nou (\n), carriage return, tab vertical (\v) şi avans de pagină la
imprimantă (\f)) sau la caracterul prin care se ajunge la lungimea maximă de caractere indicată
de specificatorul de format.
Funcţia scanf
- folosită pentru citirea datelor introduse de la dispozitivul standard de intrare (tastatura) ş
- converteste datele în conformitate cu formatul specificat
- returnează numărul câmpurilor citite corect, adică în conformitate cu tipul specificat.

Prototipul funcţie scanf se găseşte în <stdio.h>

int scanf(char *format, arg1, arg2,...argn)

Apelul funcţiei scanf

scanf("control",&par1, &par2,...,&parn);

&par1, &par2, ... , &parn sunt adresele de început ale locaţiilor de memorie în care se păstrează
valorile corespunzătoare lui par1, par2, ... , parn.

Astfel, dacă v este o variabilă, atunci &v reprezintă adresa primului octet al locaţiei de memorie la
care se stochează valoarea variabilei v.

Şirul control conţine specificatori de tip folosiţi pentru controlul conversiei datelor citite.
Specificatori de tip

Specificatorul %c este folosit pentru citirea unui caracter.

Specificatorul %s este folosit pentru citirea unui şir de caractere.


- citirea sirului se încheie la primul caracter citit după care urmează un caracter alb (spaţiu, tab (\t), rând
nou (\n), carriage return, tab vertical (\v) şi avans de pagină la imprimantă (\f)) sau la caracterul prin
care se ajunge la lungimea maximă de caractere indicată de specificatorul de format.

Specificatorul %d permite citirea unor valori şi conversia acestora spre tipul întreg
- citirea se încheie la primul caracter citit după care urmează un caracter alb sau la caracterul prin care se
ajunge la lungimea maximă de caractere indicată de specificatorul respectiv.

Specificatorul %o este folosit pentru citirea unor valori întregi în sistemul de numeraţie octal.

Specificatorul %u se foloseşte pentru citirea întregilor de tip unsigned.

Specificatorul %f este folosit la citirea unor date de tip real şi conversia acestora spre tipul
float.

Litera l poate precede literele d, o, x, X, u sau f şi converteşte datele citite spre tipul long (în
cazul d, o, x, X, u) sau spre tipul double dacă precede litera f.

Litera L poate precede litera f şi are ca efect convertirea datelor citite spre tipul long double.
Alte functii de intrare iesire
Intrare: getch, getche, getc, gets, getchar
Ieşire: printf, putch, putc, puts, putchar.
Operatori
- folosiţi la construcţia expresiilor matematice şi logice
- exercită diferite acţiuni asupra operanzilor expresiilor şi sunt de două feluri:

a) operatori unari, care se aplică unui singur operand


b) operatori binari, care se aplică la doi operanzi

Clase de operatori

operatori aritmetici operatori de relaţie operatori de forţare a tipului

operatori de atribuire operatori logici operatorii paranteze

operatori de incrementare şi decrementare operatorul adresă operatorul *

operatori de dimensiune operatorul virgulă operatori logici pe biţi

operatori condiţionali operatorul ->

operatorul ∙ operatori de egalitate


Operatori aritmetici
- folosiţi la efectuarea calculelor aritmetice cu date de diferite tipuri
- se împart în următoarele categorii:
1) operatorii unari + şi –;
operatorul unar + nu are nici un efect, iar operatorul unar –
negativează valoarea operandului căruia i se aplică.

2) operatorii binari aditivi + şi –

3) operatorii binari multiplicativi *, / şi %.


operatorul * realizează produsul operanzilor
operatorul / realizează împărţirea operanzilor
operatorul % (modulo) se aplică numai la operanzi întregi şi
returnează restul împărţirii întregi a operanzilor.

Operatorii unari sunt mai prioritari decât cei binari, iar cei multiplicativi sunt
mai prioritari decât cei aditivi.

Dacă un operator se aplică la doi operanzi cu tipuri diferite, operandul de tip inferior se converteşte
spre tipul superior al celuilalt operand şi rezultatul este de tipul superior.
Dacă un operator se aplică la doi operanzi de acelaşi tip atunci tipul rezultatului coincide cu tipul
comun al operanzilor.
Dacă rezultatul are o valoare ce depăşeşte limitele tipului respectiv, atunci rezultatul este
imprevizibil.
Exemple
(1) float a;
double b; int i;
b = 3*a-i;
Valoarea 3 (de tip int) se converteşte la float (adică valoarea 3 se extinde pe 4 octeţi) şi rezultatul este
de tip float. Apoi se converteşte i la float şi apoi se scade din rezultat. In final, rezultatul se converteşte
la double.

(2) int a, b, c;
...
a = 30000;
b = 29000;
c = a+b;
Valoarea lui c este imprevizibilă deoarece depăşeşte limitele tipului int.
Operatori de relaţie (relaţionali)
==, >, >=, <, <=
- acţiunea lor constă în a compara în sens algebric valorile a doi operanzi întregi
sau în virgulă mobilă
- au aceeaşi prioritate (mai mică decât a operatorilor aditivi)

E1 operator relaţional E2
unde E1 şi E2 sunt expresii, are valoarea 0 (fals) sau 1 (adevărat).

În C şi C++ se consideră că o expresie este falsă dacă valoarea ei este 0 şi se consideră că este adevărată
dacă valoarea ei este diferită de zero (este egală cu 1).

Exemple
#include <stdio.h>
int main( )
{
float a, b;
scanf("%f %f",&a,&b);
printf("%g\t%g\t%d", a, b, a>b);
return 0;
}
printf("\n%g\t%g\t%d",a,b,(a>b)*10);
printf("\n%g\t%g\t%d",a,b,(a>b)+1)
Operatori de egalitate
== (egal) şi!= (diferit)
- verifică dacă valorile a doi operanzi sunt egale sau nu
- au aceeaşi prioritate (mai mică decât a operatorilor de relaţie)

E1 operator de egalitate E2
unde E1 şi E2 sunt expresii, are valoarea 0 sau 1.

Exemple
b == a*a
are valoarea 1 dacă b=a2 şi 0 dacă b≠a2
a%4!=0
are valoarea 1 dacă a nu este multiplu de 4 şi 0 în caz contrar
getchar()==EOF
are valoarea 1 dacă s-a citit caracterul de sfârşit de fişier şi 0 dacă s-a citit un alt caracter.

float x;
scanf("%f",&x)==1
are valoarea 1 (adevărat) dacă funcţia scanf a citit o valoare de tip float (sau convertibilă la
float) şi zero în caz contrar

int m, x, y, z;
scanf("%d%d%d%d",&m,&x,&y,&z)==4
are valoarea 1 dacă s-au citit 4 valori de tip întreg şi zero în caz contrar
Operatorul de atribuire
=
- atribuie valoarea unei expresii la o anumită variabilă (dacă este cazul se face şi conversia
necesară)
- are cea mai mică prioritate
- se foloseşte sub forma:
v = expresie;
v poate fi o variabilă simplă, un element de tablou sau de structură, un apel de funcţie, etc.

În limbajul C este permis:


V1=V2= expresie;
sau
V1=V2=.....Vi=Vn= expresie;

Operatorul de atribuire
- poate fi însoţit de un operator binar aritmetic sau logic pe biţi
=> operatori prescurtaţi sau operatori compuşi
+=, -=, *=, /=, %=, >>=, <<=, &=, |=, ^=, ~=
- produc conciziune în scrierea expresiilor

V op=(expresie)  V = V op (expresie)
Exemple
int a;
a=10; // variabilei a i se atribuie valoarea 10
a+=10; // variabilei a i se atribuie vechea sa valoare la care s-a adăugat 10
i=i+1; // este echivalentă cu expresia i+=1;
a*=(b/c)+d // este echivalentă cu expresia a=a*((b/c)+d)
a&=0x00FF // este echivalentă cu expresia a=a&0x00FF
//vezi operatori logici pe biţi (FF)16=(255)10
sir[i*j]=sir[i*j]*5; // elementului de pe poziţia i*j al tabloului şir i se multiplică valoarea cu 5
sir [i*j]*=5; // această expresie este echivalentă cu cea de mai sus dar în
//acest caz compilatorul crează un cod mai eficient
// deoarece multiplicarea i*j se efectuează o singură dată
Operatori logici
! - operator unar de negaţie logică
&& - şi logic
|| - sau logic
- folosiţi pentru construirea unor expresii relaţionale

Negaţia logică (!)


- are aceeaşi prioritate ca şi ceilalţi operatori unari, imediat mai mare decât a
operatorilor multiplicativi.

Expresia:
! operand
are valoarea 0 (fals) dacă operand ≠ 0 şi valoarea 1 (adevărat) dacă operand = 0 (fals).

Şi logic (&&)
- are prioritate mai mică decât a operatorilor de egalitate

Expresia:
E1 && E2
are valoarea 1 (adevărat) dacă E1 şi E2 au simultan valori diferite de zero şi are valoarea 0
(fals) dacă E1 şi/sau E2 au valoarea 0.
Sau logic (||)
- are prioritate imediat mai mică decât &&.

Expresia:
E1|| E2
unde E1 şi E2 sunt expresii, are valorile:
1 (adevărat) dacă E1 şi/sau E2 ≠ 0
0 (fals) dacă E1 şi E2 = 0
Operatorii logici (&& şi ||) se evaluează de la stânga la dreapta.
Dacă la evaluarea unei expresii se ajunge într-un punct în care se poate cunoaşte valoarea de
adevăr a întregii expresii, atunci restul expresiei (aflată în dreapta) nu se mai evaluează.

Exemple

a&&b = 1 dacă a ≠ 0 şi b ≠ 0
!a&&b = 1 dacă a = 0 şi b ≠ 0 (prima dată se evaluează !a)

Fie atribuirea:
d=c>='0'&&c<='9';
În acest caz d are valoarea 1 dacă c este cifră şi d are valoarea 0 dacă c nu este cifră.
Program exemplu: convertirea unui şir de cifre într-un număr întreg

#include <stdio.h>
int atoi(char s[])
{
int i,n=0;
for(i=0;s[i]>='0'&&s[i]<='9';i++)
n=10*n+(s[i]-'0');
return n;
}

int main( )
{
char s[20];
int n;

gets(s);
printf("%d",atoi(s));
return 0;
}

#include <stdio.h>
double x;
int main ( )
{
printf("Introduceti o valoarea reala: ");
scanf("%lf",&x);
printf("x = %lg\t %d",x,(x>=500)&&(x<=800));
return 0;
}
Operatori de incrementare şi decrementare
- operatori unari
- operatorul ++
- operator de incrementare
- măreşte valoarea operandului căruia i se aplică cu valoarea 1
- operatorul –
- operator de decrementare
- micşorează valoarea operandului cu 1.
Pot fi:
i) prefixaţi, când sunt aplicaţi sub forma ++ operand sau –operand
- se foloseşte valoarea operandului la care s-a aplicat operatorul respectiv.
ii) postfixaţi, când sunt aplicaţi sub forma operand++ sau operand—
- se foloseşte valoarea operandului de dinaintea aplicării operatorului.
Exemplu
a = 5;

b = ++ a;
=> a primeşte valoarea 6 şi apoi b ia valoarea 6.

b = a++ ;
=> variabila b ia valoarea 5 şi apoi lui a i se atribuie valoarea 6.
Operatorul de forţare a tipului (conversie implicită)
- operator unar
- este folosit la conversia valorii unui operand spre un alt tip
- se aplică sub forma:
(tip)(operand)

Exemple
int k;
scanf("%d",&k);
printf("\n k/k+1 = %.15g",(double)k/(k+1));
printf("\n k/k+1 = %.15g",(double)(k/(k+1)));

int n;
double f(float x)
{
.................
}
f((float)(n));
Operatorul dimensiune (sizeof)
- determină dimensiunea în octeţi a unei date sau a unui tip de date
- se aplică sub forma:
sizeof data sau sizeof(tip)

data
- nume de variabilă simplă, nume de tablou sau element de tablou, nume de structură
sau de element al unei structuri
tip
- cuvânt cheie corespunzător unui tip de bază sau unui tip de utilizator

Exemplu
int i,d,x,y,z,v;
long double sir[10];
d = sizeof(i);
x = sizeof(sir[3]);
y = sizeof(sir);
z = sizeof(float);
v = sizeof (char);

printf("d= %d\nx= %d\ny= %d\nz= %d\nv= %d",d,x,y,z,v);


Operatorul adresă (&)
- determină adresa de început a zonei de memorie alocată unei date
- operator unar
- numit şi operator de referenţiere
- folosit la citirea valorilor datelor cu funcţia scanf şi de asemenea este folosită cu pointeri
- se aplică sub forma:
&nume

unde nume este numele unei variabile simple, al unui tablou sau al unei structuri
Exemplu
int n, *pi;
printf("Introduceti o valoare intreaga: ");
scanf("%d",&n);
pi=&n;
printf("Valoarea citita este %d\nLocatie de memorie \nrezervata ei incepe la
adresa %X",n,pi);

Operatorii paranteză ()
- sunt de prioritate maximă
- au ca efect impunerea ordinii de evaluare a expresiilor
- nu pot fi folosiţi cu operatorii de incrementare şi decrementare şi cu operatorul adresă
Operatori condiţionali (? şi :)
- permit construirea expresiilor condiţionale, adică a unor expresii a căror valoare
depinde de valoarea unei alte expresii
- se folosesc împreună în ordinea indicată de formatul expresiei condiţionale

Expresia:
E?E1:E0
are valoarea şi tipul lui E1 dacă E are valoarea 1 (adevărat), altfel are valoarea şi
tipul lui E0 (dacă E = 0 (fals) ).

Exemplu if(a>b)
max = (a>b)?a:b; max=a;
min=a<b?a:b; else
caz=x==y?”egale”:”diferite”; max=b;
Operatorul virgulă (,)
- leagă două expresii în una singură
- are cea mai mică prioritate dintre toţi operatorii limbajului C
- se utilizează când într-un anumit punct al unui program este necesar să se realizeze un
calcul complex exprimat în mai multe expresii
- folosit si pentru separarea listei de argumente ale unei funcţii

Expresia:
exp1, exp2,......, expn
este o expresie a cărui tip şi valoare coincide cu tipul şi valoarea ultimei expresii.
Evaluarea expresiilor de genul celei de mai sus se evaluează de la stânga la dreapta.

Program exemplu: tipărirea maximului a două valori absolute, folosind operatorii


condiţionali şi operatorul virgulă.

#include<stdio.h>
int main ()
{
int a, b, c, d;
scanf("%d%d",&a, &b);
printf("a=%d\tb=%d\tmax(|a|,|b|)=%d",a,b,((c=a<0?-a:a),(d=b<0?-b:b),
(c>d?c:d)));
//c = |a| d = |b| tipăreşte c sau d
return 0;
}
Operatorul *
- se foloseşte pentru a accesa conţinutul unei zone de memorie definită prin adresa ei
- se numeşte şi operator de dereferenţiere.
Exemple de folosire a acestui operator vor fi date la discuţia pointerilor.

Operatorii . si ->
- utilizaţi pentru a accesa componentele structurilor
- sunt de prioritate maximă.
Exemple de utilizare a acestor operatori vor fi date la discuţia structurilor.
Operatori pe biţi
- folosiţi pentru manipularea biţilor
- utili pentru scrierea softului de sistem

Limbajul C oferă următorii operatori pe biţi:


operatorul ŞI logic pe biţi: & (AND)
operatorul SAU logic pe biţi: | (OR inclusiv)
are valoare 1 când cel puţin unul dintre biţi este 1
operatorul SAU exclusiv: ^ (OR exclusiv)
are valoare 1 când cei doi biţi sunt diferiţi şi zero în caz contrar
operatorul de deplasare spre stânga: << (left shift)
operatorul de deplasare spre dreapta: >> (right shift)
operatorul de complementare faţă de 1: ~

O1 O2 O1&O2 O1|O2 O1^O2 ~O1


0 0 0 0 0 1
1 0 0 1 1 0
0 1 0 1 1 1
1 1 1 1 0 0

biţii de rang oarecare "i" ai celor doi operanzi cărora li se aplică operatorul logic pe biţi
Program exemplu: testarea operatorilor logici pe biţi

#include <stdio.h>

void binar(unsigned int v)


{
long int i,s[100],j,r,c,dim;
double val;
j=0;
do
{
c=v/2;
r=v%2;
s[j]=r;
j++;
v=c;
}
while(c>0);
val=0;
for(dim=j-1;dim>=0;dim--)
val=10.0*val+(s[dim]);
printf("%016.0lf",val);
}
int main()
{
long int a,b,c,i,o1,o2,rez;

printf("Program pentru testarea operatorilor logici pe biti:\n");


printf("Introduceti o1: ");
scanf("%ld",&o1);
printf("Introduceti o2: ");scanf("%ld",&o2);
binar(o1);
printf("\to1= %ld\n",o1);
binar(o2);
printf("\to2= %ld\n",o2);
//Testarea operatorului &
rez=o1&o2;
binar(rez);
printf("\to1&o2= %ld\n",rez);
//Testarea operatorului |
rez=o1|o2;
binar(rez);
printf("\to1|o2= %ld\n",rez);
//Testarea operatorului ^
rez=o1^o2;
binar(rez);
printf("\to1^o2= %ld\n",rez);
//Testarea operatorului <<
printf("\n");
binar(o1);
printf("\to1= %d\n",o1);
for(i=1;i<=3;i++)
{
binar(o1<<i);
printf("\to1<<%ld= %ld\n",i,o1 << i);
}
//Testarea operatorului <<=
printf("\n");
binar(o2);
printf("\to2= %ld\n",o2);
for(i=1;i<=3;i++)
{
binar(o2<<=i);
printf("\to2<<=%ld= %ld\n",i,o2);
}
//Testarea operatorului >>
binar(o1);
printf("\to1= %ld\n",o1);
for(i=1;i<=3;i++)
{
binar(o1>>i);
printf("\to1>>%ld= %ld\n",i,o1 >> i);
}
//Testarea operatorului ~
printf("\n");
binar(o1);
printf("\to1= %ld\n",o1);
b=~o1;
binar(b);
printf("\t~o1= %ld\n",b);
Exerciţiu
Scrieţi un program care să transforme în binar valori de tip int (stocate pe 16 biţi)
folosind o masca pentru biţi. (vezi Mark Burgess, C Programming Tutorial, Faculty of
Engineering, Oslo College, http://www.iu.hio.no/~mark/CTutorial/C-Tut-4.02.pdf, pag.
240-243)

Ce se întâmplă dacă folosiţi ca şi mască de biţi valoarea lui 1 (unu)?


Explicati!!!

Pentru a înţelege mai uşor programul, urmăriţi figura de mai jos:


CURS 6
Instructiunile limbajului C
Instructiuni
- părţi de program care prin compilare produc coduri executabile
- specifică ordinea şi modul în care vor fi efectuate calculele impuse de modul de
prelucrare a datelor de intrare ale programului.

structura secvenţială structura alternativă structura repetitivă


 instrucţiuni compuse  instrucţiunea if  instrucţiunile for,
sau instrucţiunea if-else while sau do-while
structura selectivă
 instrucţiunea switch

instrucţiunile: expresie, return, break, continue şi goto


Instrucţiunea expresie

- se obţine adăugând terminatorul de instrucţiune ; după o expresie


- poate fi concret o instrucţiune de atribuire sau o instrucţiune de apel de funcţie.
Exemple
pi=3.1415; //instrucţiune de atribuire
getch(); //apel de funcţie
clrscr(); //apel de funcţie
h_max=v0*v0/2/g; //atribuire
y=sqrt(fabs(x-a)); //apel de funcţie şi atribuire
i++; //atribuire
--contor; //atribuire
N=N0*exp(-lambda*t[i]); //atribuire

Instrucţiunea compusă
- folosită la codificarea structurilor secvenţiale
- constă dintr-o succesiune de instrucţiuni cuprinse între acolade
Exemple
{ {
t=a[i]; k++;
a[i]=a[i+1]; printf("\n%d:\t%d",k*k);
a[i+1]=t; }
}
Instrucţiunile if şi if-else
Instrucţiunea if
- folosită pentru implementarea structurilor alternative cu decizie simplă
Sintaxa Executie
- se evaluează expresie
if(expresie) - dacă expresie este adevărată (are
instrucţiune; valoare diferită de zero) se execută
instrucţiune, iar dacă expresie este
falsă nu se execută instrucţiune şi se
trece la instrucţiunea imediat
următoare lui if.

Instrucţiunea if-else
- folosita pentru implementarea structurilor alternative cu decizie dublă
Executie
Sintaxa - se evaluează expresie
- dacă expresie este adevărată se
if(expresie) execută instrucţiune_1 după care se
instrucţiune_1; trece la instrucţiunea imediat
else următoare lui if-else. Dacă expresie
instrucţiune_2; este falsă se execută instrucţiune_2
după care se trece la execuţia
instrucţiunii care urmează după if-
else.
Exemple
//rezolvarea ecuaţiei de gradul 1: ax+b=0
...
if(a) //în loc de if(a!=0)
Tips x=-b/a;
Pentru simplificarea expresiilor: ...

if(a!=0) {...}  if(a) {...} // Calculul solutiei unei ecuaţii neliniare


//folosind metoda lui Newton
...
si: if(df==0) //sau if(!df)
df=eps;

if(a==0) {...}  if(!a) {...}


x=x-f(x)/df;
...

//ordonarea crescătoare a unui şir de numere


//(metoda bulelor)
...
if(a[i]>a[i+1])
{
t=a[i];
a[i]=a[i+1];
a[i]=t;
ordonat=0;
}
Rezolvarea ecuaţiilor prin metoda înjumătăţirii intervalului
...
if(f(a)*f(c)<=0)
if(f(c)==0)
sol=c; else face pereche cu cel mai apropiat if
else
b=c;
else
a=c;
...

Discutati secventa:
...
if(n>0)
{
if(i<n)
s[i]=2*a[i];
}
else
printf("\n n este negativ!");
...

Exerciţiu:
Scrieţi un program care să calculeze impedanţa unui circuit de curent alternativ. Se vor citi
valorile R, L şi C, precum şi tipul circuitului (serie sau paralel). În funcţie de valorile datelor de
intrare se va calcula Z.
Instrucţiunea for
- utilizată pentru implementarea unei structuri repetitive condiţionată anterior, atunci când se ştie
apriori de câte ori se repetă blocul de calcul al acesteia
Sintaxa
for(exp1;exp2;exp3) Antet
instrucţiune; Corp de instructiuni
- se execută repetat cât timp este
îndeplinită condiţia definită de exp2

exp1 - secvenţa de iniţializare a instrucţiunii for


exp2 - defineşte condiţia de continuare a ciclului
! Dacă exp2 are valoarea zero (este falsă) de la
început, corpul instrucţiune nu se execută niciodată.
exp3 - secvenţa de reiniţializare a instrucţiunii for
for(exp1;exp2;exp3)
instrucţiune;

Execuţie:
1. se execută secvenţa de iniţializare definită de către exp1.
2. se evaluează exp2.
Dacă exp2≠0 (adevărată) se execută corpul de instrucţiuni al
instrucţiunii for. Dacă exp2=0 (falsă) se termină execuţia instrucţiunii
for şi se trece la execuţia instrucţiunii imediat următoare lui for.
3. după execuţia corpului de instrucţiuni al instrucţiunii for se
execută secvenţa de reiniţializare definită de exp3 şi se reia execuţia
de la pasul 2.

! exp1, exp2 şi exp3 pot fi vide


caracterele ; trebuie să fie prezente şi în acest caz.
Exemple //Calculul lui x^n
//Tiparirea tuturor literelor mari
char c; for(p=1,i=1;i<=fabs(n);i++)
for(c='A';c<='Z';c++) p=p*x;
putchar(c); if(n<0)
p=1/p;
//Tiparirea valorilor de la 0 la 100 din 2 in 2
int i;
for(i=0;i<=100;i+=2)
//Citirea elementelor unei matrici
printf("%d ",i); for(i=0;i<nl;i++)
for(j=0;j<nc;j++)
//Adunarea elementelor unui sir de numere {
printf("A[%d,%d]= ",i,j);
int n=4,j;
scanf("%f",&A[i][j]);
float s,sir[4]={3.5,-2,8,14.1};
}
for(s=0,j=0;j<n;j++)
s=s+sir[j];

//Calculul lui n!
for(f=1,i=2;i<=n;i++)
f*=i;
//Produsul a doua matrici
#define m 2
#define n 3
#define p 3
...
for(i=0;i<m;i++)
for(j=0;j<p;j++)
{
C[i][j]=0;
for(k=0;k<n;k++)
C[i][j]=C[i][j]+A[i][k]*B[k][j];
}
for(i=0;i<m;i++)
for(j=0;j<p;j++)
printf("\nC[%d,%d]= %g",i,j,C[i][j]);
...
Instrucţiunea while
-folosita pentru implementarea structurilor repetitive condiţionate anterior.

Sintaxa
while(expresie ) Antet
instrucţiune; Corp de instructiuni
- se execută repetat cât timp expresie
are valoare logica de adevar (diferita
de zero)

Execuţie:
1. Se evaluează expresie.
Dacă expresie este adevărată (are valoare nenulă) se execută corpul instrucţiunii
while şi se revine la evaluarea expresiei.
2. Când expresie devine falsă se trece la instrucţiunea imediat următoare
instrucţiunii while.

! Dacă expresie este falsă de la început, corpul de instrucţiuni al lui while nu se execută niciodată.
Pentru a se evita ciclarea infinită a corpului de instrucţiuni al lui while, acesta trebuie să conţină în mod
obligatoriu instrucţiuni prin care să se modifice termenii expresiei lui while.
Exemple
Tiparirea valorilor de la 0 la 100, din 2 in 2
int i=0; Sau echivalent:

while(i<=100) int i=0;


{
printf("%d ",i); while((i+=2)<=100)
i+=2; printf("%d ",i);
}

//Afisarea valorilor functiei sinus din grad in grad de la 0 la 360o, oprirea dupa afisarea a 24
linii pe ecran, cu evitarea opririi dupa afisarea valorii sin(0)

int x;
double pi=4*atan(1.0);
x=-1;
while(++x<=360)
{
printf("\nsin(%d)= %.15f",x,sin(x*pi/180));
if(x%24==0&&x) //stop din afisare dupa 24 de linii si evitarea
while(!_kbhit()); // opririi dupa afisarea valorii sin(0)
}
//Citirea dintr-un fisier, a cate 4 valori simultan, pana se ajunge la sfarsitul fisierului
FILE *fin;
float m,x,y,z;
int n=0;

fin=fopen("d:\\user\\c\\test.dat","r");
while(!feof(fin))
if(fscanf(fin,"%f%f%f%f",&m,&x,&y,&z)==4)
{
n++;
printf("\n%g\t%g\t%g\t%g",m,x,y,z);
}
fclose(fin);
printf("\nn= %d",n);
Instrucţiunea do-while
- utilizată pentru implementarea structurilor repetitive condiţionate posterior.

Sintaxa
do
instrucţiune;
while(expresie )

Execuţie:
1. Se execută instructiune.
2. Se evaluează expresie.
Dacă expresie este adevărată ( ≠0 ) se revine la pasul 1, altfel se trece la instrucţiunea imediat
următoare lui do-while.

! Corpul de instrucţiuni al lui do-while se execută cel puţin o dată, chiar dacă expresie este falsă de la
început.

Pentru a se evita ciclarea infinită a corpului de instrucţiuni al lui do-while, acesta trebuie să conţină în
mod obligatoriu instrucţiuni prin care să se modifice termenii expresiei .
Exemple
//Metoda bisectiei
...
do
{
c=(inf+sup)/2.0;
if((*pf)(c)==0) return c;
if((*pf)(inf)*(*pf)(c)<0)
sup=c;
else
inf=c;
}
while(fabs((*pf)(c)) >= eps);
//Metoda Newton
...
float newton(float (*)(float), float xv, float er)
{
float xn,der,eps=5e-4;
//xnou=xvechi-f(xvechi)/f'(xvechi)

xn=xv;
do
{
xv=xn;
der=(f(xv+eps)-f(xv))/eps;
if(der= =0.0)
der=eps;
xn=xv-f(xv)/der;
}
while(fabs(f(xn))>er);
return xn;
}
...
Instrucţiunea switch
- folosită pentru codificarea structurii selective (o generalizare a structurii alternative)
- echivalentă cu mai multe instrucţiuni if imbricate
- are avantajul că duce la creşterea lizibilităţii şi calităţii
programului
Sintaxa
switch (expresie) c1, c2, ..., cn
{ - etichete case
case c1: - reprezintă valori constante
instrucţiune_1;
instrucţiune_1,
break; instrucţiune_2, ... ,
case c2: instrucţiune_n şi instrucţiune
instrucţiune_2; - instrucţiuni simple sau
http://www.tutorialspoint.com/cplusplus/cpp_switch_statement.htm break; compuse.
... break;
case cn: - instrucţiune care are ca scop
instrucţiune_n; întreruperea instrucţiunii switch sau
break; întreruperea unui ciclu.
default: - la întâlnirea acesteia se iese
imediat din switch şi execuţia
Optionala! instrucţiune;
programului continuă cu
break;
instrucţiunea imediat
}
Execuţie:
switch (expresie)
1.se evaluează expresie; fie v valoarea acesteia.
2.se compară v cu valorile constantelor c1, c2, ..., cn.
{
Dacă v este egală cu una dintre aceste constante, de case c1:
exemplu ci, atunci se execută instrucţiune_i şi apoi se trece la instrucţiune_1;
instrucţiunea de după switch. break;
3. Dacă v nu coincide cu nici una dintre constantele ci se execută case c2:
instrucţiunea de după default (dacă aceasta există) după care se instrucţiune_2;
continuă la instrucţiunea de după switch. break;
...
Instrucţiunea switch este echivalentă cu o succesiune de mai case cn:
multe instrucţiuni if imbricate: instrucţiune_n;
if(expresie==c1) break;
instrucţiune_1 default:
else
instrucţiune;
if(expresie==c2)
instrucţiune_2 break;
else }
if
...
...
else
if(expresie==cn)
instrucţiune_n
else
instrucţiune
Exemple
Meniu pentru alegerea rezolvării unui sistem de ecuaţii, calculul unui determinant sau determinarea
inversei unei matrici

#include<stdio.h>
int main()
{
char optiune;
printf("\t\tMeniu:\nS)istem\t\tD)eterminant\tI)nversa\n");
optiune=getchar();
switch(optiune)
{
case 'S':
printf("Ati ales rezolvarea unui sistem de ecuatii");
break;
case 'D':
printf("Ati ales calculul unui determinant");
break;
case 'I':
printf("Ati ales determinarea inversei unei matrici");
break;
default:
printf("Optiune ilegala!");
}
}
Simularea unui calculator de operaţii simple
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
char oper;
float op1, op2, rez;
printf("Tastati o expresie de forma: operand1 operatie operand2: \n");
if(scanf("%f%c%f",&op1,&oper,&op2)!=3)
{
printf("\nExpresie eronata!");
exit(1);
}
switch(oper)
{
case '+':
rez=op1+op2;
break;
case '-':
rez=op1-op2;
break;
case '*':
rez=op1*op2;
break;
case '/':
if(op2==0)
{
printf("Eroare! Divizor nul.");
rez=0;
}
else
rez=op1/op2;
break;
default:
printf("Operator ilegal!");
rez=0;
}
printf("\n%g %c %g = %g",op1,oper,op2,rez);
while(!_kbhit());
return 0;
}
Exerciţiu: Folosiţi instrucţiunea switch pentru a modela următorul experiment: generaţi 100 de valori
aleatoare între 1 şi 5. Tipăriţi un grafic de forma alăturată, în funcţie de apariţiile fiecărei valori generate.
Instrucţiunile break şi continue
break
- întrerupe execuţia unui ciclu (for, while sau do-while) sau a unei Sintaxa
instrucţiuni switch
break;
- se foloseşte pentru ieşirea imediată, fără testarea unei anumite condiţii,
dintr-un ciclu şi renunţarea la execuţia în continuare a acestuia

continue
- abandonează iteraţia curentă a ciclului şi reia ciclul cu iteraţia următoare Sintaxa
- se foloseşte numai în interiorul instrucţiunilor for, while sau do-
continue;
while
Exemple
Folosirea instrucţiunilor break şi continue

#include <stdio.h>
#include <conio.h>

int main()
{
int k;
for( k=0;k<6;k++)
{
if(k==3)
break; // se abandoneaza instructiunea for
printf("In ciclul for cu *break*, k are acum valoarea %d\n",k);
}
for(k=0;k<6;k++)
{
if(k==3)
continue; // se abandoneaza iteratia corespunzatoare lui k=3
printf("In ciclul for cu *continue*, k are acum valoarea %d\n",k);
}
while(!_kbhit());
return 0;
}
Funcţia exit
- folosită pentru evitarea nivelelor mari de imbricare ale instrucţiunilor if sau if-else.
- prototipul funcţiei este:

void exit (int stare)

- se găseşte în <stdlib.h> şi în <process.h>

-are rolul de a întrerupe execuţia programului şi închiderea tuturor fişierelor deschise.

Stare defineşte starea programului în momentul apelului:

 valoarea 0 (zero) pentru stare corespunde unei întreruperi normale, fără eroare a
programului
 o valoarea diferită de zero defineşte o întrerupere cu eroare a programului.
Exemple
Se citeşte o valoare, se testează dacă ea aparţine intervalului [1,10] şi se calculează pătratul
acestei valori
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>

int main()
{
int v;

printf("Introduceti o valoare in intervalul [1,10]: ");


if(scanf("%d",&v)!=1)
{
printf("Valoare incorecta");
while(!_kbhit());
exit(1);
}
if((v<1)||(v>10))
puts("Eroare! v este in afara intervalului");
else
printf("%d^2= %d",v,v*v);

while(!_kbhit());
return 0;
}
Instrucţiunea goto
- transfera controlul execuţiei programului la o instrucţiune etichetată
- poate fi utilă doar atunci când se doreşte ieşirea din mai multe instrucţiuni if imbricate
Sintaxa
goto eticheta;

etichetă
- şir de caractere urmat de caracterul : şi care precede o anumită instrucţiune
Exemple
Găsirea unui element comun a două şiruri
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
int main()
{
int n,i,j,a[10],b[3]={0,5,10};
//Cauta in sirul a un element al sirului b.
//Daca un astfel de element este gasit, cautarea inceteaza
printf("Dimensiunea primului sir: ");
scanf("%d",&n);
printf("Introduceti elementele primului sir\n");
for(i=0;i<n;i++)
scanf("%d",&a[i]);
for(i=0;i<3;i++)
for(j=0;j<n;j++)
if(b[i]==a[j])
goto gasit;
printf("\nNu s-a gasit nici un element comun al celor doua siruri");
while(!_kbhit());
exit(0);
gasit:
printf("\nS-a gasit elementul comun: %d",b[i]);
while(!_kbhit());
return 0;
}
CURS 7
Pointeri
- tipuri speciale variabile sau constante care au ca valori adrese ale unor alte variabile sau
constante (adrese ale unor locaţii de memorie)
- permit calcule cu adrese
- specifice limbajelor de asamblare
- sunt folosiţi în scopul scrierii unor programe mai eficiente atât din punctul de vedere al
timpului de execuţie cât şi din punctul de vedere al utilizării resurselor hard, în mod
concret al utilizării memoriei computerelor.
- sunt în mod special utili la alocarea dinamică a memoriei şi la apelul prin referinţă.
Pointerii
- păstrează adresa începutului locaţiei în care este stocată o anumită valoare.
- pachet compus din două părţi:
- pointerul însuşi
- care are ca valoare adresa primului octet al locaţiei de memorie în care este
stocată o variabilă (sau constantă)
- tipul valorii stocate în locaţia de memorie la începutul căreia pointează
- spune computerului câtă memorie să citească după adresa la care pointează
şi cum să o interpreteze
Limbajul C foloseşte pointerii în trei moduri:
a) pentru a crea structuri dinamice de date construite din blocuri de memorie
b) pentru a opera cu parametrii pasaţi funcţiilor la apelul acestora
c) pentru a accesa informaţia stocată în tablouri

În cazul unui pointer la o funcţie, tipul pointerului va fi tipul de dată returnat de


către funcţie, iar valoarea sa va fi adresa la care începe codul funcţiei respective

Pentru lucrul cu pointeri, limbajul C oferă doi operatori:


-&
- &x înseamnă adresa variabilei x (de fapt adresa primului octet al locaţiei de
memorie în care este stocată variabila x)
- *
- *p1 valoarea stocată în locaţie de memorie la care pointează pointerul p1.
Declararea şi iniţializarea pointerilor
Declarare
tip *nume_pointer; sau tip* nume_pointer;

tip
- tip de date de bază sau tip utilizator

nume_pointer
- identificator folosit pentru pointerul care se declară

Exemple
float *pf; //pf poate conţine adrese la care se află memorate date de tip float
int *pi; //pi poate conţine adrese la care se află memorate date de tip int
char* pc; //pc poate conţine adrese la care se află memorate date de tip char

struct agenda
{
char nume[20];
char tel[15];
};

struct agenda *psa;


//psa este un pointer la date de tip structură agenda.
Iniţializare
- precizarea adresei unui obiect definit în memorie.
- p - numele unui pointer => *p reprezintă valoarea de la adresa la care "pointează"
pointerul p.
CURS 8
Managementul fişierelor în C
Fisier
- colecţie de date, păstrată pe un dispozitiv periferic (magnetic sau optic)
- succesiune de caractere, de cuvinte, linii sau pagini ale unui document
de tip text
- înregistrări ale unei baze de date
- pixelii unei imagini grafice
- etc.
Operatii
- deschidere, închidere, creare, citirea datelor, adăugarea de înregistrări, poziţionarea pe o
anumită înregistrare, ştergerea fişierelor
Accesare
- de la începutul sau de la sfârşitul fişierului
- dintr-un loc oarecare din fişier.
1. Pentru prevenirea folosirii necorespunzătoare a unui fişier, sistemul de operare instalat pe calculator
trebuie să fie înştiinţat despre scopul în care este deschis fişierul şi despre operaţiile care vor fi
efectuate (citire, scriere, adăugare) asupra datelor.

2. La încheierea operaţiunilor care se efectuează asupra datelor dintr-un fişier acesta trebuie închis
deoarece în caz contrar, sistemul de operare nu poate actualiza datele referitoare la acel fişier
(dimensiune, data ultimei accesări, etc.).
Tipuri de fişiere
1. fişiere text
 stochează datele ca o secvenţă de caractere alfanumerice
 conţinutul acestor fişiere este lizibil şi poate fi editat direct cu ajutorul unui editor de texte.
 sunt organizate pe rânduri, fiecare rând fiind delimitat de caracterul de sfârşit de rând (EOL)
 sunt citite caracter cu caracter
 => funcţiile pentru citirea şi scrierea lor vor fi aproape identice cu cele folosite pentru
citirea de la tastatură şi respectiv scrierea pe monitor.
 sunt procesate secvenţial
 => un fişier text se deschide de obicei numai pentru un anumit tip de operaţie la un
moment dat (citire, scriere sau adăugare)

2. fişiere binare
 pot să conţină orice tip de date, codate într-o formă binară, în secvenţe de bytes
 pot conţine orice fel de informaţie : text formatat, imagini, sunete, etc.
 diferă de fişierele text în două puncte esenţiale:
 fiecare octet de date este transferat pe sau de pe disc neprocesat
 interpretarea lor este lăsată pe seama programatorului (pot fi citite sau scrise în orice
mod dorit de către programator)
 pot fi procesate secvenţial sau aleator
 sunt accesate mai rapid decât fişierele text
 sunt înţelese numai de programe scrise special să lucreze cu astfel de fişere (de ex. bazele de
date)
Exemple
Declararea fişierelor
FILE *df;

FILE - cuvânt cheie care semnifică o structură de date de tip fişier


df - descriptor de fişier
- pointer spre tipul FILE.

Exemple
FILE *f1, *fin, *frez, *ftext;

Deschiderea fişierelor
Funcţia fopen: -> #include <fstream>
FILE *fopen(const char *cale, const char *mod);

cale - pointer spre un şir de caractere care defineşte calea spre fişierul care se deschide
mod - pointer spre un şir de caractere care defineşte modul de prelucrare a fişierului
după deschiderea acestuia.
cale = reprezintă orice nume valid de fişier, eventual precedat de calea de directoare
până la acesta, cuprins între ghilimele. Dacă trebuie specificată calea până la
respectivul fişier, atunci directoarele căii vor fi separate prin \\ ca de exemplu:
"d:\\input.txt".
fopen - returneaza: in caz de succes - un pointer la fisier
in caz de eroare – pointerul NULL
mod = atributul fişierului
- poate avea valorile

"r" - fişierul se deschide pentru citire


"w" - fişierul se deschide pentru scriere
"a" - fişierul se deschide pentru adăugare de înregistrări
- nu permite repozitionarea in fisier
"rb" - fişierul se deschide pentru citire binară
"wb" - fişierul se deschide pentru scriere binară
"r+b" - caz în care fişierul se deschide pentru citire şi scriere binară

1. Un fişier inexistent, deschis în modul "w" va fi creat (dacă este posibil) în momentul deschiderii,
iar un fişier existent deschis în modul "w" va fi creat din nou, ceea ce înseamnă că vechiul său
conţinut se va şterge.

2. Deschiderea în modul "w" va eşua dacă sistemul nu poate deschide fişierul


-disc plin, disc protejat la scriere, nu exista drepturi de acces la fisier
3. Deschiderea în modul "r" eşuează daca:
fişierul nu există, fişierul este protejat într-un anume fel

4. Unui fişier inexistent deschis în modul "r" i se va asocia pointerul NULL.

5. La deschiderea în modul "a", dacă fişierul există, poziţionarea se face la sfârşitul fişierului, iar dacă
nu există atunci el va fi creat.

6. Deschiderea în modul "a" poate eşua în aceleaşi cazuri în care eşuează deschiderea în modul "w".
Exemple

FILE *f, *fin;


f=fopen("notean1.dat","r");
/* se deschide fisierul notean1.dat, din directorul curent, in modul citire.*/

fin=fopen("c:\\soft\\config.ini","w");
// se deschide fisierul c:\soft\config.ini in modul scriere.

Folosirea pointerului NULL poate fi folosit pentru testarea posibilităţii deschiderii unui fişier
if((f=fopen("fis_test","r"))==NULL)
printf("Eroare la deschiderea fisierului!");

sau :

f=fopen("fis_test","r");
if(!f)
printf("Eroare la deschiderea fisierului!");

Închiderea fişierelor
int fclose(FILE *pf);
pf - pointerul spre tipul FILE
- valoarea lui a fost determinată de către funcţia fopen la deschiderea fişierului.
- returnează valoarea 0 la închidere reuşită şi valoarea -1 în caz de eroare.
Exemplu
1. fclose(fin);

2. // Testarea închiderii reusite a unui fisier


// se poate intampla atunci cand pointerul fin nu a fost initializat
if(fclose(fin)) //sau: if(fclose(fin)!=0)
{
printf("Fisierul nu exista ! ");
exit(0);
}
Citirea şi scrierea fişierelor
fscanf, fprintf, fgetc, fputc, fgets, fptus, fread, fwrite.

fscanf(*pf, "control", &par1, &par2, ... , &parn);


fprintf(*pf,"control",par1, par2, ... , parn);
Exemple
FILE *fin, *fout;
fin=fopen("test.inp","r");
fout=fopen("test.out","w");
...
fscanf(fin,"%d",&n);
fprintf(fout,"n^2= %d",n*n);
...
După fiecare caracter citit, poziţia în fişier avansează cu o unitate.
Funcţiile fread şi fwrite
- folosite pentru citirea/scrierea fişierelor binare.

Funcţia fwrite
- scrie un bloc de memorie în fişierul specificat
Functia fread
- citeşte date dintr-un fişier binar şi le pune într-un bloc de memorie.

Apelul funcţiei fread:


fread( ptr, size, n, f )

ptr - pointer la blocul de memorie în care se vor prelua datele citite din fişier
size - lungimea în octeţi a blocului citit
n - numărul de itemi citiţi
f - pointer la fişierul din care se face citirea

Apelul funcţiei fwrite :


fwrite( ptr, size, n, f )

ptr - pointerul la blocul de date care va fi scris în fişierul binar

Numărul de octeţi scrişi este n*size.


Funcţiile fgetc şi fputc
-folosite pentru citirea, respectiv scrierea unui caracter dintr-un/într-un fişier (stream)
- returnează caracterul citit sau scris în caz de succes şi EOF în caz de eroare.
Prototipuri:
fgetc(FILE *stream);
fputc(int c, FILE *stream);

EOF - caracter constant care indică sfârşitul de fişier.


- citirea lui se testeaza cu funcţia feof(f)
feof returnează: - o valoare nenulă dacă a fost detectat caracterul EOF
- zero dacă nu a fost citit caracterul EOF.
Funcţiile fgets şi fputs
- folosite pentru preluarea într-un şir, respectiv scrierea într-un şir a unor caractere dintr-un/într-
un fişier (stream).
Prototipuri:
char *fgets(char *s, int n, FILE *stream);
int fputs(const char *s, FILE *stream);
Funcţia fgets - preia într-un şir n-1 caractere dintr-un fişier
- returnează şirul la care pointează s, respectiv pointerul NULL în caz de eroarea
sau la întâlnirea caracterului EOF.

Funcţia fputs - scrie un şir de caractere într-un fişier


- returnează ultimul caracter scris, respectiv EOF în caz de eroare.
Exemple
//Citirea unui rand dintr-un fisier
char sir[100];
FILE *f;
f=fopen("d:\\test.inp","r");
fgets(sir,100,f);
printf("Sirul citit este: %s",sir);
fclose(f);

// Tiparirea la imprimanta (functioneaza pentru o imprimanta


// conectata la portul LPT1
FILE = *prt;
if((prt=fopen("LPT1","w"))==NULL)
{
printf("\a\nPrinter nedisponibil");
exit(0);
}
else
fprintf(prt,"Test tiparire la imprimanta!");
Poziţionarea într-un fişier
Funcţiile ftell şi fseek
ftell - determină poziţia curentă a capului de citire/scriere
- are prototipul:
long ftell(FILE *pf)
- returnează o valoare care reprezintă deplasamentul în octeţi al poziţiei capului de
citire/scriere faţă de începutul fişierului.

Fseek - permite poziţionarea aleatoare într-un fişier


- returnează 0 în caz de succes (poziţionare corectă a cursorului în fişier)
- prototipul funcţiei:
int fseek(FILE *pf, long deplasament, int origine);

pf - pointer spre tipul FILE


- defineşte fişierul în care se face poziţionarea capului de citire/scriere
- valoarea sa este determinată la deschiderea fişierului.

Deplasament
- defineşte numărul de octeţi peste care se va deplasa capul de citire/scriere al discului
- poate fi o valoare întreagă pozitivă sau negativă.

Origine
- determină locul din care se face deplasarea capului
- poate avea valorile:
0 -> deplasare de la inceputul fisierului
1 -> deplasare de la pozitia curenta a capului de citire/scriere a fisierului
2 -> (deplasare de la sfârşitul fişierului)
Ştergerea unui fişier
- se foloseşte funcţia unlink
- prototip:
int unlink(const char *cale);

cale - specifică fişierul care va fi şters.

Funcţia nu poate şterge fişierele read-only sau fişierele deschise şi returnează valoarea 0 la ştergere
reuşită, respectiv -1 în caz de eroare.
Program exemplu: crearea unui fişier text cu 5 linii
#include <stdio.h>
#include<string.h>
#include <fstream>

int main( )
{
FILE *fp;
char text[25];
int i;

fp = fopen("d:\\flinii.txt","w");
strcpy(text,"Acesta este randul: ");
for (i=1;i<=5;i++)
fprintf(fp,"%s%d\n",text,i);
fclose(fp);
return 0;
}
Program exemplu: determinarea numărului de caractere dintr-un fişier (se numără şi caracterele de rând nou)
#include <stdio.h>
#include <stdlib.h>
#include <fstream>

int main( )
{
FILE *fp;
char c;
int n=0;
/*Se deschide fisierul de intrare, testandu-se deschiderea corecta a acestuia.
Daca deschiderea fisierului nu se poate realiza (fisier inexistent) functia
fopen returneaza pointerul NULL*/
if((fp = fopen("d:\\flinii.txt","r"))==NULL)
{
printf("Eroare la deschiderea fisierului!");
exit(1);
}
while(fscanf(fp,"%c",&c)==1)
{
n++;
}
fclose(fp);
printf("In fisier sunt %d caractere.",n);
return 0;
}

Exerciţiu
Modificaţi programul de mai sus astfel încât caracterele de rând nou să nu fie numărate.
Program exemplu: interogarea utilizatorului în cazul suprascrierii unui fişier deschis în modul "w".
do {
#include<stdio.h>
printf("\nIntroduceti numele fisierului de iesire: " );
#include<conio.h>
gets(nfout) ;
int main()
fout=fopen(nfout,"r") ;
{
if(fout!=NULL) {
FILE *fout;
fclose(fout);
char nfout[20];
printf("\aFisierul exista! \nSuprascrieti acest
char opt;
fisier? (D/N): ");
int OK;
opt=getche();
switch(opt) {
case 'D':
{ OK=1;
fout=fopen(nfout,"w");
break;
}
default:
OK=0;
}
}
else
{ fclose(fout);
OK=1; fout=fopen(nfout,"w");
}
}
while((OK!=1)&&fout); if(opt=='D') fprintf(fout,"Suprascriere
in fisier!");
else fprintf(fout,"Scriere in
fisier!");
printf("\nTerminat!");
fclose(fout);
return 0;
}
Program exemplu: folosirea funcţiei fgets pentru tipărirea unui fişier pe ecran
#include<stdio.h>
#include<conio.h>
int main()
{
char *c, rand[100],nf[25];
FILE *f;
printf("Introduceti numele fisierului: ");
scanf("%s",nf);
f=fopen(nf,"r");
do
{
c=fgets(rand,100,f); //functia fgets returneaza sirul la care pointeaza
//pointerul rand.
if(c)
printf("%s",rand);
}
while(c);
fclose(f);
while(!_kbhit());
return 0;
}
Program exemplu: folosirea funcţiilor fwrite şi fread
strcpy(ag.n,"Popescu");
//Testarea functiilor fwrite si fread strcpy(ag.p,"Georgel");
#include <stdio.h> strcpy(ag.tel,"0445111222");
#include<stdlib.h> ag.v=40;
#include <string.h> ag.s=1;
struct bd fwrite(&ag,sizeof(ag),1,fin);
{ fclose(fin);
char n[20],p[20],tel[20]; fin=fopen("c:\\temp\\bd.dat","rb");
int v; fseek(fin,0,0);
int s; printf("Datele din fisier:\n\n");
}; fread(sir,sizeof(ag.n),1,fin);
void main() printf("NUME: \t\t%s\n",sir);
{ fread(sir,sizeof(ag.p),1,fin);
FILE *fin; printf("PRENUME: \t%s\n",sir);
struct bd ag; fread(sir,sizeof(ag.tel),1,fin);
char sir[20]; printf("Telefon: \t%s\n",sir);
int *pi,*pu; fread(pi,sizeof(ag.v),1,fin);
if((fin=fopen("c:\\temp\\bd.dat","wb"))==NULL) printf("Varsta: \t%d\n",*pi);
{ fread(pu,sizeof(ag.s),1,fin);
printf("Eroare la deschiderea fisierului!"); printf("Stare civila: \t%d\n",*pu);
exit(1); }
}
După rularea acestui program se obţine fişierul bd.dat în Pe ecran, va fi tipărit:
directorul d:\c. Deschizând fişierul bd.dat cu un utilitar de
gestiune a fişierelor, acesta va arăta sub forma:
Program exemplu: calculul coordonatelor centrului de masă al unui sistem de particule ale căror date se
găsesc într-un fişier
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
FILE *fin,*fout;
float m,x,y,z,sm,smx,smy,smz,xc,yc,zc;
int i;
char opt;
void scrie_date()
{
fout=fopen("d:\\bc\\centru.rez","w");
fprintf(fout,"Nr. particule: %d",i);
fprintf(fout,"\nsm= %g \nsmx= %g smy= %g smz= %g ",sm,smx,smy,smz);
fprintf(fout,"\nxc= %g\t yc=%g\t zc=%g\n",xc,yc,zc);
fclose(fout);
}
int main()
{
sm=smx=smy=smz=0;
i=0;
if((fin=fopen("d:\\bc\\centru.dat","r"))==NULL) {
printf("\nFisierul nu poate fi deschis\a\a\a");
}
while(!feof(fin)) {
if(fscanf(fin,"%f%f%f%f",&m,&x,&y,&z)==4) {
sm+=m; smx+=m*x; smy+=m*y; smz+=m*z;
i++;
}
}
xc=smx/sm;
yc=smy/sm;
zc=smz/sm;
fclose(fin);
if((fout=fopen("d:\\bc\\centru.rez","r"))!=NULL)
{
printf("\nAtentie! Fisierul de output exista!");
printf("\nCONTINUATI ? (Y/N)");
opt=getch();
fclose(fout);
if((opt=='y')||(opt=='Y') )
scrie_date();
else
{
printf("\nExecutie terminata!");
exit(1);
}
}
else
scrie_date();
printf("\nTerminat!");
return 0;
}

Bibliografie suplimentară
http://www.codingunit.com/c-tutorial-binary-file-io
Parametrii liniei de comandă
În C este posibilă apelarea programelor şi transferarea parametrilor acestora în linia de
comandă.

Exemplu: suma 3.8 9.2

Funcţia main trebuie să fie definită sub următoarea formă:


int main(int argc, char* argv[])
{
...
}
argc - specifică numărul de argumente, adică numărul parametrilor din linia de comandă cu care
a fost apelat programul.
argv[] - vector de pointeri la şiruri de caractere care constituie argumentele cu care este apelat
programul; fiecare element al vectorului de pointeri pointează la un şir (de fapt la primul
caracter al şirului).

Lista de pointeri în argv este terminată întotdeauna cu pointerul NULL, astfel încât argv[argc]
este NULL.

Prin convenţie, argv[0] este numele aplicaţiei (calea completă către programul executabil), iar cel
de-al doilea este primul argument furnizat de către utilizator.

Dacă argc are valoarea 1 atunci nu există parametri în linia de comandă, după numele
programului.
Program exemplu: Tipărirea numelui programului şi a parametrilor săi din linia de comandă
#include <stdio.h>
int main(int argc, char *argv[])
{
int i;
printf("Numele programului este: %s\n",argv[0]);
//Numele programului este primul pointer din tabloul de pointeri argv[]
printf("Programul are %d parametri, si acestia sunt:\n",argc-1);
//Numele programului nu este considerat explicit ca parametru
for (i=1; i<argc; i++)
printf("%s%s",argv[i],(i < argc- 1) ? " " : "");
//Se tipareste caracterul spatiu dupa fiecare parametru daca acel
//parametru nu este ultimul
return 0;
}

Executabilul se lansează în execuţie într-o fereastră DOS (Start -> Run -> cmd) sub forma:
Program exemplu: suma a două numere introduse în linia de comandă
#include <stdio.h>
#include <process.h>
#include <math.h>
main(int argc,char *argv[])
{
double n1,n2,s;
int n=argc;
if(n<3)
{
printf("\nParametri insuficienti!");
exit(1);
}
else
if(n>3)
{
printf("Prea multi parametri!");
exit(1);
}
else
{
n1=atof(argv[1]); //atof face conversia de la string la double
n2=atof(argv[2]);
s=n1+n2;
printf("\nSuma numerelor introduse este %lf",s);
}
return 0;
}

Exercitiu
Scrieti un program cu parametri in linia de comanda, pentru concatenarea a doua fisiere.
CURS 9
Tipuri de date derivate
- tipuri definite de către utilizator
- bazate pe tipurile de date de bază
- permit prelucrarea globală a unor grupe complexe de date
Tipul enumerare
- permite folosirea unor nume sugestive pentru valori numerice.
Exemple
1. roşu, oranj, galben, verde albastru, indigo şi violet pot fi asociate valorilor numerice
1, 2, 3, 4, 5, 6, 7.
enum nume
{
nume_0, nume_1, ..., nume_k
} data_1, data_2, ..., data_n;
enum culoare {Rosu=1,Oranj, Galben, Verde, Albastru, Indigo, Violet} cul;
cul=Galben; 3
printf(“%d”,cul);

enum colors
{
rosu=650, oranj=590, galben=570, verde=510, albastru=475, indigo=445, violet=400
} col;
Tipul reuniune
- variabilă care poate păstra obiecte de diferite tipuri şi dimensiuni.
- permite păstrarea într-o zonă de memorie a unor date de tipuri diferite, lucru care duce la
posibilitatea reutilizării unor zone de memorie şi deci la economisirea memoriei

Accesul membrilor reuniunii:


Declarare - prin nume calificate
union nume - prin intermediul pointerilor :
{
lista de declaraţii; cerc.x cerc *p,c1;
} cerc.y p=&c1;
data_1, data_2, ..., data_n; cerc.r p->x
cerc.fill p->y
Exemplu p->r
union a { p->fill
int x,y;
double r; Membrii unei structuri sunt stocaţi la aceeaşi adresă,
char fill; aşadar, în mod evident, un singur membru poate fi
} cerc;
stocat la un moment dat.
Pentru date de diferite tipuri union se O reuniune poate păstra oricare dintre membrii săi,
alocă o zonă de memorie necesară dar la momente diferite de timp.
pentru a păstra data care necesită un se recomandă utilizarea cu atenţie a datelor de
număr maxim de octeţi. acest tip
În exemplul de mai sus, pentru orice
dată de tip union a se alocă 8 octeţi.
Tipul structură
- un set de variabile, nu neapărat de acelaşi tip, grupate împreună sub un singur nume, conform unei
ierarhii.
- permite ca un grup de variabile aflate într-o anumită legătură să fie tratate ca o unitate şi nu ca
entităţi separate.

Declararea structurilor:
struct nume struct nume
{ {
lista_de_declaratii; lista de declaraţii;
} };
data_1, data_2, ..., data_n; struct nume data_1, data_2, ..., data_n;
Exemple
Explicaţi output-ul programului de mai jos:
#include <stdio.h> Output:
int main()
{
union a
{
int x,y;
double r;
char fill;
}
cerc, *p;
cerc.y=66;
printf("y= %d",cerc.y);
printf("\nfill: %c",cerc.fill);
cerc.y=67;
printf("\nx= %d",cerc.x);
printf("\nfill: %c",cerc.fill);
printf("\nr: %lf",cerc.r);
printf("\nr: %d",cerc.r);
return 0;
}
Tipul structură
- set de variabile, nu neapărat de acelaşi tip, grupate împreună sub un singur nume,
conform unei ierarhii
- permit ca un grup de variabile aflate într-o anumită legătură să fie tratate ca o unitate
şi nu ca entităţi separate.

Tablourile sunt structuri particulare în care toate elementele structurii sunt de acelaşi tip.

Declarare:
struct nume struct nume
{ {
lista_de_declaratii; lista de declaraţii;
} };
data_1, data_2, ..., data_n; struct nume data_1, data_2, ..., data_n;

typedef struct nume


{
lista de declaraţii;
};
nume data_1, data_2, ..., data_n;
nume - numele tipului introdus prin această structură
data_1, data_2, ..., data_n - date de tipul structură nume

membrii structurii
Exemple O structură poate avea ca mebru o altă structură.
struct coord Având declarată structura coord, o structură dreptunghi
{
int x;
poate fi declarată sub forma:
int y; struct drpt
} poz; {
struct coord pss;
Initializarea structurii: struct coord pdj;
struct coord poz={30,30}; } dr;

struct data
typedef struct nucleu {
{ int zi;
int nrp; enum luni{Ian=1, Feb, Mar, Apr, Mai, Iun, Iul,
int nrn; Aug, Sep, Oct, Noi, Dec
} ; } luna;
nucleu C12={6,6},C13; int an;
C13.nrp=6; };
C13.nrn=7;
struct date_personale
{
char nume[30], prenume [30], adresa[50];
struct data data_nasterii;
long cod;
int varsta;
enum stare {Necasatorit, Casatorit} stare_civ;
int nr_copii;
};

struct date_personale staff_ubb[2000],


staff_ffiz[50], angajat;
Accesul la elementele structurilor
- se foloseste operatorul . (operator membru de structură)
poz.x=20;
staff_ubb[7].data_nasterii.an=1950;
strcpy(angajat.data_nasterii.luna,"Apr");
Transferarea structurilor catre funcţii
- se folosesc pointeri
Exemplu
Fie o funcţie care prelucrează structura angajat. O astfel de funcţie va fi apelată sub
forma:
f(&angajat)
Antetul funcţiei f va fi:
void f(struct date_personale *psdp)

În corpul lui f nu se pot utiliza nume calificate de forma:


angajat.nume, angajat.data_nasterii.zi, etc.
Accesul elementelor structurii se face prin intermediul pointerului, sub forma:
(*psdp).nume, (*psdp).data_nasterii.zi
Eventual, în loc de construcţia (*psdp). se pot folosi construcţii de forma:
psdp->nume, psdp->data_nasterii.zi, etc.

Este posibila copierea unei întregi structuri într-o singură instrucţiune:


angajat=staff_ubb[2];
Exemple

Exemple structuri
CURS 10
Regresia liniară
- aproximarea unei functii tabelate cu o functie analitica de gradul 1, prin metoda
celor mai mici patrate

1310

1300

1290

1280

1270
Y

1260

1250

1240
y = -78.545x + 1313.4
1230 R² = 0.9823

1220
0 0.2 0.4 0.6 0.8 1 1.2
X
Fie o funcţie:
f:[a,b], [a,b]
pentru care este cunoscut un număr discret de valori yi într-un număr de puncte de reţea xi[a,b]:

f(xi)=yi, i  1,n

In general, valorile yi sunt afectate de erori de măsură sau de erori de calcul


xi yi
Ce vrem?
0.10 1305.00 1310
Aproximarea acestei funcţii tabelate f
0.20 1295.00 1300
0.30 1293.00
cu o funcţie "model":
1290
0.40 1283.00
0.50 1270.00 1280

0.60 1267.00 1270


Y

0.70 1260.00 1260 αj - parametri ai funcţiei model


0.80 1256.00
1250
0.90 1243.00
1.00 1230.00 1240 De ce?
1230 F(xi;αj)
1220 - permite cunoasterea valorii in orice
0 0.2 0.4 0.6 0.8 1 1.2
punct x  xi
X
- poate fi derivata, integrata sau
Cum alegem functia model? folosite in alte calcule
 F trebuie să fie determinată de fenomenul fizic modelat
 F se va alege dintr-o clasă convenabilă de funcţii care să ofere simplitate şi eficienţă în prelucrări ulterioare
αj => F

Cum determinam parametrii funcţiei model?


Se defineşte o funcţională care să reflecte gradul în care funcţia F aproximează funcţia tabelată f.

Distanţa dintre funcţia tabelată şi funcţia model:

Cazuri:

Interpolare: graficul functiei F trece prin toate punctele (xi,yi)

Fitare: graficul functiei F nu trece neaparat prin punctele (xi,yi)


Fitare
- se minimizează suma abaterilor pătratice ale funcţiei model faţă de funcţia tabelată:
n
S    y i  F(x i ;  j )
2

i 1
= regresie (ajustare) prin metoda celor mai mici pătrate

Condiţiile de obţinere a parametrilor αj:


S
 0; j  1, k
 j
Regresia liniară Condiţiile de obţinere a parametrilor αj (a şi b):
Funcţia model = funcţie de gradul 1: F=ax+b  S
F=F(xi, αj) j=2  a  0

n
 S  0
S    y i  (ax i  b)
Funcţionala S: 2
 b
i 1
 n
2  y i  (ax i  b)(  x i )  0
 i 1
 n
2 1   y  (ax  b)  0
 
i 1
i i

 n n n

2 x i y i  2 ax i  2 bx i  0
2

 i 1 i 1 i 1
 n n n
2 y  2 ax  2 b  0
 
i 1
i 
i 1
i 
i 1

Notăm:
n n n n

x y
i 1
i i  Sxy x
i 1
2
i  Sxx x
i 1
i  Sx y
i 1
i  Sy

Tinem cont că:


n

 b  nb
i 1
Sistemul de ecuaţii devine:

Sxy  aSxx  bSx  0




S y  aSx  nb  0

Înmulţind prima ecuaţie cu n şi a doua cu (-Sx) şi adunându-le se obţine:
Sx S y  nSxy 1
a
(Sx )2  nSxx
b
n

Sy  aSx 
Semnificatia parametrilor de fit:
a - panta dreptei de regresie
a=tg(α)
α - unghiul făcut de graficul
funcţiei F cu axa absciselor
b - valoarea la care graficul funcţiei
intersectează axa ordonatelor
(interceptor)

Ub=E-rI E=b
F=ax+b r=|tg()|

Valorile estimate de dreapta de regresie (yicalc) sunt interpretate ca medii ale valorilor y asociate
cu o anumită valoare xi.
Cum se procedează atunci când funcţia model nu este o funcţie de gradul 1?

Exemplu
Un set de măsurători de radioactivitate
t(ore) Λ(mCi)
2.5
3
280
218 (t)  0 e t
3.5 177
4 140
4.5 100
5 85
5.5 67
6 48
6.5 42
7 30
7.5 20
8 17

1Ci = 3.7·1010 Bq
t(ore) Λ(mCi) ln(Λ))
2.5 280 5.63 ln((t))  ln(0 )  t
3 218 5.38
3.5 177 5.18
4 140 4.94
4.5 100 4.61
5 85 4.44
5.5 67 4.20
6 48 3.87
6.5 42 3.74
7 30 3.40
7.5 20 3.00
8 17 2.83

ln(Λ0(t))=y‘
y'=a-bt unde a=ln(Λ0) şi b=λ

Λ0=exp(6.9565)=1049.95
- ln(0)
Coeficientul de corelare R2
- dă calitatea unei drepte de regresie

R2 = 1 => funcţia model explică întreaga variabilitate a lui y


R2 = 0 => nu există nici o relaţie liniară între variabila răspuns şi variabila x (între y şi x)
R2 = 0.5 => aproximativ 50% din variaţia variabilei răspuns poate fi explicată de către variabila independentă
//regresia liniara
#include <stdio.h>
#include <conio.h>
#include <graphics.h>
#include<stdlib.h>
#include<math.h>

int main()
{
FILE *f;
int n,i,xpmin,xpmax,ypmin,ypmax,xr,yr;
float x,y,xd[20],yd[20],xdmin,xdmax,ydmin,ydmax;
float Sx,Sy,Sxx,Sxy,a,b;
float ymed, s1,s2,R2;
float ax,bx,ay,by;
int xp[50],yp[50];
char nf[20],stra[15], strb[15];

printf("Numele fisierului de intrare: ");


gets(nf); f=fopen(nf,"r");
if(!f)
{
printf("\nFisier inexistent!");
getch();
exit(1);
}
i=0;
Sx=Sy=Sxx=Sxy=0;
while(!feof(f))
{
if(fscanf(f,"%f%f",&x,&y)==2)
{
xd[i]=x; yd[i]=y; i++; Sx+=x; Sy+=y; Sxx+=x*x; Sxy+=x*y;
}
}
n=i; a=(n*Sxy-Sx*Sy)/(n*Sxx-Sx*Sx); b=(Sy-a*Sx)/n;
fclose(f);
f=fopen(nf,"r");
s1=s2=0;
ymed=Sy/n;
while(!feof(f))
{
if(fscanf(f,"%f %f",&x,&y)==2)
{
s1+=(a*x+b-y)*(a*x+b-y);
s2+=(ymed-y)*(ymed-y);
}
}
R2=1-s1/s2;

printf("===================================================\n");
printf("n= %d",n);
for(i=0;i<n;i++)
printf("\n%10.2f\t%10.2f",xd[i],yd[i]);

printf("\n\nParametrii de fit sunt:\na= %7.3f\tb= %7.3f\n",a,b);


printf("\nCoeficientul de corelare: R2= %g\n",R2);
printf("===================================================\n");

fclose(f);

xdmin=xdmax=xd[0];
ydmin=ydmax=yd[0];
for(i=0;i<n;i++)
{
if(xd[i]>xdmax)
xdmax=xd[i];
else
if(xd[i]<xdmin) xdmin=xd[i];
if(yd[i]>ydmax) ydmax=yd[i];
else if(yd[i]<ydmin) ydmin=yd[i];
}
//Dimensiunile ferestrei de afisare si coeficientii de scalare
xpmin=160;xpmax=440;
ypmin=85;ypmax=365;
ax=(xpmax-xpmin)/(xdmax-xdmin);
bx=xpmin-ax*xdmin;
ay=(ypmax-ypmin)/(ydmin-ydmax);
by=ypmax-ay*ydmin;

for(i=0;i<n;i++)
{
xp[i]=(int)(ax*xd[i]+bx);
yp[i]=(int)(ay*yd[i]+by);
}

initwindow(800,500,"Regresia liniara",5,5);
xpmax=getmaxx();
ypmax=getmaxy();
setcolor(GREEN);
xr=4;yr=4;
for(i=-1;i<=1;i++)
rectangle(150+i,75+i,450-i,375-i);

for(i=0;i<n;i++)
{
fillellipse(xp[i], yp[i], xr, yr);
delay(500);
}
setcolor(YELLOW);
setlinestyle(0,0,2);
//Trasarea dreptei de regresie
line(xp[0],(int)(ay*(xd[0]*a+b)+by),xp[n-1],(int)(ay*(xd[n-1]*a+b)+by));
delay(2000);
//Tiparirea informatiilor pe grafic

settextstyle(4,HORIZ_DIR,1);
outtextxy(270,390,"I (mA)");
settextstyle(1,HORIZ_DIR,3);
outtextxy(150,10,"Regresia liniara");
settextstyle(6,HORIZ_DIR,1);
outtextxy(150,40,"Exemplu: potentiometrul compensator");
settextstyle(4,VERT_DIR,1);
outtextxy(120,270,"U (V)");
settextstyle(8,HORIZ_DIR,1);
outtextxy(460,200,"Functia de fit:");
outtextxy(460,230,"f(x) = ");
gcvt(a,5,stra);
gcvt(b,7,strb);
outtextxy(530,230,stra);
outtextxy(610,230,"x +");
outtextxy(650,230,strb);
gcvt(R2,5,stra);
outtextxy(460,260,"R^2 = ");
outtextxy(530,260,stra);
outtextxy(460,320,"E = ");
outtextxy(500,320,strb);
outtextxy(570,320," V");
outtextxy(460,350,"r = ");
gcvt(-a,5,stra);
outtextxy(500,350,stra);
outtextxy(580,350," ohmi");
setcolor(RED);
rectangle(455,310,650,376);

while(!_kbhit());
closegraph();

return 0;
}
Deviaţia standard (abaterea standard)
= distanţa medie dintre media valorilor unui set de date şi datele setului respectiv
- măsoară împrăştierea datelor dintr-un set (dispersia faţă de medie)
10 10
9 9
8 8
7 7
6 6
5 5
4 4
3 3
2 2
1 1
0 0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

20 valori, media = 5 20 valori, media = 5


10
10
9
9
8
8
7
7
6
6
5
5
4
4
3
3
2
2
1
1
0
0
1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
Formula

 X 
n Numitorul:
2
i X - n-1 dacă datele Xi reprezintă un eşantion
-n dacă datele Xi reprezintă întreaga populaţie
i 1
 (pentru n-mare, n-1n)
n 1

Semnificatie
Eroarea estimarii parametrilor de fit

n n
er _ a  S 2 er _ a  S
n  n  nS xx  S x2
n i 1
x i2  
  xi 
 i 1 

x 2
i
S xx
Sunt necesare minim trei
er _ b  S i 1 er _ b  S puncte pentru aputea
n  n 
2
nS xx  S x2 folosi regresia liniara!
n  x i2  
  xi 

i 1  i 1 

unde:

 a
i 1
 x i  b  y i  2

S
n2
Exemplu
Presupunem că s-au obţinut mai multe valori pentru E şi pentru r, din măsurători repetate.
Rezultatul final se raportează ca şi valoarea medie +/- deviaţia standard.
Analiza reziduurilor

350 80
y = -44.531x + 335.79
R² = 0.8931 Fit liniar
300 60
y = 9.7762x2 - 147.18x + 576.12
250 R² = 0.9936
y = 1049.9e-0.512x 40
R² = 0.9956
200
20
150

100 0
0 2 4 6 8 10 12
50 -20

0
0 2 4 6 8 10 -40
-50

80
60
Fit exponential Fit parabolic
50 60
40
30 40

20
20
10
0 0
-10 0 2 4 6 8 10 12 0 2 4 6 8 10 12
-20 -20
-30
-40
-40
Distribuţia normală (Gaussiană)
Funcţia densităţii de probabilitate (densitatea unei variabile aleatoare continue) este o funcţie care
descrie probabilitatea relativă pentru ca respectiva variabilă sa aibă o anumită valoare.
Probabilitatea ca variabila aleatoare să aibă valori într-un anumit interval este dată de integrala densităţii
variabilei respective pe intervalul dat.
Funcţia densităţii de probabilitate este nenulă pe întreg domeniul său de definiţie, iar integrala sa pe
întreg spaţiul este egală cu unu.
Funcţia densităţii de probabilitate pentru distribuţia 1  ( x   )2 
Gaussiană cu media  şi deviaţia standard  ( x;  , )  exp  
 2  2 2 
 

Distribuţia Gaussiană standard (=0 şi =1) 1  x2 


( x)  exp  

2  2 
CURS 11
Rezolvarea ecuaţiilor transcendente
Fie ecuatia: f(x)=0
algebrică - dacă poate fi adusă la o formă polinomială
transcendentă – dacă nu este algebrică
Ecuaţii algebrice: 3x=9; 2x2-3x+2=0; x5=x(2x-1);
Ecuaţii transcendente: sin(x)+cos(x)=0.5; eln(x)-x=π;

Pentru determinarea soluţiilor ecuaţiilor transcendente este nevoie de metode de aproximare.


Rădăcină unei ecuatii:

Cum se defineste o rădăcină aproximativă?


Pentru determinarea soluţiilor unei ecuaţii de forma f(x)=0 trebuie parcurse două etape:
1. separarea rădăcinilor
- partiţionarea intervalului de definiţie al funcţiei în mai multe subintervale determinate de
nodurile xmin=x1, x2, ... , xM=xmax astfel încât oricare subinterval să conţină cel mult o rădăcină a ecuaţiei

2. calculul rădăcinilor cu o anumită precizie


1. Separarea rădăcinilor
Teorema:
Dacă o funcţie continuă f(x) are valori de semn opus la capetele unui interval [a,b] (dacă f(a)·f(b)<0)
atunci în acel interval se găseşte cel puţin o rădăcină a ecuaţiei f(x)=0.

Rădăcina este unică în intervalul [a,b] dacă derivata funcţiei (f'(x)) există şi îşi păstrează semnul în acel
interval.

O singura radacina in
intervalul [10,15] Nici o radacina in Radacini multiple in
intervalul [-10,-5] intervalul intervalul [0,10]

Dacă subintervalele rezultate în urma partiţionării domeniului de definiţie al funcţiei sau a


domeniului în care se caută zerourile funcţiei, [xm,xm+1], sunt suficient de mici astfel ca
fiecare să conţină cel mult o rădăcină, atunci:
2. Calculul rădăcinilor cu o anumită precizie
Metode:
- metoda bisecţiei (înjumătăţirii intervalului)
- metoda lui Newton (metoda tangentei)
- metoda secantei
- metoda falsei poziţii
-metoda aproximaţiilor succesive
- ...
Metoda bisecţiei
- constă în împărţirea repetată a intervalului iniţial [a,b] în jumătăţi ale acestuia şi selectarea
intervalului (jumătăţii) în care se află soluţia.
Conditia de oprire a procesului iterativ :
Avantaje si dezavantaje
- oferă convergenţă liniară a soluţiei ecuaţiei
- convergenţă lentă
- garantează convergenţa la soluţia exactă dacă valorile f(a) şi f(b) sunt de semne contrare
Program exemplu: metoda bisecţiei
//metoda bisectiei
#include<stdio.h>
#include<math.h>
#include <conio.h>
#include <stdlib.h>
#define eps 1e-8

double f(double x)
{
return 4.5*cos(x/3)*cos(x/3)-x/4;
}

double bisect(double inf, double sup, double (*pf)(double))


{
double c;
if((*pf)(inf)==0) return inf; if((*pf)(sup)==0) return sup; if((*pf)(inf)*(*pf)(sup)>0)
{
printf("\nNu exista sol sau exista solutii multiple");
while(!_kbhit());
exit(1);
}
do {
c=(inf+sup)/2.0;
if((*pf)(c)==0) return c;
if((*pf)(inf)*(*pf)(c)<0)
sup=c;
else
inf=c;
}
while((sup-inf) >= eps); // conditia de oprire
return c;
}

int main()
{
double s;
float A=3.0, B=4;
s=bisect(A,B,f);
printf("\nSolutia este s= %lf\a",s); while(!_kbhit()); return 0;
}
Metoda lui Newton
- propusă de către Isaac Newton în anul 1669
- revăzută de către Joseph Raphson în 1690 si Thomas Simpson în 1740
- una dintre cele mai răspândite metode folosite în acest scop
- algoritmul bazat pe această metodă poate fi folosit şi la determinarea minimului sau
maximului unei funcţii prin determinarea zeroului primei derivate a funcţiei, în metode de
optimizare.
Fie ecuatia: f(x)=0
Conditia de oprire a procesului iterativ :

Calculul soluţiei exacte implică:


1. alegerea unei aproximaţii iniţiale (x0) a soluţiei ecuaţiei f(x)=0
- condiţie necesară şi suficientă: f(x0)f"(x0)>0.
2. calculul derivatei funcţiei al cărui zero se calculează
- calcul numeric (daca nu este posibil analitic)
Deoarece în relaţia iterativă de calcul a rădăcinii valoarea f'(x0) apare la
numitor, în cazul accidental în care derivata funcţiei în punctul xi este zero, se
va alege pentru aceasta valoarea ε (o valoare mică, diferită de zero) folosită la
calculul derivatei sale.
Dezavantajele metodei lui Newton
1. în unele cazuri este necesară o alegere atentă a valorii de start, x0
2. necesită evaluarea a două funcţii.
3. la o iteraţie, se poate determina numai una dintre rădăcinile ecuaţiei cu rădăcini
multiple (depinde de rădăcina aproximativă de "guess" de la care se porneşte)
Calculul numeric al derivatelor
1. Forward differences method (FDM)

2. Central differences method (CDM)


Pentru valori de tip REAL, stocate pe 4 octeţi, p  10-7, iar pentru valori de tip DOUBLE, stocate
pe 8 octeţi, p  10-16.
Vezi cursul 2 – pasul de reprezentare a numerelor reale
simpla precizie: 2-23 = 1.192 x 10-7
dubla precizie: 2-52= 2.22 x 10-16

Conditii pentru alegerea valorii 


if(k>20)
//Metoda Newton {
#include <stdio.h> printf("\nNu converge!");
#include <stdlib.h> exit(1);
#include <math.h> }
#include <conio.h> }
double f(double x) while(x!=x0);
{ printf("\nSolutia ecuatiei este
return 4.5*cos(x/3)*cos(x/3)-x/4; %15.12lf\nNr. de iteratii: %d",x,k);
} return x;
double newton(double (*) (double), double x0) }
{ int main ()
double p=1.0,eps,x,df; {
int k; double x0,x;
//Calculul preciziei masinii si a valorii eps int k;
do printf("Solutia initiala: x0= ");
p=p/2.0; scanf("%lf",&x0);
while(p+1.0!=1.0); newton(f,x0);
eps=pow(p,1/3.0); while(!_kbhit());
printf("p= %.20lf\teps= %.20lf",p,eps); return 0;
//Calculul solutiei }
x=x0;
k=0;
do
{
k++;
x0=x;
//calculul numeric al derivatei prin CDM
df=(f(x+eps)-f(x-eps))/2/eps;
//evitarea cazului in care df este zero
if(df==0)
df=eps;
//actualizarea solutiei
x=x0-f(x)/df;
printf("\nIteratia: %d: x= %15.12lf",k,x);
CURS 12
Integrarea funcţiilor
Metoda trapezelor
- functia de integrat este aproximata liniar
//Metoda trapezelor
#include <stdio.h>
#include <math.h>
float f (float x)
{
return x*x-exp(x);
}
float trapez( float (*p)(float), float a, float b, int n)
{
float h,vint;
int i;
h=(b-a)/(n-1);
vint=((*p)(a)+(*p)(b))/2.0;
for(i=2;i<=n-1;i++)
vint+=(*p)(a+(i-1)*h);
vint=h*vint;
return vint;
}
int main()
{
int n;
float li,ls,v;
printf("Limita inferioara: ");
scanf("%f",&li);
printf("Limita superioara: ");
scanf("%f",&ls);
printf("Nr. puncte de integrare: ");
scanf("%d",&n);
v=trapez(f,li,ls,n);
printf("Valoarea integralei este: %g",v);
// Caz test: Functia: x*x-exp(x) cu limitele a=0, b=2
// valoarea exacta este:
printf("\nCaz test: %f",11.0/3.0-exp(2.0));
while(!_kbhit());
return 0;
}
Metoda Simpson
- functia de integrat este aproximată cu un polinom de gradul 2 (parabolă)
- polinomul aceleaşi valori ca şi f(x) la capetele intervalului de integrare şi în mijlocul acestuia,
adică pentru f(a), f(b) şi pentru f(q), unde q=(a+b)/2.

Trapez Simpson
Cum se calculeaza integrala functiei f?
- se aproximeaza cu integrala polinomului
(1)
(2)
(3)

(2)*4+(3)

Dar:
valoarea integralei se poate calcula evaluând
funcţia f în 3 puncte: 0, h şi 2h.
Nu trebuie determinati coeficientii
polinomului de interpolare!
1. Pentru un interval oarecare [a,b] se împarte
intervalul [a,b] în m intervale şi se aplică formula
fiecărui subinterval [x0,x2], [x2,x4], ...
2. Numărul de intervale m trebuie să fie par pentru
a putea aplica formula parabolei definită de trei
puncte care determină două intervale.

3. In intervalul [x0,x2] se va evalua valoarea funcţiei


în punctele a, a+h şi a+2h, în intervalul [x2,x4] se va
evalua valoarea funcţiei în punctele a+2h, a+3h şi
a+4h, etc.
//Metoda Simpson
#include<stdio.h>
#include<math.h>
#include<conio.h>
double f(double x)
{
return 4.5*cos(x/3)*cos(x/3)-x/4;
}
double simpson(double a, double b, int m, double (*)(double x))
{
double h,s1,s2,I;
int i;
if(a==b) return 0; //cazul a=b
m=2*m; // asigura ca nr. de intervale sa fie par
h=(b-a)/m; // calculul lungimii intervalelor
s1=0.0; Cazuri test pentru metoda Simpson
s2=0.0;
for(i=1;i<=m/2;i++) //calculul celor doua sume m Valoarea integralei
{
s1+=f(a+(2*i-1)*h);
if(i<m/2)
s2+=f(a+2*i*h);
4 11.26644521
} 10 11.26284817
I=(h/3)*(f(a)+f(b)+4*s1+2*s2);
return I; 20 11.26276583
} 40 11.26276074
int main()
{ 100 11.26276041
double a,b,I;
int m;
a=0;
b=10;
printf("\nIntroduceti o valoare (para) pentru numarul de intervale m= ");
scanf("%d",&m);
I=simpson(a,b,m,f);
printf("\n\t I=%12.10f\n",I);
while(!_kbhit());
return 0;
}
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

Rezolvarea sistemelor de ecuaţii liniare

Exemplu
Fie circuitul din figura de mai jos pentru care se dau: R1=1 Ω, R2=2 Ω, R3=3 Ω, E1=8 V,
E2=15 V şi E3=3V. Să se determine curenţii prin cele trei rezistenţe.

Fig.1 Exemplu de reţea electrică de curent continuu

Pentru rezolvarea problemei vom folosi legile lui Kirchhoff. Alegem sensul acelor de ceas
pentru parcurgerea ochiurilor şi obţinem sistemul:
I 2  I1  I3

E1  E 2  R 2 I 2  R 1I1
E  E  R I  R I
 2 3 2 2 3 3

Pentru rezolvarea acestuia şi obţinerea necunoscutelor I1, I2 şi I3 îl vom rearanja sub forma:
I1  I 2  I3 0

R 1I1  R 2 I 2  E 2  E1
 R 2 I 2  R 3I 3  E 2  E 3

Inlocuind valorile rezistenţelor şi tensiunilor electromotoare obţinem:
I1  I2  I3 0

I1  2I 2 7
 2I 2  3I3  12

Pentru eliminarea lui I1 din ecuaţia a doua vom scădea din prima ecuaţie pe cea de-a doua,
iar a doua ecuaţie va deveni rezultatul acestei scăderi. In cea de-a treia ecuaţie I1 lipseşte.
I1  I 2  I3 0

  3I 2  I3  7
 2I 2  3I3  12

Acest lucru este posibil deoarece un system de ecuaţii, B, obţinut dintr-un sistem A are
aceleaşi soluţii ca şi sistemul A dacă schimbarea constă în:
a) interschimbarea a două ecuaţii ale sistemului
b) înmulţirea unei ecuaţii cu o constant nenulă
c) înlocuirea unei ecuaţii cu suma dintre ecuaţia respectivă şi multiplul alteia

1
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

Impărţim a doua ecuaţie cu -3 şi pe cea de-a doua cu 2:



I1  I2  I3 0

 1 7
 I2  I3 
 3 3
 3
 I2  I3 6
2
Pentru eliminarea lui I2 din a treia ecuaţie scădem ecuaţia 3 din 2, iar a treia ecuaţie va fi
rezultatul acestei scăderi:

I1  I2  I3 0

 1 7
 I2  I3 
 3 3
 11 11
  I3  
6 3
Ultima ecuaţie a sistemului permite obţinerea directă a lui I3, iar celelalte două intensităţi se
obţin prin substituţie inversă, a lui I3 în a doua ecuaţie şi apoi a lui I2 şi I3 în prima ecuaţie.
Astfel: I3=2 A, I2=3 A şi I1=1 A.
Aşadar, pentru rezolvarea sistemului, matricea acestuia a fost adusă la o formă (superior)
triunghiulară care a permis determinarea directă a soluţiei ultimei ecuaţii şi apoi obţinerea
celorlalte soluţii prin substituţii inverse.

Metoda de eliminare a lui Gauss


Metoda lui Gauss este una din metode tradiţionale directe de rezolvare a sistemelor de
ecuaţii liniare. Ideea de bază a metodei constă în aducerea sistemului de ecuaţii prin
transformări elementare la o formă echivalentă, având matrice superior sau inferior
triunghiulară, urmată de rezolvarea sistemului rezultat prin procedee recurente specifice,
foarte eficiente.

Transformarea sistemului iniţial într-un sistem de formă triunghiulară se realizează cu


ajutorul a trei operaţii elementare:
a) interschimbarea a două ecuaţii între ele;
b) înmulţirea unei ecuaţii cu o constantă nenulă;
c) scăderea unei ecuaţii din alta şi înlocuirea celei de-a doua ecuaţii cu rezultatul
scăderii.

Transformarea sistemului este echivalentă cu eliminarea succesivă a necunoscutelor din


ecuaţii, prin această operaţie ajungându-se la o matrice triunghiulară a sistemului (faza
eliminării). Rezolvarea sistemului cu matrice triunghiulară constă în determinarea
necunoscutelor şi substituţia lor în ecuaţiile sistemului în ordine inversă, fiind denumită din
acest motiv faza substituţiei inverse.

Fie pentru exemplificare un sistem de trei ecuaţii cu trei necunoscute:

2
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

 a11x1  a12 x2  a13x3  b1



a21x1  a22 x2  a23x3  b2 (1)
a x  a x  a x  b
 31 1 32 2 33 3 3

sau sub formă matricială

 a11 a12 a13   x1   b1 


a a a . x   b 
 21 22 23   2  2
a31 a32 a33   x3  b3 

respectiv:
A · x =b
cu A=[a ij] – matricea sistemului,
x=[xi] – matricea coloană a necunoscutelor
b=[bi] – matricea coloană a termenilor liberi.

Pivotarea parţială
Pentru majoritatea metodelor de rezolvare a sistemelor de ecuaţii liniare - fie ele
directe sau iterative - se ajunge ca la un moment dat să fie necesară împărţirea la un
element diagonal din matricea A, ajj. Acest element poartă numele generic de pivot. Desigur,
dacă acest element este nul metoda respectivă eşuează, deoarece - din punct de vedere
numeric - operaţia de împărţire la 0 este imposibilă şi, dacă nu se iau masuri speciale, orice
program de calcul se întrerupe din execuţie ca urmare a producerii unei erori de tipul "Run
time error", cu un mesaj de eroare de genul "Floating point overflow".
Situaţia extremă în care într-o matrice A poate să apară un element diagonal nul este
cea în care matricea respectivă este singulară (determinantul ei este nul). Pe de altă parte,
pivotul se poate anula fară ca matricea A să fie singulară. Mai mult decât atât, pivotul poate
fi nenul, dar cu o valoare foarte mică, astfel încât împărţirea la el să conducă la producerea
unor erori de rotunjire, care prin acumulare pot denatura rezultatul.
Evitarea unor asemenea situaţii se poate face prin adoptarea unei măsuri care să
permită aducerea pe diagonală a unui element suficient de mare. O asemenea tehnică este
aceea a pivotării care constă în schimbarea între ele a două linii sau a două coloane, astfel
încât noul pivot sa aibă o valoare absolută cât mai mare posibil. Căutarea noului pivot se
face pe coloana curentă j*, pe liniile situate sub linia j*, inclusiv aceasta (pivotarea
partiala) sau pe liniile şi coloanele situate sub linia j* şi la dreapta coloanei j*, inclusiv
acestea (pivotarea completă).
In cazul pivotării parţiale, la un pas j*, se spune ca se executa pivotarea parţială pe
coloana j*. Prin această tehnică se caută pe coloana j* elementul subdiagonal maxim în
valoare absolută şi se schimbă linia j* cu linia in care apare acel element. Deoarece
schimbarea a două linii în matricea A înseamnă de fapt schimbarea ordinii a două ecuaţii din

3
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

sistem, se impune ca - simultan - să se realizeze şi interschimbarea termenilor liberi


corespunzători din vectorul b şi de asemenea, schimbarea semnului determinantului matricii.
În cazul concret al unui sistem de trei ecuaţii cu trei necunoscute, la primul pas al
etapei eliminării urmărim eliminarea necunoscutei x1 din toate ecuaţiile sistemului, cu
excepţia primei ecuaţii. Pentru aceasta, împărţim mai întâi prima linie la elementul pivot a11,
presupus nenul, adică a11 ≠0 (dacă nu este îndeplinită această condiţie se reordonează
ecuaţiile sistemului):
 x1  a12
(1)
x2  a13
(1)
x3  b1(1)

a21x1  a22 x2  a23x3  b2
a x  a x  a x  b
 31 1 32 2 33 3 3

Scădem apoi prima ecuaţie înmulţită cu primul coeficient al celei de-a doua ecuaţii
din a doua ecuaţie şi, respectiv, prima ecuaţie înmulţită cu primul coeficient al celei de-a
treia ecuaţii din cea de-a treia ecuaţie. Obţinem astfel sistemul:

 x1  a12
(1)
x2  a13(1)
x3  b1(1)
 (1)
 a22 x2  a23 x3  b2
(1) (1)

 a (1) x  a (1) x  b (1)


 32 2 33 3 3

unde:
 a1 j
 a (1)
1j  , j  1,2,3
 a11
 b (1)

b1
 1
a11
 (1) (2)
aij  aij  ai1a1 j , j  1,2,3; i  2,3
(1)


 bi(1)  bi  ai1b1(1)

Aşadar, primul pas al metodei eliminării a lui Gauss conduce la ecuaţia matricială:
1 a12
(1) (1) 
a13  x1  b1 
(1)
 (1)     (1) 
. x2   b2 
(1)
0 a22 a23
(3)
0 a (1) a33  x3  b3(1) 
(1) 
 32   

La următorul pas, eliminăm necunoscuta x2 din ultima ecuaţie. Pentru aceasta, împărţim mai
întâi a doua ecuaţie la elementul pivot, a(221) , diferit de zero (dacă nu este aşa, atunci
realizăm interschimbarea ecuaţiilor a doua şi a treia) şi apoi scădem linia obţinută, înmulţită
cu, a(321) , din ecuaţia a treia. Acest al doilea pas conduce la ecuaţia matricială:

4
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

1 a12
(1) (1) 
a13  x1   b1 
(1)
 ( 2)     ( 2) 
0 1 a23 . x 
  2  b2 
(4)
0 0 ( 2) 
a33  x3  b3( 2) 
   

unde:
 a2(1j)
 a2 j 
( 2)
, j  2,3
 a22
 b2(1)
 b2
( 2)
 (1)
 a 22 (5)
aij( 2)  aij(1)  a (1) a ( 2) , j  2,3; i  3
 i2 2 j
 bi  bi(1)  ai(21) b2( 2)
( 2)

Faza eliminării se încheie împărţind cea de a treia ecuaţie la elementul pivot a(332) ,
care, pentru un sistem cu matrice nesingulară (matrice pătratică, cu determinant nenul),
trebuie să fie diferit de zero. Rezultă după acest pas sistemul:
1 a12
(1) (1) 
a13  x1   b1 
(1)
 ( 2)     ( 2) 
0 1 a23 . x 
  2  b2  (6)
0 0 1   x3  b3(3) 
   
cu
b3( 2)
b3(3)  ( 2)
a33

sau matricial A(3) · x =b(3).


Se observă că matricea A(3) este superior triunghiulară, iar sistemul obţinut este
echivalent cu cel iniţial A · x =b, adică are soluţia (x1, x2, x3).
Faza substituţiei inverse (mersul înapoi) presupune parcurgerea în sens invers a ecuaţiilor
sistemului cu matrice triunghiulară (6), rezultat în faza eliminării şi stabilirea soluţiei
sistemului pe baza unui calcul recursiv:
 x3  b3(3)

 x2  b2( 2)  a23( 2)
x3
(7)
 x  b (1)  (a (1) x  a (1) x )
 1 1 12 2 13 3

Aşadar, determinarea soluţiilor se face recursiv, de la indici mari spre indici mici,
fiecare nouă soluţie depinzând în mod explicit numai de soluţiile determinate anterior.

5
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

Determinantul matricii sistemului


Metoda de eliminare Gauss permite şi calcularea determinantului matricii sistemului.
Se observă că, matricea A(3) a sistemului (6) fiind triunghiulară, are determinantul egal cu
produsul elementelor diagonale, adică:
det A(3)=1
Având în vedere, însă, că prin împărţirea liniilor matricii sistemului la elementele pivot rezultă
o matrice a cărui determinant este egal cu determinantul matricii iniţiale împărţit la produsul
elementelor pivot, rezultă:
det A
det A(3)  (1) ( 2)
 1 adica : det A  a11a22
(1) ( 2)
a33
a11a22 a33
Metoda descrisă mai sus poate fi generalizată şi aplicată la rezolvarea unui sistem cu
un număr oarecare de n ecuaţii liniare cu n necunoscute de forma (8):
 a11x1  a12 x2  ...  a1n xn  b1
 a x  a x  ...  a x  b
 21 1 22 2 2n n 2
 (8)
 ......................................
am1 x1  am 2 x2  ...  amn xn  bm
sau sub formă matriceală:
 a11 a12 ... a1n   x1   b1 
a a22 ... a2n   x2   b2 
 21 . 
 ... ... ... ...   ...   ... 
    
am1 am 2 ... amn   xn  bm 

La fiecare pas k al fazei eliminării se efectuează împărţirea liniei pivot k la elementul


diagonal a(kkk 1) . Deoarece este posibil ca un element pivot să fie egal cu zero (ceea ce
conduce la imposibilitatea continuării fazei eliminării), în practică se procedează astfel:
a) se determină elementul maxim al matricii A(k–1) situat pe coloana k şi pe liniile l ≥ k
(pe diagonala principală şi sub ea), adică elementul alk;
b) se aduce elementul maxim alk găsit pe diagonala principală, interschimbând între ele
liniile l şi k.
Relaţiile de calcul al elementelor matricii sistemului şi a matricii termenilor liberi sunt:
aijk  aijk 1  mik 1  akjk 1
cu
aikk 1
mik 1  k 1
akk
respectiv :
bik  bik 1  mik 1  bkk 1
cu: i,j=k+1, ...,n şi k=1,n-1

6
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

Inversa unei matrici


Fie o matrice pătratică A=[aij]. Pentru determinarea inversei acestei matrici se foloseşte
relaţia A·A-1=I unde I este matricea unitate.
Fie matricea inversă

 x11 x12 ... x1n 


x x ... x2 n 
A   21 22
1
 ... ... ... ... 
 
 xn1 xn 2 ... xnn 

Cum A·A-1 trebuie să fie I, obţinem:

a
k 1
ik xkj   ij i, j  1,...,n

Aşadar, pentru determinarea inversei matricii A trebuie rezolvate n sisteme de ecuaţii


care au toate aceeaşi matrice A, fiind diferite doar matricile termenilor liberi. Vectorii coloană
care reprezintă termenii liberi vor fi: {1, 0, ...,0}, {0, 1, 0, ...,0}, ..., respectiv {0, 0, ...,1}.
Cele n2 elemente ale matricii A-1 pot fi determinate folosind metoda Gauss de n ori.

Program exemplu: metoda Gauss


//Program Metoda Gauss

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
#define dm 5

// Constanta dm reprezinta dimensiunea maxima a matricii sistemului


double a[dm][dm],ain[dm][dm],inv[dm][dm],prod[dm][dm];
//a este matricea sistemului
double b[dm],x[dm],det=1.0,dtm; //b este matricea termenilor liberi
int n,opt; //n este dimensiunea actuala a matricii sistemului
FILE *f; //descriptorul fisierului in care se vor scrie toate rezultatele

void stop()
{
printf("\n\n====================================");
printf("\nApasa orice tasta pentru continuare.");
printf("\n====================================");
printf("\n\nRezultatele se gasesc si in fisierul: d:\\gauss.rez");
getch();
}

7
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

void meniu()
//permite selectarea unei optiuni din meniu si apoi calculul corespunzator
{
clrscr();
printf("\n======= M E T O D A G A U S S =================");
printf("\n\nPuteti alege intre:\n\t1) Rezolvarea unui sistem de
ecuatii liniare");
printf("\n\t2) Determinarea inversei unei matrici\n\t3) Calculul
determinantului unei matrici");
do
{
fflush(stdin);
gotoxy(1,9);
printf("Optiunea: ");
gotoxy(12,9);
scanf("%d",&opt);
}
while(((opt!=1)&&(opt!=2))&&(opt!=3));
}

void verif()
//verifica inversarea matricii prin inmultirea acesteia cu inversa ei
//rezultatul trebuie sa fie matricea unitate
{
int i,j,k;
printf("\nVerificarea inversarii: AxA^-1");
fprintf(f,"\n\nVerificarea inversarii: AxA^-1\n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
prod[i][j]=0;
for(k=0;k<n;k++)
prod[i][j]+=ain[i][k]*inv[k][j];
}
for(i=0;i<n;i++)
{
printf("\n\t\t");
fprintf(f,"\n\t\t");
for(j=0;j<n;j++)
{
if(fabs(prod[i][j])<1e-8)
prod[i][j]=0;
printf("%g\t",prod[i][j]);
fprintf(f,"%g\t",prod[i][j]);
}
}
}

void solutii()
//calculeaza solutiile sistemului liniar
{

8
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

int i,j;
double suma;

x[n-1]=b[n-1]/a[n-1][n-1];
for (j=n-2;j>=0;j--)
{
suma=0;
for(i=j+1;i<n;i++)
suma+=a[j][i]*x[i];
x[j]=(b[j]-suma)/a[j][j];

}
}

void tip_sol()
//tipareste solutiile sistemului
{
int i;
for(i=0;i<n;i++)
{
printf("\nx[%d]=%10.5lf",i,x[i]);
fprintf(f,"\nx[%d]=%10.5lf",i,x[i]);
}
}

void citire_mat()
//citeste matricea de intrare
{
int i,j;
gotoxy(1,10);
printf("Ordinul matricii sistemului: ");
scanf("%d",&n);
gotoxy(1,11);
printf("Matricea sistemului: ");
fprintf(f,"Matricea sistemului: \n");
for(i=0;i<n;i++)
{
fprintf(f,"\n");
for(j=0;j<n;j++)
{
gotoxy(7*j+1,i+12);
scanf("%lf",&a[i][j]);
ain[i][j]=a[i][j];
fprintf(f,"%10.5lf",a[i][j]);
}
}
}

void citire_tl()
{
//citeste matricea termenilor liberi

9
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

int i;
fprintf(f,"\nTermenii liberi:\n");
for(i=0;i<n;i++)
{
gotoxy(7*n+1,i+12);
scanf("%lf",&b[i]);
fprintf(f,"%10.5lf",b[i]);
}
}

double gauss(double a[dm][dm])


{
//realizeaza eliminarea Gaussiana

double t,m;
int i,j,k,l;

for(i=0;i<n;i++) //este necesar cand functia gauss() este


//apelata in functia matinv
for(j=0;j<n;j++) //altfel, la orice alt apel in afara celui
//initial matricea a ar fi
a[i][j]=ain[i][j]; //una modificata in urma
//transformarilor de la apelurile anterioare

//Se cauta elementul pivot


//de fapt linia care are in coloana k cel mai mare element

for(k=0;k<n;k++)
{
l=k; // l este indexul liniei pivot
//elementul pivot se cauta pe coloana k, in liniile aflate sub linia k
for (i=k+1;i<n;i++)
if (fabs(a[i][k])>fabs(a[k][k]))
l=i;
//Daca elementul pivot este intr-o alta linie decat cea curenta
// atunci se interschimba linia curenta cu cea in care se afla elem. pivot
if(l!=k)
{
for(j=0;j<n;j++)
{
t=a[k][j];a[k][j]=a[l][j];a[l][j]=t;
}
t=b[k];b[k]=b[l];b[l]=t;
det*=-1;
}

//Se calculeaza elementele matricii la eliminarea k


for(i=k+1;i<n;i++)
{
m=a[i][k]/a[k][k];
a[i][k]=0;

10
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

for(j=k+1;j<n;j++)
a[i][j]=a[i][j]-m*a[k][j];
b[i]=b[i]-m*b[k];
}

}
//Se calculeaza determinantul matricii
for(i=0;i<n;i++)
det*=a[i][i];
dtm=det;
return dtm;
}

matinv()
//calculeaza inversa matricii
{
int p,j,i,k;
double t[dm];

for(p=0;p<n;p++)
{
for(j=0;j<n;j++)

if(j==p)
b[j]=1;
else
b[j]=0;

gauss(a);
solutii();
for(k=0;k<n;k++)
inv[k][p]=x[k];

}
printf("\nMatricea inversa este:");
fprintf(f,"\n\nMatricea inversa este:\n");
for(i=0;i<n;i++)
{
printf("\n");
fprintf(f,"\n");
for(j=0;j<n;j++)
{
printf(" %10.5lf",inv[i][j]);
fprintf(f," %10.5lf",inv[i][j]);
}
}
return 0;
}

//========================================================

11
Curs 13 Rezolvarea sistemelor de ecuaţii liniare

void main()
{
double x[10],det,suma;
int i,j,k;

f=fopen("d:\\gauss.rez","w");
meniu();
if(opt==1)
{
citire_mat();
citire_tl();
gauss(a);
solutii();
tip_sol();
stop();
}
else
if(opt==2)
{
citire_mat();
matinv();
verif();
stop();
}
else
{
citire_mat();
gauss(a);
printf("\nDeterminantul matricii este: %lg",dtm);
fprintf(f,"\n\nDeterminantul matricii este: %lg",dtm);
stop();
}
fclose(f);
}

Pentru testarea programului folosiţi exemplul prezentat la începutul acestui curs.

Diagonalizarea matricilor

12

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