Sunteți pe pagina 1din 31

Limbajul C cu aplicații în analiza numerică – Elemente generale ale limbajului C

Lucrarea nr. 2

ELEMENTE GENERALE ALE LIMBAJULUI C

1. Scopul lucrării
Lucrarea are ca scop prezentarea elementelor de bază ale limbajului C.

2. Noţiuni teoretice

2.1 Structura programelor


Orice activitate de programare începe cu editarea În cadrul programelor C este obligatorie declararea
programului, în conformitate cu regulile sintactice şi variabilelor, care constă în precizarea tipului variabilei.
semantice aferente limbajului. Se elaborează astfel aşa- În urma declaraţiei, variabila determină compilatorul
numitul „program sursă", care se păstrează într-un să-i aloce un spaţiu corespunzător de memorie.
fişier (fişier sursă) sau mai multe. Aceste fişiere au În limbajul C există cinci tipuri de variabile:
extensia .c pentru limbajul C şi .cpp pentru limbajul - caracter: char,
C++. - întreg: int,
Pentru a putea fi executat, programul trebuie să - real în virgula mobilă în simplă precizie: float,
parcurgă o serie de etape: - real în virgula mobilă în dublă precizie: double şi
- etapa de compilare care presupune rezolvarea - tip de variabilă neprecizat sau inexistent: void
directivelor către preprocesor şi transpunerea Primele 4 tipuri aritmetice de bază pot fi extinse cu
programului sursă în „program obiect" (prin ajutorul unor declaraţii suplimentare, cum ar fi:
compilarea unui fişier sursă se obţine un fişier obiect cu - signed (cu semn)
extensia .obj): - unsigned (fără semn)
- etapa de link-editare care presupune legarea - long (lung)
programului obiect obţinut cu bibliotecile de sistem; - short (scurt).
rezultă un „program executabil” (în urma link-editării Un exemplu de set de tipuri de variabile obţinut cu
se obţine un fişier executabil cu extensia .exe) ajutorul acestor declaraţii este prezentat în Tab.1.
- etapa de lansare în execuţie. Exemple de declaraţii de variabile:
Un program sursă este compus din una sau mai …int i, j, k;
multe funcţii dintre care una singură trebuie numită double val, set;
main(). unsigned int m;
Exemplul următor conţine o singură funcţie, funcţia
main(). Către această funcţie principală sistemul de Programul următor utilizează declaraţii multiple de
operare transferă controlul la lansarea în execuţie a variabile:
programului.
Ex. 1 Ex. 2
#include<stdio.h> #include<stdio.h>
main() main()
{ {
printf ("Program in limbajul C!"); int nr;
} char ev;
Dacă sunt parcurse în mod corect etapele de float timp;
compilare şi link-editare ale programului, la lansarea lui nr=5;
în execuţie va apare mesajul: ev = 'S';
Program in limbajul C! timp = 11.30;
Acoladele { } încadrează o construcţie (instrucţiune printf("Evenimentul %c are numărul %d ", ev, nr);
compusă sau bloc) alcătuită din declaraţii şi printf("si a avut loc la %f", timp);
instrucţiuni aşa cum este cazul corpului unei funcţii. }

2.2 Variabile. Tipuri de variabile. Declarare În urma execuţiei acestui program se va afişa:
Limbajul C permite utilizarea de variabile (nume
simbolice) pentru memorarea datelor, calculelor sau Evenimentul S are numărul 5 şi a avut loc la
rezultatelor. 11.300000

1
Limbajul C cu aplicații în analiza numerică – Elemente generale ale limbajului C

Tab.1 Tipuri de variabile în limbajul C


Tip Spaţiul Domeniul de valori
(biţi)
char 8 - 128÷127
unsigned char 8 0÷255
signed char 8 -128 ÷127
int 16 - 32768÷32767
unsigned int 16 0÷65535
signed int 16 - 32768 ÷ 32767
short int 16 - 32768÷32767
unsigned short int 16 0÷65535
signed short int 16 - 32768÷32767
long int 32 -2.147.483.648 ÷ 2.147.483.647
signed long int 32 -2.147.483.648 ÷ 2.147.483.617
unsigned long int 32 0÷4.294.967.295
float 32 10 ÷1037 (6 digiti precizie)
-37

double 64 10-308 ÷10308 (10 digiti precizie)


long double 80 10-4932 ÷104932 (15 digiti precizie)

2.3 Funcţia printf( )


Funcţia printf() permite afişarea textului aflat între l cu f, e, g — permite afişarea unei date de tip double
ghilimele precum şi valori ale diferitelor variabile din h cu d, i, u, x, o — permite afişarea unei date de tip
program, utilizând anumite notaţii denumite short
specificatori de format care realizează conversia datelor L cu f, e, g — permite afişarea unei date de tip long
într-o formă adecvată pentru afişare. double.
Prototipul funcţiei printf() se găseşte în fişierul antet Exemple:
stdio.h şi de aceea este nevoie de declaraţia %ld - permite afişarea unei date de tip long int
preprocesor: #include<stdio.h> la începutul fiecărui %hu - permite afişarea unei date de tip short unsigned
program care foloseşte această funcţie. int
Formatele specifice utilizate de funcţia printf() sunt: În exemplul 2 afişarea valorii reale s-a realizat cu
%c — pentru afişarea unui singur caracter; şase zecimale şi nu cu două conform operaţiei de
%s — pentru afişarea unui şir de caractere; atribuire iniţiale a acestei variabile. Pentru afişarea
%d — pentru afişarea unui număr întreg (în baza zece) corectă, formatul de scriere %f trebuie însoţit de o
cu semn; notaţie suplimentară care specifică dimensiunea
%i — pentru afişarea unui număr întreg (în baza zece) câmpului de afişare a datelor şi precizia de afişare a
cu semn ; acestora. Această notaţie suplimentară se introduce între
%u — pentru afişarea unui număr întreg (în baza zece) simbolul % şi simbolul f şi are forma generală
fără semn; %-m.nf cu m şi n numere întregi având următoarele
%f — pentru afişarea unui număr real (notaţie semnificaţii:
zecimală); semnul “-“, în cazul în care este folosit,
%e — pentru afişarea unui număr real (notaţie realizează alinierea la stânga a informaţiei
exponenţială); afişate în cadrul câmpului de afişare; în lipsa
%g — pentru afişarea unui număr real (cea mai scurtă acestuia, implicit alinierea se face la dreapta.
reprezentare dintre %f si %e); m precizează dimensiunea câmpului de afişare
%x — pentru afişarea unui număr hexazecimal întreg (numărul de coloane)
fără semn; .n reprezintă numărul de digiţi din partea
%o — pentru afişarea unui număr octal întreg fără zecimală (precizia de afişare a numărului)
semn Astfel, în exemplul 2, dacă în locul specificaţiei de
%p — pentru afişarea unui pointer (a unei adrese); format %f am fi trecut %5.2f, la consolă ar fi apărut
În plus se pot folosi următoarele prefixe: mesajul:
l cu d, i, u, x, o permite afişarea unei date de tip long Evenimentul S are numărul 5 şi a avut loc la 11.30

