Documente Academic
Documente Profesional
Documente Cultură
De ce nu C++? http://www-pnp.physics.ox.ac.uk/~tseng/teaching/lab/handbook_C.pdf
Syllabus
FLR1304
Link-uri utile
Functii matematice: http://en.wikipedia.org/wiki/C_mathematical_functions
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).
Mbps (Mb) – unitatea de masura pentru viteza de transmisie (download si upload) in internet
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
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
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.
•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)
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ă.
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.19210-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ă.
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
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
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.
Funcţii recursive
- functii care se autoapelează
- se folosesc la definirea proceselor recursive.
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;
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 );
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.
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.
This should not be confused with the size of the array that holds the
string. For example:
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 .
Exemple:
printf("\nSuma celor %d numere este %g\t\a“,n,s);
Sem I Sem II
1: 8.75 5.25
2: 10.00 10.00
3: 5.30 6.67
...................................................
2. Sectiunea de declaratii
a) variabile
b) tipuri utilizator
c) functii
....
3. Functia principala
int main()
{
...
return 0;
}
- 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“
#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).
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
....
3. Functia principala
int main()
{
...
return 0;
}
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.
În plus, există câţiva calificatori care pot fi aplicaţi acestor tipuri de bază:
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:
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;
}
while(--val>1)
rez*=val;
return rez;
}
int decidebisect(...)
{
int i;
.....
i=(an%4==0 && an%100!=0)an%400==0);
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.
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.
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
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 %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 %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:
Clase de operatori
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.
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
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);
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.
#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
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>
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: ...
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
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.
//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:
//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:
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;
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
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];
};
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;
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
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.
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
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);
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.
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
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);
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ă.
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
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;
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;
};
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
Cazuri:
i 1
= regresie (ajustare) prin metoda celor mai mici pătrate
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
b nb
i 1
Sistemul de ecuaţii devine:
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
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("===================================================\n");
printf("n= %d",n);
for(i=0;i<n;i++)
printf("\n%10.2f\t%10.2f",xd[i],yd[i]);
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
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-1n)
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
n2
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
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]
double f(double x)
{
return 4.5*cos(x/3)*cos(x/3)-x/4;
}
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 :
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.
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.
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
2
Curs 13 Rezolvarea sistemelor de ecuaţii liniare
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
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)
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
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
6
Curs 13 Rezolvarea sistemelor de ecuaţii liniare
a
k 1
ik xkj ij i, j 1,...,n
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<conio.h>
#define dm 5
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 t,m;
int i,j,k,l;
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;
}
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);
}
Diagonalizarea matricilor
12