2
Limbajul C cu aplicații în analiza numerică – Elemente generale ale limbajului C
cu printf(), apelul funcţiei scanf() implică utilizarea
Ex. 3 unui şir de caractere de control urmate de o listă de
#include<stdio.h> argumente. Dar, în timp ce printf() utilizează nume de
main() variabile, constante şi expresii, scanf() utilizează
{ pointeri la variabile.
float valoare; Exemplul 4 este o variantă a programului din
valoare = 20.13301; exemplul 2 în care, în plus, se utilizează funcţia scanf().
printf ("%8.1f%8.1f\n”, 22.5,425.7);
printf ("% -8.1f % -8.1f\n.", 22.5,425.7); Ex. 4
printf ("%f\n",valoare); #include<stdio.h>
printf ("%5.2f\n", valoare); main()
printf (" %012f\n", valoare) ; {
printf ("%10f\n”, valoare); int nr;
} char ev;
În urma executării programului din ex.3, va rezulta: float timp;
printf ("Introduceţi pozitia, evenimentul, timp:");
2 2 . 5 4 2 5 . 7 scanf ("%c %d %f", &ev, &nr, &timp);
2 2 . 5 4 2 5 . 7 printf ("Evenimentul %c are numărul %d ", ev, nr);
2 0 . 1 3 3 0 1 1 printf (" şi a avut loc la %5.2f", timp);
2 0 . 1 3 }
2 0 . 1 3
0 0 0 2 0 . 1 3 3 0 1 1 Execuţia programului poate fi:
2 0 . 1 3 3 0 1 1 Introduceţi pozitia, evenimentul şi timpul: A 6 11.30
Evenimentul A are numărul 6 şi a avut loc la 11.30
Se observă că prezenţa unui zero înaintea numărului
care specifică dimensiunea câmpului de scriere Valorile variabilelor ev, nr şi timp au fost introduse
determină la afişare umplerea cu zero a spaţiilor goale. de la tastatură. Pentru separarea lor a fost utilizat spaţiu
(blank). Putea fi folosit return sau tab; orice alt
2.4. Secvenţe de evitare (escape) separator (linie, virgula) nu realizează această separare.
În exemplul 3, caracterul "\n" inserat în şirul de
caractere din apelul funcţiei printf() a determinat 3. Problemă rezolvată
afişarea pe o linie nouă (carriage return-linefeed).
Acest caracter este un exemplu de secvenţă escape, 3.1 Să se scrie un program care permite aflarea
numită aşa deoarece simbolul (\) backslash este codului numeric al unei taste în zecimal, hexa si octal.
considerat caracter escape, care determină o abatere de
la interpretarea normală a şirului. Aceste secvenţe #include<stdio.h>
escape sunt: #include<conio.h>
\a beep alarmă-sonoră; void main(void)
\b backspace spaţiu înapoi; {char caracter;
\f formfeed linie nouă, dar pe coloana următoare clrscr();
celei curente; printf("Acest program afiseaza codul unei taste in
\n newline determină trecerea la linie nouă, pe zecimal, hexa si octal.\n");
prima coloană; printf("Apasati o tasta:");
\r carriage return determină revenirea la începutul scanf("%c",&caracter);
liniei; printf("Codul tastei \”%c\” este %d (in decimal),
\t tab determină saltul cursorului din 8 in 8 coloane; %x (in hexa), %o (in octal)\n", caracter, caracter,
\\ backslash ; caracter, caracter);
\' apostrof simplu; getch();
\" ghilimele; }
\0 null ;
\ddd valoare caracter în notaţie octală 4. Chestiuni de studiat
(fiecare d reprezintă un digit); 4.1 Studierea noţiunilor teoretice şi a exemplelor
\xdd valoare caracter în notaţie hexazecimală; prezentate.
4.2 Studierea problemelor rezolvate şi identificarea
2.5. Funcţia scanf() elementelor de limbaj şi a algoritmilor utilizaţi.
O altă funcţie des utilizată a limbajului C este
funcţia de introducere a datelor scanf(). În mod similar

3
Limbajul C cu aplicații în analiza numerică – Pointeri în limbajul C

Lucrarea nr. 3

POINTERI ÎN LIMBAJUL C

1. Scopul lucrării
Lucrarea are ca scop prezentarea utilizării variabilelor pointer în limbajul C.

2. Noţiuni teoretice

2.1 Declararea variabilelor pointer

Variabilele pointer (indicator) reprezintă adrese În această secvenţă de program, variabila iptr
ale unor zone de memorie. Pointerii sunt utilizaţi este un pointer de obiecte int, iar variabila fptr un
pentru a face referire la date cunoscute, prin pointer de obiecte float. Tot aici, tabptr este un
adresele lor. Puterea şi flexibilitate în utilizarea tablou de 10 pointeri de tip int, iar dptr va putea
pointerilor, specifică limbajului C, reprezintă un conţine adresa unui pointer de obiecte float (se
avantaj faţă de celelalte limbaje (de ex. Pascal). realizează o dublă indirectare, pointer la pointer).
Există 2 categorii de pointeri: Deoarece, la compilare sau în timpul execuţiei
pointeri de date (obiecte) care conţin adrese programului nu se fac verificări ale validităţii
ale unor variabile sau constante din valorilor pointerilor, orice variabilă pointer trebuie
memorie; iniţializată cu o valoare validă, 0 sau adresa unui
pointeri de funcţii care conţin adresa obiect sau a unei funcţii, înainte de a fi utilizată.
codului executabil al unei funcţii. Iniţializarea cu valoarea 0 a unei variabile
În plus, există şi pointeri de tip void (o a treia pointer indică faptul ca aceasta nu conţine adresa
categorie), care pot conţine adresa unui obiect unui obiect sau a unei funcţii. Uzual, în aceste
oarecare. cazuri, se foloseşte pentru atribuire identificatorul
Declararea unui pointer de date se face cu NULL(=0), care este declarat în fişierele antet
sintaxa: (stdio.h, stdlib.h etc.).
tip *var_ptr; Utilizarea variabilelor pointer implică folosirea
a doi operatori unari: operatorul & ce permite
Prezenţa caracterului * defineşte variabila aflarea adresei unei variabile oarecare şi
var_ptr ca fiind de tip pointer, în timp ce tip este operatorul * care permite accesul la variabila
tipul obiectelor a căror adresă o va conţine (numit adresată de un pointer.
şi tipul de bază al variabilei pointer var_ptr). Astfel, în cazul unei variabile var de tipul tip,
Pentru pointerii de tip void se foloseşte expresia:
declaraţia: &var se citeşte: “adresa variabilei var”
void * v_ptr; iar rezultatul este un pointer de obiecte tip şi are
valoarea adresei obiectului var.
Exemplul următor conţine un set de declaraţii În cazul unei variabile pointer de obiecte tip,
de variabile pointer: numită ptr, expresia:
Ex.1: *ptr se citeşte: “la adresa ptr”
iar rezultatul este de tipul tip şi reprezintă obiectul
int *iptr; adresat de variabila pointer ptr. Expresia *ptr
float *fptr, val; poate fi utilizată atât pentru a aflarea valorii
void *v_adr; obiectului, dar şi în cadrul unei operaţii de
int * tabptr [10]; atribuire.
float ** dptr;

1
Limbajul C cu aplicații în analiza numerică – Pointeri în limbajul C
Utilizarea acestor operatori este prezentată în if(ptr1<ptr2)
exemplul următor, în care, pentru afişarea adreselor printf(“ptr1=%p <ptr2=%p”,ptr1,ptr2);
în hexazecimal se foloseşte funcţia printf() ………………
împreună cu specificatorul de format %p: În multe situaţii este necesară compararea unui
pointer cu 0, pentru a verifica dacă adresează sau
Ex.2: nu un obiect:
#include <stdio.h> …………..
void main(void) if(ptr1==NULL)…/* ptr1 este un pointer nul*/
{ else… /* ptr1 este un pointer nenul*/
int var=5, *ptr; …………..
printf(“\n Variabila var se află la adresa:%p”, sau, sub forma:
&var); ………
printf(“\n şi are valoarea var=%d”,var); if(!ptr1)… /* ptr1 este un pointer nul*/
ptr=&var; else … /* ptr1 este un pointer nenul*/
printf(“\n Variabila ptr are valoarea:%p”, ptr); …………
printf(“\n şi conţine adresa obiectului: %d”,*ptr); Pot fi efectuate operaţii de adunare sau de
*ptr=10; scădere între un pointer de obiecte şi un întreg.
printf(“\nAcum, variabila var are valoarea Deoarece un pointer este o valoare care indică o
%d\n”,var); anumită locaţie din memorie, dacă adăugăm
} numărul 1 acestei valori, pointerul va indica
următoarea locaţie din memorie. Deci, în cadrul
În urma execuţiei programului se afişează: acestor operaţii intervine şi tipul variabilei.
Regula după care se efectuează aceste operaţii
Variabila var se află la adresa: 1A56 este următoarea:
şi are valoarea var=5 în cazul unei variabile pointer ptr:
Variabila ptr are valoarea: 1A56 tip *ptr;
şi conţine adresa obiectului: 5 operaţiile aritmetice:
Acum, variabila var are valoarea 10 ptr+n şi ptr-n
corespund adăugării/scăderii la adresa ptr a valorii
În urma operaţiei de atribuire ptr=&var, n*sizeof(tip).
variabila pointer ptr preia adresa variabilei var,
astfel încât cele două obiecte *iptr şi var devin De exemplu:
identice, reprezentând un întreg cu valoarea 5 de la ……………..
adresa 1A56. În aceste condiţii, expresia *ptr int *ip; /* sizeof(int)=2 */
poate fi folosită în locul variabilei var, cu efecte float *fp; /* sizeof(float)=4 */
identice. De aceea, atribuirea *ptr=10 are ca efect double *dp1, *dp2; /* sizeof(double)=8 */
modificarea valorii variabilei var din 5 în 10. ………….
dp2=dp1+5; /* dp2<-- adresa_dp1+5*8 */
2.2 Operaţii arimetice cu pointeri fp=fp-2; /* fp<-- adresa_fp-2*4 */
ip++; /* ip<-- adresa_ip+1*2 */
Operaţiile aritmetice ce se pot efectua cu dp1--; /* dp<-- adresa_dp-1*8 */
pointeri sunt: compararea, adunarea şi scăderea.
Aceste operaţii sunt supuse unor reguli şi restricţii În acelaşi context, se poate efectua scăderea a
specifice. În cazul în care tipurile asociate doi pointeri de obiecte de acelaşi tip, având ca
operanzilor pointer nu sunt identice, pot apare rezultat o valoare întreagă ce reprezintă raportul
erori, care nu sunt întotdeauna semnalate de dintre diferenţa celor două adrese şi dimensiunea
compilator. În acest sens, se recomandă conversia tipului de bază, ca în exemplul:
de tip explicită cu operatorul cast, de forma (tip*).
Operatorii relaţionali permit compararea int i;
valorilor a doi pointeri: float *fp1,*fp2; /*sizeof(float)=4*/
……….. i=fp2-fp1;
int *ptr1,*ptr2; /*i=(adresa_fp2-adresa_fp1)/sizeof(float)*/

2
Limbajul C cu aplicații în analiza numerică – Pointeri în limbajul C
Având în vedere importanţa tipului pointerilor void free(void*ptr);
în cadrul operaţiilor de adunare şi scădere,
operanzii nu pot fi pointeri de funcţii sau pointeri Parametrul funcţiei free() este un pointer ce
void. conţine adresa zonei care trebuie eliberată şi care
obligatoriu este rezultatul unui apel al unei funcţii
2.3 Variabile dinamice de alocare dinamică (de tip malloc()).
Astfel, zona alocată anterior poate fi eliberată
Pentru tipurile de date la care se cunoaşte prin apelul:
dimensiunea zonei de memorie necesară, aceasta …………….
este fixată în urma declaraţiei, înaintea lansării în free(fp);
execuţie a programului. ……………….
În cazul structurilor de date a căror dimensiune Zona de memorie alocată astfel este echivalentă
nu este cunoscută sau se modifică în timpul cu un tablou. Elementele acestuia pot fi referite
execuţiei programului, este necesară o alocare prin indexat. De exemplu fp[5] este obiectul float de la
program a memoriei, în timpul execuţiei. Memoria adresa fp+5.
alocată este folosită, iar atunci când nu mai este
utilă, se eliberează tot în timpul execuţiei 3. Problemă rezolvată
programului. 3.1 Acest program exemplifică regulile specifice
Variabilele create astfel se numesc dinamice. operaţiilor aritmetice cu pointeri.
Prototipurile funcţiilor utilizate pentru alocarea
şi eliberarea memoriei în timpul execuţiei #include <stdio.h>
programului se află în fişierele alloc.h şi stdlib.h. void main(void)
O funcţie des utilizată pentru alocarea dinamică {
a memoriei este malloc() şi are prototipul: int a=5,b=10, *iptr1, *iptr2,i;
float m=7.3, *fptr;
void*malloc(unsigned nr_octeţi); iptr1=&a;iptr2=&b;
fptr=&m;
Prin parametrul funcţiei malloc() se precizează printf("\n fptr=%u, *fptr=%2.1f, &fptr=%u", fptr,
dimensiunea în octeţi a zonei de memorie *fptr, &fptr);
solicitate. Dacă operaţia de alocare reuşeşte, fptr++;printf("\n Incrementare fptr:");
funcţia întoarce un pointer care conţine adresa printf("\n fptr=%u, *fptr=%2.1f, &fptr=%u", fptr,
primului octet al zonei de memorie alocate. În caz *fptr, &fptr);
contrar (spaţiul disponibil este insuficient) printf("\n iptr1=%u, *iptr1=%d, iptr2=%u,
pointerul rezultat este NULL (=0). *iptr2=%d", iptr1, *iptr1, iptr2,*iptr2);
Pentru o bună portabilitate a programelor, este i=iptr1-iptr2;
recomandabil, în apelul funcţiei malloc(), să se printf("\n Diferenta pointerilor iptr1 si iptr2
utilizeze operatorii cast (pentru conversie de tip la este=%d",i);
atribuire) şi sizeof (pentru precizarea dimensiunii iptr2=iptr1+8;
zonei solicitate). printf("\n iptr1=%u, *iptr1=%d, iptr2=%u,
De exemplu, dacă se doreşte alocarea unei zone *iptr2=%d", iptr1, *iptr1,iptr2,*iptr2);
de memorie pentru 10 valori de tipul float, se poate }
proceda astfel:
…………. 4. Chestiuni de studiat
float *fp; 4.1 Studierea şi însuşirea noţiunilor teoretice şi
fp=(float*)malloc(10*sizeof(float)); a exemplelor prezentate.
…………. 4.2 Identificarea elementelor de limbaj şi a
Eliberarea memoriei (rezultate în urma unei algoritmilor utilizaţi.
alocări dinamice) se face atunci când variabila
dinamică nu mai este utilă, iar spaţiul alocat poate
fi refolosit. În acest caz se poate folosi funcţia
free() care are prototipul:

3
Limbajul C cu aplicații în analiza numerică – Tablouri şi pointeri în limbajul C

Lucrarea nr. 4

TABLOURI ŞI POINTERI ÎN LIMBAJUL C

1. Scopul lucrării
Lucrarea are ca scop prezentarea legăturii dintre tablouri şi pointeri în limbajul C

2. Noţiuni teoretice Astfel, în fişierul stdio.h sunt declarate:


- funcţia gets(sir_dest) care citeşte caractere
2.1 Tablouri şi şiruri de caractere introduse de la tastatura şi le transferă în şirul
sir_dest şi
Un tablou este o structură omogenă, formată - funcţia puts(sir) care afişează şirul şir pe
dintr-un număr finit de elemente de acelaşi tip ecran ,
denumit tipul de bază al tabloului. Sintaxa de bază iar, în fişierul string.h, se găsesc câteva funcţii ce
în declararea unui tablou este: realizează operaţii uzuale cu şiruri, cum ar fi:
- funcţia strcpy(sir_dest,sir_sursa) care
tip nume_tablou[nr_elem]={val_initiala….}; copiază şirul sir_sursa în şirul sir_dest,
- funcţia strcat(sir1, sir2) care adaugă şirul sir2
De exemplu: la sfârşitul şirului sir1 (concatenare) şi
- funcţia strlen(sir) care returnează numărul de
int tab[5]={5,4,3,2,1}; elemente al şirului sir.
- funcţia strcmp(sir1,sir2) care compară
defineşte un tablou de 5 valori de tip int şi succesiv caracterele celor 2 şiruri. Dacă şirurile
realizează iniţializarea acestuia cu valorile din sunt identice returnează valoarea 0, iar dacă diferă,
interiorul acoladelor. o valoare nenulă.
Pentru identificarea unui element al unui tablou
se foloseşte numele tabloului şi indexul (poziţia Utilizare acestor funcţii este prezentată în
elementului în tablou). Valorile pe care le poate lua exemplul următor, care testează introducerea
indexul pleacă de la 0, ultimul element având parolei corecte “next”:
indexul nr_elem-1:
Astfel, în exemplul precedent, tab[0] este #include <stdio.h>
primul element al tabloului şi are valoarea 5. #include <string.h>
Limbajul C nu are un tip de date special pentru #include<process.h>
şiruri de caractere, dar permite folosirea tablourilor void main(void) {
unidimensionale de tip caracter (char). Sintaxa de char sir[20], parola[10];
declarare este: strcpy(parola,”next”);
puts(“Introduceti parola:”);
char nume_sir [nr_elem]; gets(sir);
if (strcmp(sir, parola)) {
Pentru a marca sfârşitul unui şir cu n elemente, puts(“Incorect”);
după ultimul caracter, compilatorul rezervă n+1 exit(1); /*iesire din program */
locaţii de memorie, pe ultima poziţie adăugând un }
octet cu valoarea 0 (caracterul ‘\0’). Astfel, acest else puts(“Corect!”);
terminator ‘\0’ permite testarea sfârşitului şirului. /*…si se poate executa in continuare programul
În biblioteca limbajului C există un set de */
funcţii dedicate operaţiilor cu şiruri. }

1
Limbajul C cu aplicații în analiza numerică – Tablouri şi pointeri în limbajul C

În cazul tablourilor unidimensionale, se poate În exemplul:


omite dimensiunea la declaraţie. În această situaţie, ……………..
dimensiunea zonei de memorie alocate este fixată float fmat [10][10];
de compilator pe baza listei de constante utilizate la float *fp;
iniţializare. fp=mat;
În cazul tablourilor mari, nu mai este necesară …………………..
numărarea elementelor, ca în declaraţia: atribuirea fp=mat; este incorectă, deoarece mat
este pointer de tablouri float cu 10 elemente şi nu
char sir[]=”Nu mai este nevoie de dimensiunea un pointer float.
sirului”; Astfel, mat referă prima linie a matricii
identificată prin mat[0], iar mat[0] referă primul
2.2 Tablouri şi pointeri element al matricii mat[0][0]. Pot fi scrise
echivalenţele:
Numele unui tablou fără index este echivalent
cu un pointer constant de tipul elementelor 1. &mat[0] <= => mat
tabloului, având ca valoare adresa primului 2. &mat[0][0] <= => mat[0]
element din tablou. Totuşi, în timp ce unei 3. mat[0][0] <= => *mat[0] <= => **mat
variabile de tip pointer i se atribuie valori la 4. *(mat+i) <= => mat[i] <= =>&mat[i][0]
execuţie, nu este posibil şi pentru numele unui 5. *(*(mat+1)+5)<==>*(mat[1]+5)<==>mat[1][5]
tablou, care va avea mereu ca valoare adresa
primului element. De aceea se spune că numele În general este valabilă echivalenţa:
unui tablou este un pointer constant. mat[i][j] <= =>*(*(mat+i)+j)
De exemplu, după declaraţiile:
…………..
float ftab[10],*fptr; 3. Probleme rezolvate
int i;
…………. 3.1 Acest program încarcă tabloul t1 cu
se poate face atribuirea: numerele 1….10 şi apoi copiază conţinutul lui t1 în
fptr=ftab; tabloul t2:
în urma căreia variabila pointer fptr va avea adresa
primului element al tabloului ftab. Există de PROGRAMUL 3.1
asemenea următoarele echivalenţe:
#include <stdio.h>
1. &ftab[0] <= => ftab main ( )
2. &ftab[1] <= => ftab+1 {
3. &ftab[i] <= => ftab+i int t1 [10] ,t2[10];
4. ftab[0] <= => *ftab
int i;
5. ftab[4] <= => *(ftab+4)
6. fptr+i <= => fptr[i] for (i=1;i<11;i++) t1[i-1] = i;
for (i=0;i<10;i++) t2[i] =t1[i];
Pe baza acestor egalităţi se poate calcula expresia: for (i=0;i<10;i++)
printf(“%d “,t2[i] );
(&ftab[i]-ftab)= = ftab+i- ftab==i
}
Chiar dacă conţine adresa primului element,
numele tabloului (fără index) referă întregul tablou, 3.2 Acest program calculează urma unei matrice
astfel că în exemplul nostru sizeof(ftab) va avea pătrate (suma elementelor de pe diagonala
valoarea 40 (10 elemente de 4 octeţi fiecare). principală) utilizând variabile pointer pentru
În cazul tablourilor multidimensionale, adresarea elementelor matricei. Aceste variabile
deoarece reprezintă tablouri cu elemente tablouri, pointer sunt iniţializat (pentru fiecare linie) cu
numele unui astfel de tablou (fără index) este un adresa de început a liniei respective.
pointer de tablouri.

2
Limbajul C cu aplicații în analiza numerică – Tablouri şi pointeri în limbajul C

PROGRAMUL 3.2 PROGRAMUL 3.3

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


#include <conio.h> void main (void)
main ( ) {
{ char sir[80], *str;
int mat[10][10]; int spatiu;
int s=0, *ptr,n,i,j; printf("Introduceti un sir: ");
printf("Dati dimensiunea matricei patrate:"); gets(sir);
scanf("%d",&n); str = sir;
for(i=0;i<n;i++) for (spatiu=0; *str; str++)
for(j=0;j<n;j++) {
{ if (*str != ' ') continue;
printf("mat[%d][%d]=",i+1,j+1); spatiu++;
scanf("%d",&mat[i][j]); }
} printf("Sirul contine %d spatii \n",spatiu);
for(i=0;i<n;i++) }
{
ptr=mat[i]; 4. Chestiuni de studiat
s=s+*(ptr+i); 4.1 Studierea noţiunilor teoretice şi a
} exemplelor prezentate.
printf("Suma=%d\n",s); 4.2 Studierea problemelor rezolvate şi
} identificarea elementelor de limbaj şi a
algoritmilor utilizaţi.
3.3 Acest program numără spaţiile dintr-un şir
introdus de la tastatura de către utilizator. Este
testat fiecare caracter, iar dacă acesta nu este
spaţiu, instrucţiunea continue forţează reluarea
ciclului for. În cazul în care este găsit un spaţiu,
valoarea variabilei spaţiu este incrementată.
Parcurgerea şirului se realizează prin
incrementarea variabilei str de tip pointer la un şir
de caractere

3
Limbajul C cu aplicații în analiza numerică – Funcţii in limbajul C

Lucrarea nr. 5

FUNCŢII ÎN LIMBAJUL C

1. Scopul lucrării
Lucrarea are ca scop prezentarea funcţiilor în limbajul C.

2. Noţiuni teoretice

În general, un program C este alcătuit din una Formatul general al apelului unei funcţii este:
sau mai multe funcţii. Întotdeauna există cel puţin nume_fct (param1, param2…)
o funcţie, funcţia main() care este apelată la Numim parametrii formali identificatorii din
lansarea în execuţie a programului. lista_declaraţii_parametrii din definiţia funcţiei
Sintaxa generală a definirii unei funcţii este : şi parametrii efectivi acele variabile, constante
sau expresii din lista unui apel al funcţiei.
tip_fct nume_fct(listă_declaraţii_parametrii) Se observă ca parametrii formali reprezintă
{ variabilele locale ale funcţiei. Timpul lor de viaţă
<lista_declaraţii_locale> corespunde duratei de execuţie a funcţiei.
listă_instrucţiuni Transmiterea parametrilor (în urma unui apel al
} funcţiei) se realizează prin încărcarea valorii
parametrilor efectivi în zona de memorie a
tip_fct este tipul rezultatului returnat de funcţie. parametrilor formali. Acest procedeu se numeşte
Dacă o funcţie nu întoarce un rezultat, tipul transfer prin valoare.
folosit este void. În cazul în care parametrul efectiv este o
În exemplul următor funcţia max primeşte doi variabilă, operaţiile efectuate în cadrul funcţiei
parametrii de tip float şi afişează valoarea maximă asupra parametrului formal nu o afectează. În Ex.1,
şi media acestora. Deoarece funcţia nu întoarce atribuirea a1=7.5 din finalul funcţiei nu modifică
niciun rezultat, tipul său este void: valoarea variabilei r din apelul max(r,4.53); .
Ex.1: Dacă se doreşte modificarea valorii unei
………. variabile indicate ca parametru efectiv într-o
void max(float a1,float a2) funcţie, trebuie ca parametrul formal să fie de tip
{ pointer. La apelare, trebuie să i se ofere explicit
float maxim; /* declaratie locală */ adresa unei variabile. Acest procedeu se numeşte
if(a1>a2) maxim=a1; transfer prin referinţă.
else maxim=a2; În cazul transferului prin referinţă, modificarea
printf realizată de funcţie asupra parametrilor efectivi
(“Maxim=%f;Medie=%f\n”,maxim,(a1+a2)/2); este valabilă atât în interiorul cât şi în exteriorul
a1=7.5; funcţiei.
} Atunci când se doreşte ca funcţia să returneze
main() un rezultat se foloseşte instrucţiunea return cu
{ … sintaxa:
float r; return (expresie)
… Valoarea expresiei este rezultatul întors de
max(r,4.53); /*apel al functiei afmax*/ funcţie, iar parantezele sunt opţionale.
}

1
Limbajul C cu aplicații în analiza numerică – Funcţii in limbajul C

3. Probleme rezolvate 3.2 Următorul program calculează suma


3.1 Următorul program creează şi elementelor unui vector utilizând o funcţie având
implementează o funcţie care caută un caracter printre parametrii formali şi o variabilă pointer.
într-un şir şi returnează toate poziţiile pe care
acesta este găsit. Poziţiile returnate sunt grupate #include<stdio.h>
într-un tablou, deoarece rezultatul funcţiei este de double fsuma(double *ptr, int n)
tip pointer la întreg. {
int i;
#include<string.h> double sum=0;
#include<stdio.h> for(i=0;i<n;i++)
#include<conio.h> sum=sum+*(ptr+i);
#include<alloc.h> /*<malloc.h> ptr Visual C*/ return sum;
}
int *find(char*sir,char caracter) main()
{ {
int*a,*b; double tab[20],elem,suma;
char*sir1; int i,nr;
sir1=sir; printf("Dati numarul de elemente al vectorului:");
a=(int*)malloc(strlen(sir)); scanf("%d",&nr);
b=a; for (i=0; i<nr;i++)
while(*sir1!='\0') {
{ printf("Numar(%d)=",i+1);
if(*sir1==caracter) scanf("%lf", &elem);
{ tab[i]=elem;
*a=(sir1-sir); }
a++; suma=fsuma(tab,nr);
} printf("Suma elementelor vectorului este: %5.2lf",
sir1++; suma);
} }
*a=-1;
return(b); 4. Probleme propuse
} 4.1. Să se implementeze o funcţie care caută un
void main(void) caracter într-un şir şi returnează de câte ori s-a
{ găsit caracterul.
clrscr(); 4.2 Să se implementeze o funcţie care
char *s="acesta este sirul care va fi analizat"; calculează suma elementelor de pe diagonala
char car='a'; principală a unei matrice pătrate, utilizând
int *pozitia,i; variabile pointer pentru adresarea elementelor
pozitia=find(s,car); matricei.
i=0;
while (pozitia[i] !=-1) 5. Chestiuni de studiat
printf(" %d ", pozitia[i++]+1); 5.1 Studierea noţiunilor teoretice şi a
} exemplelor prezentate.
5.2 Studierea problemelor rezolvate şi
identificarea elementelor de limbaj şi a
algoritmilor utilizaţi.
5.3 Rezolvarea problemelor propuse

2
Limbajul C cu aplicații în analiza numerică – Structuri

Lucrarea nr.6

STRUCTURI

1. Scopul lucrării
Lucrarea are ca scop prezentarea utilizării tipurilor de date de tip structură în limbajul C.

2. Noţiuni teoretice Iniţializarea unei variabile de tip structură se


Limbajul C permite utilizatorului să definească poate face:
noi tipuri de date pentru a avea o reprezentare mai - prin iniţializarea fiecărui membru al
convenabilă a informaţiei. Există posibilitatea structurii sau,
grupării unor elemente, pentru a reprezenta date - global, prin enumerarea, între acolade, a
complexe, cel mai des sub forma unor structuri. valorilor iniţiale ale membrilor, în ordinea
Structura este o colecţie de variabile ce pot fi în care apar în declaraţie.
de tipuri diferite, grupate împreună sub un singur Pentru variabilele structură punct din exemplul
nume şi memorată într-o zonă continuă de precedent se pot face iniţializările:
memorie. m.x=10.5;
Sintaxa generală de declarare a unei structuri m.y=m.x+7;
este: n={12.3, 34.5};
struct nume_structura {
tip1 elem1; Pot fi definite şi structuri încuibate. De
tip2 elem2; exemplu, un dreptunghi poate fi definit prin două
… puncte ale unei diagonale:
tipn elemn; struct dreptunghi {
} lista_var_struct; struct punct pt1;
în care: struct punct pt2;
struct = cuvânt cheie asociat structurilor; };
nume_structura = numele dat de utilizator struct dreptunghi d;
structurii; d.pt2.y=9.7;
tipi = tipul elementului elemi ; În ultima atribuire, ordonata punctului pt2 al
lista_var_struct = lista variabilelor de tip dreptunghiului d primeşte valoarea 9.7.
structură nume_structura definită anterior. De asemenea, pot fi declarate tablouri cu
Elementele componente ale unei structuri se elemente structuri:
numesc membrii sau câmpuri. struct punct sirpuncte[10];
De exemplu un punct identificat prin Pentru acest şir de puncte, secvenţa:
coordonatele sale x şi y poate fi reprezentat prin sirpuncte[2].x=20;
intermediul unei structuri cu două câmpuri x şi y atribuie abscisei celui de-al treilea punct valoarea
de tip float: 20.
struct punct Pot fi efectuate operaţii de atribuire între
{ variabile de tip structură de acelaşi tip, care
float x; echivalează cu atribuiri membru cu membru.
float y; Pot fi definite şi variabile pointer de tip
}m,n; structură:
iar m şi n sunt două variabile de tip structură struct punct *pct;
punct. pct=&sirpuncte[5];
Referirea la un membru al unei structuri se face Pentru accesul la un element al unei structuri
cu ajutorul operatorului punct „ . ” plasat între indicate de un pointer se utilizează operatorul de
numele structurii şi numele membrului, m.x fiind selecţie indirectă:’->’ (săgeata):
abscisa punctului m. pct->y=12.3;
1
Limbajul C cu aplicații în analiza numerică – Structuri

3. Probleme rezolvate 3.2. Programul următor utilizează tipul structură


3.1 Se consideră o grupă de maxim 20 de asociat cărţilor dintr-o bibliotecă şi face o selecţie
studenţi identificaţi prin numele lor. Pentru fiecare după anul apariţiei.
student se cunosc notele la cele patru examene din
sesiune. Să se afişeze toţi studenţii bursieri (a #include<stdio.h>
căror medie este mai mare sau egală cu 8.5). #include<conio.h>
struct carte
#include<stdio.h> {
struct student char titlu[20];
{ char autor[20];
char nume[15]; int an;
int nota1; float pret;
int nota2; };
int nota3; void main(void)
int nota4; {
} stud[20]; struct carte bib[50];
int i,n; int i,n=0;
float medie; clrscr();
void main (void) printf("\n Dati numarul de carti:");
{ scanf("%d",&n);
printf(" Dati numarul de studenti: ");
scanf("%d",&n); for(i=0;i<n;i++)
for(i=0;i<n;i++) {
{ printf(" Titlu=");
printf(" NUME="); scanf("%s",bib[i].titlu);
scanf("%s",stud[i].nume); printf(" Autor=");
printf(" NOTA1="); scanf("%s",bib[i].autor);
scanf("%d",&stud[i].nota1); printf(" Anul aparitiei=");
printf(" NOTA2="); scanf("%d",&bib[i].an);
scanf("%d",&stud[i].nota2); printf(" Pret=");
printf(" NOTA3="); scanf("%f",&bib[i].pret);
scanf("%d",&stud[i].nota3); }
printf(" NOTA4=");
scanf("%d",&stud[i].nota4); printf("Carti editate înainte de revolutie:\n");
} i=0;
i=0;
while(i<n) while(i<n)
{ {
medie=(float)(stud[i].nota1+stud[i].nota2+ if(bib[i].an<=1989)
stud[i].nota3+ stud[i].nota4)/4; {
if(medie>=8.5)
{ puts(bib[i].titlu);
puts(stud[i].nume); puts(bib[i].autor);
printf("%5.2f\n",medie); printf("\n");
} }
i++; i++;
} }
} }

2
Limbajul C cu aplicații în analiza numerică – Structuri

4. Probleme propuse 5. Chestiuni de studiat

4.1 Pentru o grupă de studenţi se cunosc numele 5.1 Studierea noţiunilor teoretice şi a
studenţilor şi 5 note obţinute la sfârşitul exemplelor prezentate.
semestrului. Se cere să se afişeze studenţii care nu 5.2 Studierea problemelor rezolvate şi
au nici o restanţă. identificarea elementelor de limbaj şi a
algoritmilor utilizaţi.
4.2. Să se folosească structuri de tip punct, 5.3 Rezolvarea problemelor propuse.
pentru a determina daca trei puncte A,B,C (date
prin coordonatele lor) pot forma un triunghi şi de
ce tip (oarecare, isoscel, echilateral).

4.3 Folosind tipul complex ca o structură cu


două câmpuri (parte reală şi parte imaginară), să
se simuleze operaţiile asupra numerelor complexe:
adunare, scădere, înmulţire, împărţire, modul,
parte reală şi parte imaginară.

3
Limbajul C cu aplicații în analiza numerică –Liste

Lucrarea nr. 7
LISTE

1. Scopul lucrării
Lucrarea are ca scop prezentarea listelor în limbajul C, punând accentul pe reprezentarea acestora cu ajutorul
structurilor de date dinamice.

2. Noţiuni teoretice În această structură, câmpul urm va conţine adresa


În anumite situaţii este necesară organizarea următorului nod din listă. El este un pointer la o
informaţiilor sub forma unor liste. De exemplu lista variabilă de tip structură identică cu cea din care face
persoanelor dintr-o instituţie, a produselor dintr-un parte. Pentru ultimul nod din listă, variabila urm va
magazin etc.. Lista este deci compusă din elemente de avea valoarea NULL, deoarece nu mai urmează un alt
acelaşi tip, iar informaţia conţinută în fiecare element al nod. De asemenea, spre primul nod al listei nu
listei este de multe ori complexă. pointează nici un alt nod.
Lista are un număr variabil de elemente şi deci un Cunoaşterea primului şi ultimului element al listei
caracter dinamic. Astfel, la începutul execuţiei este importanţă, deoarece permite accesul la orice
programului, lista este goală urmând ca aceasta să fie element prin parcurgerea listei (începând cu primul) şi
completată şi să i se aducă apoi modificări, tot prin facilitează operaţiile de adăugare de elemente noi la
program. sfârşitul listei.
Limbajul C permite implementarea listelor cu Atunci când trebuie adăugat un element în listă se
ajutorul variabilelor dinamice de tip structură. parcurg etapele:
Utilizarea tablourilor pentru reprezentarea unor liste 1. se alocă dinamic spaţiu pentru respectivul
este posibilă, dar nu este eficientă, deoarece listele au element,
un caracter dinamic spre deosebire de tablouri. De 2. se creează elementul prin înscrierea
aceea, practica uzuală este de a ordona elementele unei informaţiilor corespunzătoare şi
liste folosind variabile pointer care intră în componenţa 3. se leagă în listă.
elementelor. Utilizarea acestor variabile pointer dă un Când un element trebuie scos din listă, se rup şi se
caracter recursiv elementelor listei. Listele refac legăturile, iar spaţiul ocupat de acesta se
implementate astfel se numesc înlănţuite. eliberează.
Elementele unei astfel de liste poartă denumirea
uzuală de noduri. Dacă între noduri există o singură 2.2.Liste dublu înlănţuite
relaţie de legătură lista se numeşte simplu înlănţuită, iar Între nodurile unei liste dublu înlănţuite vor exista
dacă există două relaţii de legătură lista se numeşte două relaţii de legătură, cu elementul anterior şi cu
dublu înlănţuită. elementul următor. În acest caz, vor exista doi pointeri
Cele mai uzuale operaţii care se pot efectua asupra de legătură ce memorează adresa nodului anterior şi
unei liste înlănţuite sunt: crearea listei, accesul la un respectiv a celui următor din listă. Implementarea
nod, adăugarea, ştergerea sau modificarea unui element exemplului precedent se va face, în cazul utilizării
şi ştergerea listei. listelor dublu înlănţuite, sub forma:

2.1. Liste simplu înlănţuite struct nod


Între nodurile unei liste simplu înlănţuite există o {
singură relaţie de legătură, de obicei de indicare a char nume[15];
succesorului unui element. Această legătură se char prenume[15];
implementează cu ajutorul unui pointer ce memorează int varsta;
adresa nodului următor din listă. struct nod *ant;
De exemplu pentru o listă de persoane simplu struct nod *urm;
înlănţuită, la care se cunosc numele, prenumele şi };
vârsta, nodul are următoarea formă:
struct nod { Adăugarea unui element într-o listă dublu înlănţuită
char nume[15]; va necesita aceleaşi etape ca în cazul listelor simplu
char prenume[15]; înlănţuite. Funcţia care realizează adăugarea unui
int varsta; element într-o listă dublu înlănţuită, al cărui nod are
struct nod *urm;}; structura de mai sus, va avea următoarea formă:

1
Limbajul C cu aplicații în analiza numerică –Liste

void adauga(char *Nume,char *Prenume,int Varsta) void sterge(struct nod *p)


{ {
struct nod *p; struct nod *q;
p=(struct nod *)malloc(sizeof(struct nod)); if(!p) return;
if(p==NULL) if(prim==p)
{ {
printf("Memorie insuficientă.\n"); prim=p->urm;
return; if(prim==NULL) ultim=NULL;
} }
strcpy(p->nume,Nume); else {
strcpy(p->prenume,Prenume); for(q=prim;q->urm!=p&&q->urm!=NULL;q=q->urm)
p->varsta=Varsta; if(q->urm==NULL)
p->urm=NULL; {
ultim->urm=p; printf("Elementul nu aparţine listei.\n");
p->ant=ultim; return;
ultim=p; }
} q->urm=p->urm;
if(p==ultim) ultim=q;
3. Problemă rezolvată }
Să se creeze o listă simplu înlănţuită a persoanelor free(p);
dintr-o instituţie în care să se memoreze numele, }
prenumele şi vârsta fiecăruia. Să se afişeze persoanele void main(void) {
a căror vârstă este mai mică de 40 de ani. Persoanele char Nume[15],Prenume[15];
care au vârsta de pensionare (65 de ani) vor fi int Varsta;
eliminate din listă. Se va afişa apoi lista persoanelor int i,n;
rămase. struct nod *p,*q;
printf("Numărul de persoane:");scanf("%d",&n);
#include <stdio.h> prim=ultim=NULL;
#include <string.h> for(i=0;i<n;i++)
#include <alloc.h> {
#include <conio.h> printf("Nume:");gets(Nume);
struct nod { printf("Prenume:");gets(Prenume);
char nume[15]; printf("Varsta:");scanf("%d",&Varsta);
char prenume[15]; adauga(Nume,Prenume,Varsta);
int varsta; }
struct nod *urm;}; printf("Lista persoanelor sub 40 de ani :\n");
struct nod *prim,*ultim; for(p=prim;p!=NULL;p=p->urm)
if(p->varsta <= 40) printf("%15s%15s - %d\n",
void adauga(char *Nume,char *Prenume,int Varsta) p->nume,p->prenume,p->varsta);
{ p=prim;
struct nod *p; while(p!=NULL) {
p=(struct nod *)malloc(sizeof(struct nod)); if(p->varsta > 65)
if(p==NULL) {
{ q=p->urm;
printf("Memorie insuficientă.\n"); sterge(p);
return; p=q;
} }
strcpy(p->nume,Nume); strcpy(p->prenume,Prenume); else p=p->urm;
p->varsta=Varsta; }
p->urm=NULL; printf("Lista persoanelor ramase:\n");
if(prim==NULL) prim=ultim=p; for(p=prim;p!=NULL;p=p->urm)
else printf("%15s%15s - %d\n",p->nume,p-> prenume,
{ p->varsta);
ultim->urm=p; }
ultim=p;
}
}

2
Limbajul C cu aplicații în analiza numerică –Liste

4. Probleme propuse 5. Chestiuni de studiat


4.1 Să se implementeze lista din problema rezolvată 5.1 Studierea noţiunilor teoretice şi a exemplelor
3 cu ajutorul listelor dublu înlănţuite. prezentate.
4.2 Să se creeze o listă a studenţilor prezenţi la un 5.2 Studierea problemelor rezolvate şi identificarea
examen de admitere în care să se memoreze numele, elementelor de limbaj şi a algoritmilor utilizaţi.
prenumele şi media de admitere. Să se afişeze studenţii 5.3 Rezolvarea problemelor propuse
care primesc bursă (cu media peste 9.50). Studenţii cu
media de admitere sub 5.00 sunt consideraţi respinşi şi
vor fi eliminaţi din listă. Se va afişa apoi lista
studenţilor admişi.

3
Limbajul C cu aplicații în analiza numerică - Fişiere in limbajul C

Lucrarea nr.8

FIŞIERE IN LIMBAJUL C

1. Scopul lucrării
Lucrarea are ca scop prezentarea utilizării fişierelor în limbajul C.

2. Noţiuni teoretice
Un fişier reprezintă o colecţie ordonată de În exemplul următor:
înregistrări. Majoritatea operaţiilor de intrare–ieşire se FILE *fptr1, *fptr2;
bazează pe manipularea fişierelor. Datele introduse de fptr1=fopen(“fist.txt”,”r+t”);
la tastatură formează un fişier de intrare, în timp ce fptr2=fopen(”fisb.bin”,”wb”);
datele afişate pe display sau listate la imprimantă sunt deschise două fişiere: primul de tip text pentru
formează un fişier de ieşire. operaţii de actualizare şi cel de-al doilea de tip binar
Există două tipuri de fişiere: text şi binare. În timp pentru scriere.
ce fişierele text conţin caractere ASCII în gama 0-127 Închiderea unui fişier se realizează cu funcţia
(informaţie citibilă), fişierele binare conţin înşiruiri de fclose() având sintaxa generală:
caractere, neinteligibile pentru utilizator. De exemplu, int fclose(FILE* fptr_fisier);
fişierele sursă sunt fişiere text, în timp ce fişierele care va închide fişierul specificat de fptr_fisier.
executabile sunt fişiere binare. Funcţia fclose() returnează valoarea 0 în caz de
Prelucrarea unui fişier presupune o serie de operaţii închidere cu succes a fişierului şi EOF dacă a apărut o
precedate de deschiderea fişierului şi finalizate cu eroare.
închiderea acestuia. Închiderea fişierelor din exemplul precedent se va
În urma deschiderii unui fişier se generează un face cu secvenţa:
pointer la o structură de tip FILE predeclarată în fclose(fptr1);
stdio.h. Sintaxa de declarare a unui pointer la FILE fclose(fptr2);
este: FILE*fptr; Scrierea de date în fişier se realizează cu ajutorul
fptr fiind numele variabilei pointer cu care se lucrează funcţiei fprintf():
în continuare. int fprintf(FILE *fptr, const char *format,
Deschiderea unui fişier se realizează cu funcţia arg1, arg2,…,argn)
fopen() cu sintaxa generală: care scrie în fişierul pointat de fptr datele specificate de
FILE *fopen(const char*nume_fisier , arg1…argn, în formatul specificat prin şirul de
const char *mod); caractere format.
în care: În exemplul:
nume_fisier este numele fişierului care se va deschide
sau crea; FILE *fpt;
mod este modul în care este deschis fişierul: int i=5;
“r” deschide fişierul pentru citire; char c=’B’;
“w” deschide un fişier pentru scriere; float f=2.7543;
“a” deschide sau creează un fişier pentru scriere la fpt=fopen(“fis.dat”,”w”);
sfârşitul fişierului (adăugare); fprintf(fpt,”%d,%c,%f”,i,c,f);
“r+” deschide un fişier pentru actualizare
(citire + scriere); prin utilizarea funcţiei fprintf(), se scriu în fişierul
“w+” deschide un fişier pentru actualizare, conţinutul fis.dat, descris de fpt, un întreg, un caracter şi o
anterior se elimină; variabilă de tip float.
“a+” deschide un fişier pentru actualizare la sfârşit. Citirea de date dintr-un fişier se realizează cu
Fişierele pot fi deschise în mod binar sau text, după ajutorul funcţiei fscanf():
cum este specificat în argumentul mod al funcţiei fopen int fscanf(FILE *fptr, const char *format,
prin adăugarea literei t pentru text sau b pentru binar. arg1, arg2,…,argn)
Dacă operaţia de deschidere are succes, funcţia care citeşte din fişierul indicat de fptr date sub
returnează un pointer la FILE (pointer care va fi folosit controlul formatului specificat în format şi le atribuie
în continuare în operaţiile asupra fişierului), iar dacă variabilelor prin adresele specificate în arg1,
eşuează, fopen întoarce valoarea NULL. arg2,……argn, care, de această dată, sunt pointeri.

1
Limbajul C cu aplicații în analiza numerică - Fişiere in limbajul C

3. Problemă rezolvată {
Să se creeze un fişier text ce conţine informaţii despre printf("\n Nume:");
produsele dintr-un magazin. Să se scrie apoi o funcţie de scanf("%s",s.nume);
adăugare, apoi una de căutare în fişier după nume şi printf("\nNumarul de bucati:");
modificarea numărului de bucăţi . În final să se listeze scanf("%d",&(s.nr));
conţinutul fişierului modificat.
printf("\nPret: ");
#include<stdio.h>
scanf("%f",&(s.pret));
#include<string.h>
fwrite(&s,sizeof(prod),1,fp);
#include<conio.h>
printf("\n\n Mai doriţi adăugare? (d/n): ");
#include<process.h>
c=getch();
#define nf "produse.txt"
}
typedef struct {
fclose(fp);
char nume[10];
}
int nr;
void modificare()
float pret;
{ prod s;
}prod;
long int poz;
FILE *fp;
int gasit=0;
void creare ()
char n[10];
{
int nrnou;
if((fp=fopen(nf,"w"))==NULL)
printf("\n Dati numele dupa care se cauta: ");
{
scanf("%s",n);
printf("Eroare de creare\n");
printf("\n Dati noua cantitate: ");
exit(1);
scanf("%d",&nrnou);
}
if((fp=fopen(nf,"r+"))==NULL)
fclose(fp);
{
}
printf("Eroare de deschidere\n");
void listare ()
exit(1);
{
}
prod s;
while((!gasit)&&(!feof(fp)))
clrscr();
{
if((fp=fopen(nf,"r"))==NULL)
poz=ftell(fp);
{
fread(&s,sizeof(prod),1,fp);
printf("Eroare de deschidere \n");
if(!strcmp(n,s.nume))
exit(1);
gasit++;
}
}
do
if(!gasit)
{
{
fread(&s,sizeof(prod),1,fp);
printf("\nNu s-a gasit inregistrarea ");
if(feof(fp)) break;
getch();
printf("\n%s",s.nume);
}
printf("\n%d",s.nr);
else
printf("\n%5.2f",s.pret);
{
}
fseek(fp,poz,SEEK_SET);
while (!feof(fp));
fclose(fp);
fread(&s,sizeof(prod),1,fp);
}
s.nr=nrnou;
void adaugare ()
fseek(fp,poz,SEEK_SET);
{
fwrite(&s,sizeof(prod),1,fp);
char c;
}
prod s;
fclose(fp);
clrscr();
}
if((fp=fopen(nf,"a"))==NULL)
void main()
{
{ creare();
printf("Eroare de deschidere\n");
adaugare();
exit(1);
listare();
}
modificare();
c='d';
listare(); }
while(c=='d')

2
Limbajul C cu aplicații în analiza numerică - Fişiere in limbajul C

4. Probleme propuse 5. Chestiuni de studiat


4. 1. Să se creeze şi să se listeze un fişier binar cu 5.1 Studierea noţiunilor teoretice şi a exemplelor
studenţi, în care să se memoreze numele şi două note. prezentate.
Datele se citesc dintr-un fişier text creat anterior. 5.2 Studierea problemei rezolvate şi identificarea
4.2. Să se scrie o procedură de creare a unui fişier elementelor de limbaj şi a algoritmilor utilizaţi.
text ce conţine nume de studenţi şi o alta de actualizare 5.3 Rezolvarea problemelor propuse
prin adăugare a acestui fişier. În final se va scrie o
procedură de listare a conţinutului fişierului.

3
Limbajul C cu aplicații în analiza numerică – Rezolvarea ecuaţiilor

Lucrarea nr. 9

REZOLVAREA ECUAŢIILOR
1. Scopul lucrării
Lucrarea are ca scop prezentarea unei metode numerice de rezolvare a ecuaţiilor algebrice şi
transcendente cu ajutorul limbajului C++.

paşii de mai sus. Se obţin intervale de tip [ai, bi] ca


2. Noţiuni teoretice fiind jumătate din intervalul [ai-1, bi-1] prin metoda
Există mai multe metode numerice utilizate generală:
pentru calculul rădăcinilor reale ale unei ecuaţii xi-1=(ai-1+bi-1)/2;
algebrice: metoda bisecţiei, metoda poziţiei false, ai=ai-1, bi=xi-1 dacă f(ai-1)∙ f(xi-1)<0
metoda aproximaţiilor succesive, metoda lui ai=xi-1, bi=bi-1 dacă f(ai-1)∙ f(xi-1)>0
Newton, metoda lui Bairstow, etc.. Se obţin astfel două şiruri convergente:
Acestea sunt metode de calcul care presupun - şirul an al extremităţilor stângi ale intervalelor,
utilizarea unor algoritmi numerici ce permit găsirea care este monoton crescător (a < a1 < ... < an)
rădăcinilor. Înainte de calculul propriu-zis al - şirul bn al extremităţilor drepte ale intervalelor,
rădăcinilor (prin procedee iterative), trebuie care este monoton descrescător (b > b1 > ... > bn )
realizată o separarea a rădăcinilor ce constă în Se observă şi că bn-an=(b-a)/2n.
găsirea acelor intervale care conţin cel mult o Aşadar, an şi bn vor converge ambele către
rădăcină. soluţia ξ, deoarece există o valoare n pentru care
|bn-an| < ε, unde ε este eroarea impusă pentru
Metoda bisecţiei calculul soluţiei ecuaţiei date. Se poate aproxima
Această metodă mai este numită metoda soluţia ecuaţiei cu valoarea mijlocului intervalului
înjumătăţirii intervalului sau metoda bipartiţiei. [an , bn] .
Metoda permite găsirea unei rădăcini (cu o În continuare, pe baza algoritmului prezentat, se
anumită eroare ε) a ecuaţiei: vor prezenta două funcţii în limbajul C++,
f(x)=0 corespunzătoare rezolvării ecuaţiilor algebrice şi
în intervalul [a,b], unde f : [a,b] ―>R şi f este respectiv transcendente.
continuă pe [a,b]. Se presupune că s-a realizat în
prealabil o separare a rădăcinilor, astfel încât pe Exemplul 1
intervalul [a,b] există cel mult o rădăcină ξ.
Algoritmul începe prin analizarea următoarelor int bisectiepol (double s, double d, int grad,
patru situaţii: double coef[], double err, double *rad)
1. f(a)=0 şi deci ξ=a; {
2. f(b)=0 şi deci ξ=b; double xm ;
3. f(a)∙f(b)<0 şi atunci ξ aparţine intervalului if(poly(s,grad,coef)*poly(d,grad,coef)>0) return 0;
(a,b) if( poly (s,grad,coef) == 0 )
4. f(a)∙f(b)>0 şi atunci nu există o rădăcină în {
intervalului [a,b]. *rad=s;
Variantele 1,2 şi 4 presupun încheierea return 1;
procesului de găsire a rădăcinii. }
Algoritmul continuă, în varianta 3, cu if(poly(d,grad,coef)==0)
înjumătăţirea intervalului [a,b] şi determinarea {
valorii x0=(a+b)/2. Se verifică dacă x0 este soluţie a *rad=d;
ecuaţiei, prin evaluarea |f(x0)| < ε. În caz contrar, return 1;
se alege semiintervalul [a1,b1] la capetele căruia }
funcţia are semne opuse (f(a1)∙f(b1)≤0) şi se repetă xm=0.5*(s+d);

1
Limbajul C cu aplicații în analiza numerică – Rezolvarea ecuaţiilor
while((fabs(d-s)>err) &&(poly(xm,grad,coef)!=0)) parametru al acestei funcţii este un pointer ce
{ conţine adresa funcţiei matematice pentru care se
xm=0.5*(d+s); caută soluţiile.
if(poly(s,grad,coef)*poly(xm,grad,coef)<0)
d=xm;
else s=xm; 3. Probleme rezolvate
} 3.1 Să se afle dacă ecuaţia: x3-9x2+23x-15=0
*rad=xm; are o rădăcină în intervalul (-4.5,6), şi să se afle
return 1; valoarea acesteia (în cazul în care există) cu o
} eroare de 0.000001.
În acest exemplu s şi d reprezintă limitele
stânga şi respectiv dreapta ale intervalelor de lucru, #include<math.h>
iar xm mijlocul acestora. Este utilizată funcţia #include<iostream.h>
matematică poly() din math.h, care permite aflarea int bisectiepol (double s, double d, int grad,
valorii unui polinom într-un punct (primul double coef[], double err, double *rad)
parametru al funcţiei) cunoscându-se gradul {
polinomului (al doilea parametru) şi vectorul double xm ;
coeficienţilor acestuia (al treilea parametru). if(poly(s,grad,coef)*poly(d,grad,coef)>0) return 0;
Funcţia întoarce valoarea 0 în cazul în care nu if( poly (s,grad,coef) == 0 )
este găsită o rădăcină în intervalul specificat şi {
valoarea 1 în caz de succes, valoarea soluţiei fiind *rad=s;
transferată în variabila *rad. return 1;
}
if(poly(d,grad,coef)==0)
Exemplul 2. {
*rad=d;
int bisectiefct(double(*f)(double),double s, return 1;
double d, double err, double *rad) }
{ xm=0.5*(s+d);
double xm; while((fabs(d-s)>err) &&(poly(xm,grad,coef)!=0))
if(f(s)*f(d)>0) return 0; {
if(f(s)==0) xm=0.5*(d+s);
{ *rad=s; if(poly(s,grad,coef)*poly(xm,grad,coef)<0)
return 1; d=xm;
} else s=xm;
if(f(d)==0) }
{ *rad=xm;
*rad=d; return 1;
return 1; }
}
xm=0.5*(s+d); void main(void)
while( (fabs(d-s)>err)&&(f(xm)!=0) ) {
{ double *rad;
xm=0.5*(s+d); double f[]={-15,23,-9,1};
if( f(s)*f(xm)<0) d=xm; if (bisectiepol(4.5,6,3,f,0.000001,rad)==1)
else s=xm; {cout<<"Functia are o radacina in intervalul (4.5,6)
} egala cu:";
*rad=xm; cout<<*rad;}
return 1; else
} cout<<"Functia nu are radacina in intervalul
Implementarea acestei funcţii s-a realizat în specificat";
mod asemănător cu funcţia din exemplul 1. Primul }

2
Limbajul C cu aplicații în analiza numerică – Rezolvarea ecuaţiilor
3.2. Să să afle soluţia ecuaţiei transcendente 4. Probleme propuse
x e x
0 în intervalul (0.1,1), aplicând metoda 4.1 Să se afle dacă ecuaţia x3 –6x2+8x=0 are o
bisecţiei cu o eroare de calcul de rădăcină în intervalul (1,3), iar în caz afirmativ să
0.0000000001 se găsească această soluţie.
4.2 Să se găsească o rădăcină a ecuaţiei
#include<math.h> x sin( x ) 0.25 0 în intervalul (1,2) cu o
#include<iostream.h> precizie de 0.000001 .
double fct(double x)
{ 5. Chestiuni de studiat
double val_fct; 5.1 Studierea noţiunilor teoretice şi a
val_fct=x-exp(-x); exemplelor prezentate.
return (val_fct); 5.2 Studierea problemelor rezolvate şi
} identificarea elementelor de limbaj şi a
int bisectiefct(double(*f)(double),double s, algoritmilor utilizaţi.
double d, double err, double *rad) 5.3 Rezolvarea problemelor propuse
{
double xm;
if(f(s)*f(d)>0) return 0;
if(f(s)==0)
{ *rad=s;
return 1;
}
if(f(d)==0)
{
*rad=d;
return 1;
}
xm=0.5*(s+d);
while( (fabs(d-s)>err)&&(f(xm)!=0) )
{
xm=0.5*(s+d);
if( f(s)*f(xm)<0) d=xm;
else s=xm;
}
*rad=xm;
return 1;
}

void main(void)
{
double s=0.1,d=1.0,err=0.00000001,*sol;
bisectiefct(fct,s,d,err,sol);
cout<<"Solutia ecuatiei f(x)=0 pe intervalul:
("<<s<<","<<d<<") este: "<<*sol;
}

3
Limbajul C cu aplicații în analiza numerică – Interpolarea funcţiilor

Lucrarea nr. 10

INTERPOLAREA FUNCŢIILOR
1. Scopul lucrării
Lucrarea are ca scop prezentarea unei metode numerice de aproximare a funcţiilor tabelate şi a
implementării acesteia în limbajul C++.

2. Noţiuni teoretice este diferit de zero (nodurile xi sunt distincte),


Interpolarea reprezintă o metodă numerică de sistemul va avea o soluţie unică pentru coeficienţii
aproximare a funcţiilor date sub formă tabelară. a0, a1…..an şi deci pentru polinomul de interpolare.
Având un set discret de date [xi,yi] (i=0,1,…,n) Se obţine aşa numitul polinomul de interpolare
(obţinut în urma unor experimente, măsurători al lui Lagrange, care are forma:
etc.), metoda presupune găsirea unei funcţii f(x) n n x xj
continuă care să verifice yi=f(xi) (i=0,1,…,n). P ( x) yi (5)
i 0 j 0 , j i xi xj
Funcţia f(x) se numeşte funcţie de interpolare, iar
punctele xi noduri ale reţelei de interpolare. Deci, cu ajutorul acestui polinom, se poate
Uzual, funcţia de interpolare are o formă simplă calcula valoarea funcţiei în orice punct necunoscut
pentru a permite cu uşurinţă aflarea valorilor în cuprins între x0 si xn.
orice punct al domeniului de definiţie şi pentru a Implementarea polinomului de interpolare
putea fi uşor prelucrată (derivată, integrată etc.). Lagrange se poate face cu funcţia C++:
De aceea, interpolarea este utilizată şi în cadrul
metodelor numerice de derivare, integrare etc.. double lagrange(int n, float x[],
Calculul funcţiei f(x) pentru valori ale lui x float y[],float point)
cuprinse între nodurile reţelei de interpolare se {
numeşte interpolare, iar dacă x se află în afara int i,j;
reţelei, extrapolare. float sum=0, prod;
for(i=0; i<n; i++)
2.1 Interpolarea polinomială {
Cea mai utilizată funcţie de interpolare este prod = 1;
funcţia polinomială. Interpolarea polinomială for(j=0;j<n;j++)
presupune găsirea unui polinom P(x) care să if (j!=i)
verifice: prod*=(point-x[j])/(x[i]-x[j]);
P(xi)=yi , i=0,1,…,n (1) sum+=y[i]*prod;
Dacă polinomul P(x) are expresia: }
return sum;
P(x) a n x n a n 1x n 1 ... a1x a 0 (2)
}
condiţiile din relaţia (1) sunt echivalente cu:
anx0
n
a n 1x 0
n 1
... a 1x 0 a0 y0 În cazul în care reţeaua de interpolare are doar
n n 1
două puncte, interpolarea devine liniară:
a n x1 a n 1x1 ... a 1x1 a0 y1 x x2 x x1
(3) f (x ) y y1 y2 (6)
......................................................... x1 x 2 x 2 x1
anxn
n
a n 1x n
n 1
... a 1x n a0 yn Ultima egalitate din relaţia (6) reprezintă chiar
Deoarece determinantul acestui sistem (de tip ecuaţia unei drepte care trece prin punctele (x1,y1)
Vandermonde): şi (x2,y2).
n 1
D (x j xi ) (4)
i, j 0
j i

1
Limbajul C cu aplicații în analiza numerică – Interpolarea funcţiilor

3. Problemă rezolvată 4. Problemă propusă


În urma unor măsurători s-au obţinut Plecând de la datele problemei rezolvate 3, să
următoarele date memorate în variabilele x şi y: se scrie un program care realizează interpolarea,
x 0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 însă pentru un număr mai mic de noduri ale reţelei
y 7 14 17 20 22 25 26 28 29 30 de interpolare. De exemplu, pentru 7 noduri alese
Se cere să se determine puncte între nodurile în mod diferit: uniform distribuit, mai multe în
reţelei de interpolare ( de exemplu pentru: prima parte sau mai multe în a doua parte. Să se
x=0.35 ; x=0.64 ; x=0.89) compare rezultatele obţinute pentru aflarea
valorilor funcţiei în punctele x=0.35, x=0.64 şi
#include<iostream.h> x=0.89 . Să se comenteze rezultatele obţinute.
double lagrange(int n, float x[],
float y[],float point) 5. Chestiuni de studiat
{ 5.1 Studierea noţiunilor teoretice şi a
int i,j; exemplelor prezentate.
float sum=0, prod; 5.2 Studierea problemelor rezolvate şi
for(i=0; i<n; i++) identificarea elementelor de limbaj şi a
{ algoritmilor utilizaţi.
prod = 1; 5.3 Rezolvarea problemei propuse.
for(j=0;j<n;j++)
if (j!=i)
prod*=(point-x[j])/(x[i]-x[j]);
sum+=y[i]*prod;
}
return sum;
}

void main(void)
{
int n=10;
float val;
float x[]={0,0.1,0.2,0.3,0.4,0.5,0.6,0.7,0.8,0.9};
float y[]={7,14,17,20,22,25,26,28,29,30};
float p=0.64;
val=lagrange(n,x,y,p);
cout<<"Valoarea functiei de interpolare in
punctul x="<<p<<" este: "<<val;
}

2
Limbajul C cu aplicații în analiza numerică – Integrarea ecuaţiilor diferenţiale ordinare

Lucrarea nr. 11

INTEGRAREA ECUAŢIILOR DIFERENŢIALE ORDINARE

1. Scopul lucrării
Lucrarea are ca scop prezentarea unei metode numerice de integrarea a ecuaţiilor diferenţiale ordinare
cu ajutorul limbajului C++.

2. Noţiuni teoretice 3. Problemă rezolvată


Se consideră problema Cauchy: Exemplul următor foloseşte metoda Runge-
y’=f(x,y) Kutta de ordin 4, implementată în funcţia RK4,
cu condiţia iniţială: pentru rezolvarea ecuaţiei diferenţiale y’=x·y cu
y(x0)=y0 condiţia iniţială y(0)=1. Deci f(x,y)=x*y, funcţie
Există mai multe metode numerice utilizate notată în program cu F.
pentru rezolvarea unei astfel de ecuaţii diferenţiale:
metoda dezvoltării în serie Taylor, metoda lui #include<math.h>
Euler, metodele Runge-Kutta etc. #include<iostream.h>
Metodele Runge-Kutta sunt metode directe float F(float x,float y)
bazate pe dezvoltarea în serie Taylor şi necesită {
doar evaluarea funcţiei f(x,y), nu şi a derivatelor float val;
acesteia. val=x*y;
Dintre metodele Runge-Kutta, cea de ordin 4 return (val);
este mai utilizată deoarece este relativ simplă şi }
oferă un grad de precizie acceptabil. Această void RK4(float(*f)(float x,float y),
metodă este definită de relaţiile: float x0,
x m 1  x m  h float y0,
h float h,
y m1  y m  k1  2k 2  2k 3  k 4  int nr,
6
cu: float sol[])
k 1  f x m , y m  {
int i;
 h h 
k 2  f  x m  , y m  k1  float k1,k2,k3,k4;
 2 2 
sol[0]=y0;
 h h  for(i=1;i<=nr;i++)
k3  f  x m  , ym  k2 
 2 2  {
k 4  f x m  h , y m  hk 3  k1=f(x0+(i-1)*h,sol[i-1]);
În cadrul acestei metode, funcţia este evaluată k2=f(x0+(i-1)*h+0.5*h,sol[i-1]+0.5*h*k1);
de patru ori, iar eroarea de trunchiere este de k3=f(x0+(i-1)*h+0.5*h,sol[i-1]+0.5*h*k2);
forma: k4=f(x0+i*h,sol[i-1]+h*k3);
sol[i]=sol[i-1]+h*(k1+2*k2+2*k3+k4)/6.0;
eT  K  h 5

1
Limbajul C cu aplicații în analiza numerică – Integrarea ecuaţiilor diferenţiale ordinare
cout<<"\n"<<(i)*h<<" "<<sol[i]; 5. Chestiuni de studiat
} 5.1 Studierea noţiunilor teoretice şi a
} exemplelor prezentate.
void main(void) 5.2 Studierea problemei rezolvate şi
{ identificarea elementelor de limbaj şi a algoritmilor
float x0=0,y0=1,h=0.1,sol[10]; utilizaţi.
cout<<"\n0 1,000000"; 5.3 Rezolvarea problemelor propuse
RK4(F,x0,y0,h,10,sol);
}
4. Probleme propuse
4.1Să se scrie un program sursă în limbajul
C++ prin care să se găsească soluţiile ecuaţiei
diferenţiale y’=x2+y2 în punctele x=0.1; 0.2, 0.3;
0.4; 0.5, 0.6; 0.7, 0.8, 0.9 şi 1 ştiind că y(0)=1.
4.2 Se consideră un circuit R,L in serie
alimentat de la o sursa de curent alternativ
e=5cos(100πt)V. Cunoscând R=5Ω, L=5mH și că
la t=0 i=0, să se calculeze valorile curentului la
t=0.001, 0.002, 0.003, 0.004, 0.005, 0.006; 0.007,
0.008, 0.009 și 0.01 s.
Ecuaţia diferenţială asociată circuitului electric
di
este L  Ri  e .
dt

2
Limbajul C cu aplicații în analiza numerică – Rezolvarea sistemelor de ecuații liniare

Lucrarea nr. 12

REZOLVAREA SISTEMELOR DE ECUAȚII LINIARE

1. Scopul lucrării
Lucrarea are ca scop prezentarea unei metode numerice de rezolvare a sistemelor de ecuații liniare cu
ajutorul limbajului C++.
(de exemplu toate zero sau coloana termenilor
2. Noţiuni teoretice liberi) şi se construiesc şirurile:
Se consideră sistemul liniar de n ecuaţii cu n x1(1) , x (21) ,..., x (n1)
necunoscute:
x1( 2) , x (22) ,..., x (n2)
a11x1 a12 x 2 ... a1n x n b1
a x a x ... a x b ………………..
21 1 22 2 2n n 2
x1( k ) , x (2k ) ,..., x (nk )
a n1x1 a n2x 2 ... a nn x n bn pe baza condiţiei de recurenţă:
sau matriceal AX=B unde: X (k ) CX ( k 1)
D
x1 b1 unde:
a 11 a 12 ... a 1n b1
x2 b2
a 21 a 22 ... a 2n xk
a 11
A ; X . ; B . 1
. . ... . xk b2
. . Xk 2
; D
a n1 a n2 ... a nn a 22
xn bn ...
...
x kn bn
a nn
Una dintre cele mai vechi metode iterative de
rezolvare a sistemelor de ecuaţii liniare este a 12 a 13 a 1n
0 ...
metoda lui Jacobi. Aceasta presupune explicitarea a 11 a 11 a 11
fiecărei necunoscute din sistem, de pe diagonala a 21 a 23 a 2n
0 ...
C a 22 a 22 a 22 ;
principală, în funcţie de celelalte necunoscute ale
sistemului: a n1 a n2 a n3
b1 a a 13 a ... 0
x1 0 12 x 2 x 3 ... 1n x n a nn a nn a nn
a 11 a 11 a a 11
11 O condiţie suficientă de convergenţă a metodei
b2 a 21 a 23 a 2n Jacobi este:
x2 x1 0 x 3 ... xn
a 22 a 22 a 22 a 22 a ii max a ij pentru i 1,2,..., n
j i

bn a n1 a nn 1 Condiţia de oprire a procesul iterativ este:


xn x 1 ... xn 1 0
a nn a nn a nn max xik xi( k 1)
pentru i 1,2,..., n
unde ε este eroarea maxim admisibilă.
Se consideră o primă aproximare a soluţiilor În cazul în care a fost depăşit un număr maxim
sistemului oarecare: de iteraţii fără respectarea condiţiei anterioare,
x1(0) , x (20) ,..., x (n0) metoda nu este convergentă.

1
Limbajul C cu aplicații în analiza numerică – Rezolvarea sistemelor de ecuații liniare
3. Problemă rezolvată }
Metoda Jacobi prezentată mai sus este }
implementată în programul următor: void main (void)
#include<stdlib.h> {
#include<iostream.h> int i,j,n;
#include<math.h> char conv;
void Jacobi(float a[20][20],float b[20],float x[20], float x[10];
int n,char *conv) float a[10][20];
{ float b[10];
int max=10000; cout<<"Dati numarul de ecuatii: n=";
float eps=1.0e-6; cin>>n;
int i,j,it; cout<<"Dati elementele matricei A:";
float dif,eroare,s,xi[20]; for (i=0;i<n;i++)
for (i=0; i<n; i++) for (j=0;j<n;j++)
xi[i]=0.0; {cout<<"a["<<i<<","<<j<<"]=";
*conv='y'; cin>>a[i][j];
i=0; }
while (i<n) for (i=0;i<n;i++)
{ {
if (a[i][i]==0.0) cout<<"b["<<i<<"]=";
*conv='n'; cin>>b[i];
i = i+1; }
} Jacobi(a,b,x,n,&conv);
if (*conv=='y') }
{
it=1;
do 4. Probleme propuse
{ 4.1Să se rezolve, cu ajutorul metodei Jacobi,
for (i=0; i<n; i++) sistemul de ecuaţii:
{s = 0.0; 6 x1 2 x 2 2 x 3 x 4 12
for (j=0; j<n; j++)
x1 4 x 2 2
if (i!=j) s = s + a[i][j]*xi[j];
x[i] = (b[i]-s)/a[i][i]; x1 4 x 2 8x 3 2
} 2 x1 x 2 x 3 5x 4 4
eroare =0.0; și să se compare rezultatele obținute cu soluția
for (i=0; i<n; i++) exactă a sistemului.
{ dif = fabs(x[i]-xi[i]); 4.2 Studiați influența valorii erorii maxim
if (fabs(dif)>1e20) it=max+1; admisibile asupra soluțiilor obținute.
if (dif>eroare) eroare = dif;
} 5. Chestiuni de studiat
for (i=0; i<n; i++) xi[i] = x[i]; 5.1 Studierea noţiunilor teoretice şi a
it = it+1; exemplelor prezentate.
} while ((it<max)&&(eroare>eps)); 5.2 Studierea problemei rezolvate şi
if (it>max) identificarea elementelor de limbaj şi a
{ algoritmilor utilizaţi.
*conv='n'; 5.3 Rezolvarea problemelor propuse
cout<<"\n Metoda nu este convergenta!";
}
else
cout<<"Solutiile sistemului sunt:";
for(i=0;i<n;i++)
cout<<x[i]<<" ";

2
Limbajul C cu aplicații în analiza numerică – Vectori și valori proprii

Lucrarea nr. 13

VECTORI ȘI VALORI PROPRII


1. Scopul lucrării
Lucrarea are ca scop prezentarea unei metode numerice de calcul a vectorilor și a valorilor proprii unei
matrici cu ajutorul limbajului C++.

2. Noţiuni teoretice
Se consideră o matrice pătrată A de ordinul n cu sistemelor de ecuaţii diferenţiale şi în alte operaţii
elemente din corpul K (K=R sau K=C): Scalarul mai complicate.
K pentru care există un vector nenul Cea mai simplă metodă de calcul a valorilor
T proprii şi ale vectorilor proprii asociate este
x  x1 x2 x 3 ... x n , x  K n ce verifică
metoda puterii.
A·x=λ·x se numeşte valoare proprie a matricei A Pentru matricea pătrată A de ordinul n se
iar vectorul x se numeşte vector propriu asociat presupune existenţa a n valori proprii distincte λ1 ,
valorii proprii λ. λ2,… λn, şi a n vectori proprii x1, x2,…xn
Relaţia: A·x=λ·x poate fi scrisă matriceal: independenţi. În aceste condiţii, un vector oarecare
 a11 a12 ... a1n   x1   x1  y  K n poate fi scris ca o combinaţie liniară de cei
     
 a 21 a 22 ... a 2n   x 2   x2  n vectori proprii ai matricei A:
     
     ...   ... 
y  a 1x1  a 2 x 2  ...  a n x n
     
a    x 
 n1 a n 2 ... a nn   x n   n Dacă înmulţim această egalitate cu matricea A
echivalentă cu: rezultă:
 a 11   a 12 ... a1n   x1  Ay  Aa 1x1  Aa 2 x 2  ...  Aa n x n
   
 a 21 a 22   ...a 2n   x 2   a 1λ1x1  a 2 λ 2 x 2  ...  a n λ n x n
   0
     ...  iar dacă se continuă înmulţirea cu A a noilor
    egalităţi, după pasul k se obţine :
 a a n2 ... a nn     x n 
 n1
A k y  A k a 1x1  A k a 2 x 2  ...  A k a n x n
care reprezintă un sistem omogen ce admite
întotdeauna soluţia banală:  a 1λ1k x1  a 2 λ k2 x 2  ...  a n λ kn x n
x1  x 2  x3  ...  x n  0. care poate fi rescrisă :
k k
În plus, sistemul liniar omogen admite soluţii k k λ  λ 
A y  λ a x  a 2  2  x 2  ...  a n  n  x n
nenule dacă şi numai dacă: 1 1 1
 λ1   λ1 
det (A-λ·In)=0 unde In este matricea
 a 1λ1k x1
unitate de ordinul n.
Determinantul în necunoscuta λ reprezintă un dacă se consideră λ1 ca fiind cea mai mare valoare
polinom de grad n şi se numeşte polinomul proprie şi k este mare.
caracteristic al matricei A, iar egalarea sa cu zero Aceiaşi aproximare poate fi făcută şi pentru
ecuaţie caracteristică a matricei A. ecuaţia :
k 1 k 1
Orice matrice de ordinul n cu coeficienţi k 1 k 1 λ  λ 
complecşi are exact n valori proprii (nu neapărat A y  λ a x  a 2  2  x 2  ...  a n  n  x n
1 1 1
 λ1   λ1 
distincte) care sunt rădăcinile ecuaţiei
caracteristice.  a 1λ1k 1 x 1
Calculul vectorilor şi a valorilor proprii Din împărţirea ultimelor două egalităţi se obţine
simplifică operaţiile cu matrice în rezolvarea valoarea proprie de valoare maximă λ1:

1
Limbajul C cu aplicații în analiza numerică – Vectori și valori proprii

Ak y yk y[i]=0;
1   for(j=0;j<n;j++)
A k 1y y k 1
y[i]+=a[i][j]*x[j];
unde cu yk s-a notat Ak·y.
}
Se observă că y k  a1k1 x1 şi deci este un for(i=0;i<n;i++)
aproximant al vectorului propriu x1 corespunzător x[i]=y[i];
variabilei proprii λ1. temp=val;
Deoarece yk are componente mari în valoare
absolută se consideră ca vector propriu val=0;
yk for(i=0;i<n;i++)
corespunzător lui λ1 vectorul .
yk {
if(fabs(x[i])>fabs(val))
val=x[i];
3. Problemă rezolvată
}
Această metodă este implementată în exemplul
for(i=0;i<n;i++)
următor:
x[i]/=val;
}while(fabs(val-temp)>0.0001);
#include<iostream.h>
cout<<"Valoarea proprie este : "<<val<<endl;
#include<conio.h>
cout<<"Vectorul propriu este: ";
#include<math.h>
for(i=0;i<n;i++)
#include<stdlib.h>
cout<<endl<<x[i];
int main()
getch();
{
}
float a[20][20],x[20],y[20],val=0,temp;
int n,i,j;
clrscr(); 4. Probleme propuse
4.1Să se calculeze, cu ajutorul metodei puterii,
cout<<"Dati dimensiunea matricei: ";
valoarea proprie și vectorul propriu asociat pentru
cin>>n;
cout<<"\nDati elementele matricei \n ";  2 1 1 
 
for(i=0;i<n;i++) matricea:   1 2  1 şi vectorul iniţial (1 0 0)T
{  1 1 2 
 
for(j=0;j<n;j++) 4.2 Repetati calculul pentru vectorul iniţial
(-1 -1 -1)T
{
cout<<"a["<<i+1<<"]["<<j+1<<"]=" ; 5. Chestiuni de studiat
cin>>a[i][j]; 5.1 Studierea noţiunilor teoretice şi a
} exemplelor prezentate.
} 5.2 Studierea problemei rezolvate şi
cout<<"Dati vectorul initial: \n "; identificarea elementelor de limbaj şi a
for(i=0;i<n;i++) algoritmilor utilizaţi.
{ 5.3 Rezolvarea problemelor propuse
cout<<"x["<<i+1<<"]= ";
cin>>x[i];
}
do
{
for(i=0;i<n;i++)
{

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