Sunteți pe pagina 1din 125

MARIUS TOMESCU

CARMEN FIFOR

Programarea calculatoarelor Introducere n C#

Editura Universitii Aurel Vlaicu Arad - 2010 -

Prefa
C# este un limbaj de programare de nivel nalt, orientat obiect, care face parte din tehnologia software .Net, i reprezint un pas important n evoluia limbajelor de programare. Multe firme recurg la limbajul C# n procesele de implementare i dezvoltare software deoarece ofer un foarte bun suport pentru tehnologiile de vrf. Cursul de fa cuprinde att noiunile de baz ale limbajului C#, ct i unele elemente de nivel mediu i avansat. Cursul poate fi un instrument util pentru nsuirea i consolidarea cunotinelor pentru oricine dorete s neleag i s fie iniiat ntr-un limbaj de programare. Primele ase capitole cuprind noiuni de baz ale limbajului C#: tipuri de date i instruciuni elementare, care au rolul de a iniia studentul n limbajul de programare C# aducndu-l la un nivel mediu, noiuni introductive despre clase i folosirea fiierelor. Ultimul capitol (PROBLEME REZOLVATE) are un rol important n pregtire. n acest capitol sunt prezentate i explicate n detaliu programe de nivel mediu spre complex, cu scopul de a clarifica noiunile fundamentale de programare C#, explicaii menite a forma o gndire algoritmic riguroas. Sperm ca textul acestui curs s ofere o introducere plcut n programarea calculatoarelor i limbajul C#. Am ncercat s prezentm fiecare noiune ntr-o manier accesibil i interesant. Scopul acestui curs este de a va nva noiunile de baz ale programrii n C# i de realiza trecerea studentului de la un cunosctor al limbajului C# la un programator C#. Cursul se adreseaz n primul rnd studenilor din anul I, celor care studiaz un curs elementar sau academic de algoritmi, structuri de date i limbaje de programare. Octombrie 2010 Autorii

CUPRINS

CAPITOLUL I. INTRODUCERE N LIMBAJUL C#...................7


1.1 Conceptele de baz ale limbajului C#............................................................7 1.2 Structura unui program C#.............................................................................7 1.3 Metodele unui clase........................................................................................9 1.4 Comentarii....................................................................................................10 1.5 Declaraii......................................................................................................11 1.6 Blocuri de instruciuni..................................................................................11 1.7 Identificatori.................................................................................................11 1.8 Cuvinte cheie................................................................................................12 1.9 Tipuri de date ...............................................................................................13 1.10 Variabile.....................................................................................................14

CAPITOLUL II. EXPRESII I OPERATORI..............................17


2.1 Expresii.........................................................................................................17 2.2 Operatori aritmetici......................................................................................17 2.3 Operatori de atribuire...................................................................................17 2.4 Operatori relaionali.....................................................................................20 2.5 Operatori logici. Operatori logici la nivel de bii.........................................20 2.6 Operatorul condiional ?:..............................................................................21

CAPITOLUL III. INSTRUCIUNI................................................23


3.2 Instruciunea switch......................................................................................23 3.3 Instruciunea for...........................................................................................24 3.4 Instruciunea do-while..................................................................................25 3.5 Instruciunea while.......................................................................................26 3.6 Instruciunea foreach....................................................................................26 3.8 Instruciunea continue..................................................................................30 3.9 Instruciunea goto ........................................................................................30 3.10 Instruciunea return.....................................................................................32

CAPITOLUL IV. TIPURI DEFINITE DE UTILIZATOR..........33


4.1 Tipul enumerare...........................................................................................33 4.2 Tipul tablou .................................................................................................34 4.3 Conversii numerice.......................................................................................36

CAPITOLUL V. CLASE NOIUNI DE BAZ.........................39


5.1 Clasele. Noiuni de baz...............................................................................39 5.2 Cmpuri .......................................................................................................40 5.3 Metode .........................................................................................................41 5.4 Crearea variabilelor i instanelor unei clase................................................53 5.5 Membrii unei instane...................................................................................54 5.6 Modificatori de acces ..................................................................................54 5.7 Accesul privat sau public.............................................................................55

CAPITOLUL VI. PROBLEME REZOLVATE.............................59


6.1 ALGORITMI ELEMENTARI.....................................................................59 6.2 VECTORI.....................................................................................................90 6.3 MATRICI...................................................................................................113

BIBLIOGRAFIE.............................................................................125

CAPITOLUL I. INTRODUCERE N LIMBAJUL C#

1.1 Conceptele de baz ale limbajului C#


Fiecare nou limbaj de programare este influenat ntr-o anumit msur de limbaje de programare deja existente. C# deriv direct din dou dintre cele mai de succes limbaje de programare pe plan mondial i anume C (inventat de ctre Dennis Ritchie n anii 70, rulnd iniial pe sistemul de operare Unix) i C++ (inventat de ctre Bjarne Stroustrup n 1979 pe baza limbajului C, noutatea fundamental fiind introducerea programrii orientate spre obiecte). De asemenea, se nrudete cu un alt limbaj mai nou i deopotriv de succes i anume limbajul Java (dezvoltat de ctre firma Sun Microsystems ncepnd cu anul 1991, avnd o sintax i o filozofie derivate din C+ +, contribuia fundamental fiind portabilitatea programelor, necesar odat cu dezvoltarea diverselor sisteme de operare i a Internetului). Chiar dac Java a rezolvat cu succes multe din problemele legate de portabilitate n Internet, C# a venit s rezolve una din facilitile care i lipseau i anume interoperabilitatea limbajelor de programare diferite, denumit i programare n limbaj mixt. Aceasta reprezint posibilitatea codului scris ntr-un anumit limbaj s lucreze mpreun cu codul scris ntr-un alt limbaj, necesar n special la crearea sistemelor software distribuite, de mari dimensiuni. C# este un limbaj de programare orientat-obiect conceput de Microsoft la sfritul anilor 90. Acesta fost conceput ca un concurent pentru limbajul Java. C# este un derivat al limbajului de programare C++ i a fost dezvoltat de o echip restrns de ingineri de la Microsoft, echip din care s-a evideniat Anders Hejlsberg (autorul limbajului Turbo Pascal i membru al echipei care a proiectat Borland Delphi). Limbajul C# este simplu, cu circa 80 de cuvinte cheie, i 12 tipuri de date predefinite. El permite programarea structurat, modular i orientat obiect, conform preceptelor moderne ale programrii profesioniste. Limbajul de programare C# a fost proiectat pe baza experienelor acumulate din celelalte limbaje de programare. ntregul limbaj C# se bazeaz pe conceptul de obiecte. n esen, structura unui program scris n C# este gndit pe mai multe niveluri, aa cum se arat n figura urmtoare.

Figura 1. ntr-un program C# vom avea cod de program n care se definesc metode, care sunt incluse n clase, care la rndul lor sunt incluse n nume de spaii.

1.2 Structura unui program C#


Un program scris ntr-un limbaj de programare const din instruciuni n limba englez, denumite cod surs. O instruciune a unui limbaj de programare reprezint o comand dat

calculatorului. Totalitatea instruciunilor care descriu cum se rezolv o anumit problem se numete program. Structura unui program scris n limbajul C# este descris n figura urmtoare:

Figura 2. Structura unui program scris n limbajul C#

Urmtorul program C# afieaz pe ecran mesajul Hello World !:

Figura 3. Exemplu de program C#

Un program C# este format din una sau mai multe clase, grupate ntr-un spaiu de nume (namespace). Un spaiu de nume este o colecie de clase care au asociat un nume. Acesta poate cuprinde mai multe clase cu nume diferite avnd funcionaliti nrudite. Dou clase pot avea acelai nume cu condiia ca ele s fie definite n nume de spaii diferite. n cadrul aceluiai nume de spaiu poate aprea definiia unui alt nume de spaiu, caz n care avem de-a face cu spaii de nume imbricate. O clas poate fi identificat prin numele complet (nume precedat de numele spaiului sau spaiilor de nume din care face parte clasa respectiv, cu separatorul punct). n exemplul nostru, Simple.Program este numele cu specificaie complet a clasei Program. Codul i datele scrise n limbajul C# trebuie incluse ntr-o clas. Nu se pot defini variabile i nu se pot scrie declaraii nafara claselor. O clas este format din date i metode (funcii). Toate clasele deriv din clasa de baz denumit object. Apelarea unei metode n cadrul clasei n care a fost definit aceasta presupune specificarea numelui metodei. Apelul unei metode definite n interiorul unei clase poate fi invocat i din interiorul altei clase, caz n care este necesar specificarea clasei i apoi a metodei separate prin punct. Dac n plus, clasa aparine unui spaiu de

nume neinclus n fiierul curent, atunci este necesar precizarea tuturor componentelor numelui: spaiu.clas.metod sau spaiu.spaiu.clas.metod, etc. n programul nostru de mai sus se afl dou spaii de nume: unul definit (Simple) i unul extern inclus prin directiva using System;. Console.WriteLine reprezint apelul metodei WriteLine definit n clasa Console. Cum n spaiul de nume curent este definit doar clasa Program, deducem c definiia clasei Console trebuie s se gseasc n spaiul System. Altfel spus, denumirea complet ar fi System.Console.WriteLine, ceea ce ns, printre altele, ar fi incomod de redactat dac apare adesea ntr-un program. n cazul n care mai muli programatori lucreaz la realizarea unei aplicaii complexe, exist posibilitatea de a segmenta aplicaia n mai multe fiiere numite assemblies. ntr-un assembly se pot implementa mai multe spaii de nume, iar pari ale unui aceeai spaiu de nume se pot regsi n mai multe assembly-uri. Pentru o aplicaie consol, ca i pentru o aplicaie Windows de altfel, este obligatoriu ca una (i numai una) dintre clasele aplicaiei s conin un punct de intrare (entry point), i anume metoda (funcia) Main. S comentm programul de mai sus: linia 1: spune compilatorului c acest program utilizeaz tipuri de date i clase incluse n spaiul de nume System. n cazul nostru se va folosi clasa Console. linia 3: se declar un nou spaiu de nume, numit Simple. Noul spaiu de nume ncepe la acolada deschis din linia 4 i extinde pn la acolada nchis din linia 12. Orice tip declarat n aceast seciune este membru al spaiului de nume Simple. linia 5: orice program C# este alctuit din una sau mai multe clase. n aceast linie este declarat un nou tip de clas, denumit Program. Orice membrii declarai ntre acoladele care ncep n linia 6 i se termin n linia 11 sunt membrii care alctuiesc aceast clas. linia 7: n aceast linie este declarat metoda (funcia) Main ca membru al clasei Program. n acest program, metoda (funcia) Main este doar un membru al clasei Program. Main este o funcie special utilizat de compilator ca punctul de intrare n program. linia 9: Conine doar o singur declaraie simpl; aceast linie constituie corpul funciei Main. Aceast declaraie folosete clasa numit Console, amintit mai sus, care aparine spaiului de nume System i este folosit pentru operaiile de intrare/ieire. Aici se apeleaz metoda WriteLine din aceast clas, pentru afiarea mesajului dorit pe ecran. Fr folosirea directivei din linia 1 - using System compilatorul nu are de unde s tie unde se gsete clasa Console.

1.3 Metodele unui clase


O metod este un bloc de cod format dintr-o serie de instruciuni care conduc la realizarea unei aciuni. O metod este asemntoare cu funciile, procedurile sau subrutinele din limbajul C, C++ sau Pascal cu anumite excepii. O metod este o funcie coninut nuntrul unei clase. Metoda Main() Orice aplicaie scris n limbajul C# trebuie s conin o metod numit Main(), care reprezint punctul de intrare n aplicaie. n acest exemplu metoda Main() nu preia nici un 9

argument din linia de comand i nu returneaz explicit un indicator de stare a terminrii programului. Toate liniile de cod care formeaz corpul metodei Main() vor fi executate automat atunci cnd programul este rulat. Clasa Console Clasa Console aparine de spaiul de nume System. Cele dou metode (funcii de afiare pe ecran) Write i WriteLine afieaz pe consol (ecran) argumentele din parantez. n cazul metodei WriteLine, dup afiare se trece la linie nou. Urmtoarea linie de cod este un exemplu al utilizrii metodei Write:
Console.Write("Acesta este un text."); Output string

Codul scris mai sus produce urmtoarea ieire pe ecran: Acesta este un text. Un alt exemplu este urmtorul cod, care afieaz pe ecran trei iruri de caractere:
System.Console.Write ("This is text1."); System.Console.Write ("This is text2."); System.Console.Write ("This is text3.");

Acest cod produce urmtoarea ieire:


This is text1. This is text2. This is text3.

Sintaxa metodei Write i WriteLine este urmtoarea:


Console.WriteLine(FormatString, SubVal0, SubVal1, SubVal2, ... );

Dac exist mai muli parametrii, acetia sunt separai prin virgul. Primul parametru trebuie s fie ntotdeauna un ir de caractere i este denumit ir de formatare (format string). irul de formatare poate conine marcatori de substituie (substitution markers). Un marcator de substituie marcheaz poziia n formatul irului unde o valoare se substituie atunci cnd irul este afiat pe ecran. Un marcator este un numr natural cuprins ntre acolade, i care reprezint poziia numeric a valorii care urmeaz a fi substituit i care ncepe de la 0. Parametrii care urmeaz dup irul de formatare se numesc valori de substituie (substitution values). Urmtorul cod conine doi marcatori de substituie, numrul 0 i 1, i dou valori de care urmeaz a fi substituite, 3 i 6.
Substitution markers Console.WriteLine("Doua exemple de intregi sunt {0} si {1}.", 3, 6); Format string Substitution values

Acest cod produce pe ecran: Doua exemple de intregi sunt 3 si 6. Un marcator nu trebuie s refere o valoare de la o poziie mai lung dect lista valorilor ce trebuie substituite, n caz contrar se produce o eroare. Urmtorul exemplu reflect aceast situaie:
Poziia 0 Poziia 1 Console.WriteLine("Doi intregi: {0} si {2}.", 3, 6); // Eroare! Nu exist poziia 2.

1.4 Comentarii
Comentariile sunt buci de text care sunt excluse de la compilarea programului i care servesc la introducerea n program a unor explicaii referitoare la pri ale acestuia. 10

comentariu pe un rnd prin folosirea // Tot ce urmeaz dup caracterele // sunt considerate, din acel loc, pn la sfritul rndului drept comentariu:
// Acesta este un comentariu pe un singur rnd

comentariu pe mai multe rnduri prin folosirea /* i */ Orice text cuprins ntre simbolurile menionate mai sus se consider a fi comentariu. Simbolurile /* reprezint nceputul comentariului, iar */ sfritul respectivului comentariu:
/* Acesta este un comentariu care se ntinde pe mai multe rnduri */

1.5 Declaraii
O declaraie simpl este o instruciune n cod surs care descrie un tip de date sau care i spune programului s execute o aciune. O instruciune simpl se termin cu caracterul punct i virgul ;. Urmtorul exemplu de cod cuprinde dou instruciuni simple. Prima instruciune definete variabila cu numele var1 i o iniializeaz cu valoarea 5. A doua instruciune afieaz valoarea variabilei var1 pe ecran:
int var1 = 5; System.Console.WriteLine("Valoarea lui var1 este {0}", var1);

1.6 Blocuri de instruciuni


Un bloc de instruciuni cuprinde 0 sau mai multe instruciuni cuprinse ntre acolade {}. Exemplu:
{ int var1 = 5; System.Console.WriteLine("Valoarea lui var1 este {0}", var1); }

Un bloc este folosit de obicei acolo unde mai multe instruciuni definesc o aciune. Un bloc de instruciuni nu se termin cu punct i virgul ;.
Terminating ; Terminating ; {int var2 = 5; System.Console.WriteLine("The value of var1 is {0}", var1); } No terminating ;

1.7 Identificatori
Prin nume dat unei variabile, clase, metode etc. nelegem o succesiune de caractere care ndeplinete urmtoarele reguli: numele trebuie s nceap cu o liter sau cu unul dintre caracterele _ i @; primul caracter poate fi urmat numai de litere, cifre sau un caracter de subliniere; numele care reprezint cuvinte cheie nu pot fi folosite n alt scop dect acela pentru care au fost definite; cuvintele cheie pot fi folosite n alt scop numai dac sunt precedate de @; 11

dou nume sunt distincte dac difer prin cel puin un caracter (fie el i liter mic ce difer de aceeai liter majuscul); Convenii pentru nume: n cazul numelor claselor, metodelor, a proprietilor, enumerrilor, interfeelor, spaiilor de nume, fiecare cuvnt care compune numele ncepe cu majuscul; n cazul numelor variabilelor dac numele este compus din mai multe cuvinte, primul ncepe cu minuscul, celelalte cu majuscul. Simbolurile lexicale reprezentnd constante, regulile de formare a expresiilor, separatorii de liste, delimitatorii de instruciuni, de blocuri de instruciuni, de iruri de caractere etc. sunt n mare aceiai ca i n cazul limbajului C++. Secvene escape Secvenele escape permit specificarea caracterelor care nu au reprezentare grafic i reprezentarea unor caractere speciale precum backslash, apostrof, etc. Secvenele escape predefinite n C# sunt: \b : Backspace (BS) \t : Tab orizontal (HT) \n : Linie noua (LF) \f : Pagina noua (FF) \r : Inceput de rnd (CR) \" : Ghilimele \ : Apostrof \\ : Backslash Literali copie la indigo Un astfel de literal ncepe cu caracterul @ urmat de un ir de caractere cuprins ntre ghilimele. Specificul acestui literal const n faptul c acesta va putea fi reprezentat exact aa cum este scris, inclusiv dac se ntinde pe mai multe rnduri. Pentru a afia va trebui folosit (ghilimele duble). Exemplu:
Console.Write (@Ne place informatica mult);

Pe ecran va aprea:
Ne place informatica mult

1.8 Cuvinte cheie


Acestea sunt cuvinte speciale care au o semnificaie bine definit i care nu pot fi folosite dect n scopul pentru care au fost create. abstract as base bool break const continue decimal default delegate extern false finally fixed float int interface internal is lock 12 out override params private protected short sizeof stackalloc static string typeof uint ulong unchecked unsafe

byte case catch char checked class

do double else enum event explicit

for foreach goto if implicit in

long namespace new null object operator

public readonly ref return sbyte sealed

struct switch this throw true try

ushort using virtual void volatile while

Figura 4. Cuvintele cheie din C#

1.9 Tipuri de date


n limbajul de programare C# exist dou tipuri de date: tipuri valoare i tipuri referin. Tipurile valoare includ tipurile simple (char, int, float, etc), tipurile enumerare i structur acestea coninnd direct datele referite i sunt alocate pe stiv sau inline ntr-o struct. Tipurile referin includ tipurile clas, interfa, delegat i tablou, toate avnd proprietatea c variabilele de acest tip stocheaz referine ctre obiecte. Toate tipurile de date sunt derivate (direct sau nu) din tipul System.Object. Tipuri predefinite Limbajul C# conine un set de 15 tipuri predefinite, pentru care nu este necesar includerea vreunui spaiu de nume via directiva using: string, object, tipurile ntregi cu semn i fr semn, tipuri numerice n virgul mobil, tipurile bool i decimal. Tipul string este folosit pentru manipularea irurilor de caractere codificate Unicode; coninutul obiectelor de tip string nu se poate modifica. Clasa object este rdcina ierarhiei de clase din .NET, la care orice tip (inclusiv un tip valoare) poate fi convertit. Tipul bool este folosit pentru a reprezenta valorile logice true i false. Tipul char este folosit pentru a reprezenta caractere Unicode, reprezentate pe 16 bii. Tipul decimal este folosit pentru calcule n care erorile determinate de reprezentarea n virgul mobil sunt inacceptabile, de exemplu n calcule monetare, el punnd la dispoziie 28 de cifre zecimale semnificative. Pentru a semnala c un literal n virgul mobil este de tip decimal, se va pune la sfritul acestuia litera m sau M. Exemplu: decimal dcm=123.456m; Pentru a semnala c un literal n virgul mobil este de tip float, se va pune la sfritul acestuia litera f sau F, altfel se va subnelege c este de tip double i ar putea aprea erori. Exemplu: float flt=345.678F;
Denumir e Explicaie Valori reprezentate

sbyte byte short ushort int uint long ulong

ntreg cu semn pe 8 bii ntreg fr semn pe 8 bii ntreg cu semn pe 16 bii ntreg fr semn pe 16 bii ntreg cu semn pe 32 bii ntreg fr semn pe 32 bii ntreg cu semn pe 64 bii ntreg fr semn pe 64 bii 13

-128 127 0 255 -32768 32767 0 65535 -2.147.483.648 2.147.483.647 0 4.294.967.295 -9.223.372.036.854.775.808 9.223.372.036.854.775.807 0

float double bool char decimal object string dynamic

real cu precizie simpl real cu precizie dubl logic caracter Unicode 128 de bii, valoare real cu precizie de 28 de zecimale semnificative clasa de baz din care deriv toate tipurile secven de caractere Unicode tip folosit pentru assembly-urile din limbaje dinamice
Figura 5. Tipuri predefinite n C#

18.446.744.073.709.551.615 1.5x10-45 3.4x1038 5x10-324 1.7x10308 true, false U+0000 U+ffff 1.0x10-28 7.9x1028 System.Object System.String

Fiecare tip de date din C# i are corespondentul n tipul .Net (tipurile din spaiul de nume System). Tipuri definite de utilizator Tipurile care pot fi definite de utilizatori sunt de 6 feluri. O parte dintre acestea vor fi discutate n paginile urmtoare. class; struct; array; enum; delegate; interface.

1.10 Variabile
Un limbaj de programare trebuie s permit programului s stocheze i s manipuleze date. n timpul execuiei unui program, datele sunt temporal stocate n memorie. O variabil este un nume dat unei locaii de memorie folosit de un tip particular de date n timpul execuiei programului. Astfel, fiecrei variabile i se asociaz un tip de dat i o valoare. C# prevede patru categorii de variabile, fiecare dintre acestea vor fi discutate n detaliu: Variabile locale; Cmpuri; Parametrii; Elemente de tablou. Declararea variabilelor. n C# variabilele sunt declarate astfel:
<nume_tip_dat> <nume_variabil>;

Exemplu:
Tip

Nume variabil

int var2;

Codul de program de mai sus rezerv o arie de 4 bytes(octei) n memoria RAM, pentru stocarea valorii unei valori de tip ntreg, care va fi referit n program cu ajutorul identificatorului var2. Variabilele pot fi iniializate la declarare sau mai trziu:
bool isReady = true; float percentage = 87.88, average = 43.9;

14

char digit = '7';

Dup declararea tipului unei variabile, aceasta poate fi iniializat cu o valoare. Iniializarea unei variabile se face cu ajutorul semnului egal (=) plasat ntre numele variabilei i valoarea acesteia, aa cum se arat n continuare:
iniializare
int var2 = 17;

Variabilele locale neiniializate au valori nedefinite i prin urmare nu pot fi folosite pn cnd nu au atribuit o valoare. ncercarea de a utiliza o variabil neiniializat va produce o eroare la compilare. Declararea mai multor variabile de acelai tip. Se pot declara mai multe variabile ntr-o declaraie. Toate variabilele dintr-o declaraie de variabile, trebuie s fie de acelai tip. Numele variabilelor trebuie separate prin virgul iniializarea acestora se poate face cu ajutorul semnului =. n urmtorul cod de program se declar se declar, mai multe variabile de tip ntreg i respectiv real:
// Declaraii de variabile cu iniializare i fr int var3 = 7, var4, var5 = 3; double var6, var7 = 6.52;

Tip

Tip diferit

int var8, float var9; //Error!

Ultima declaraie este invalid deoarece sunt declarate dou variabile de tipuri diferite, n aceeai instruciune. Utilizarea valorii unei variabile. Numele unei variabile reprezint valoarea stocat de variabil. Se poate utiliza valoarea prin folosirea numelui variabilei. De exemplu, valoarea variabilei var este luat din memorie i plasat n poziia numelui variabilei, astfel:
Console.WriteLine("{0}", var);

n C# (la fel ca i n celelalte limbaje de programare moderne), variabilele trebuie declarate naintea folosirii acestora. Urmtorul cod de program va da eroare la compilare, deoarece variabila numr nu este iniializat:
static void Main() { int numr; //numr = 18; Console.WriteLine(numr); // error }

n cazul n care se vor terge cele dou // care preced comentariul din linia 4, codul poate fi compilat fr eroare. O variabil de un tip valoare conine efectiv o valoare. Cnd se declar o variabil de un tip valoare, compilatorul aloc n stiv numrul de octei corespunztori tipului, iar programatorul lucreaz direct cu aceast zon de memorie. O variabil de tip referin este o referin care, atunci cnd nu este null, refer un obiect de tipul specificat, alocat n memoria heap. 15

1.11 Constante. Constantele sunt variabile a cror valoare, odat definit, nu poate fi schimbat
de ctre program. Constantele sunt declarate astfel: const double PI = 3.142;

16

CAPITOLUL II. EXPRESII I OPERATORI


2.1 Expresii
Expresiile reprezint niruiri de operatori i operanzi. Operanzii pot fi: literali (constante), variabile, apeluri de metode, elemente de tablou, etc. Operatori

2.2 Operatori aritmetici


Operand

+ * / % ++ --

Descriere Adunare Scdere nmulire mprire Restul sau modulo Adunare cu 1 Scdere cu 1

Notaii prefixate sau postfixate Se d urmtoarea linie de cod: int num1 = 10; Urmtoarele instruciuni sunt echivalente:
num1++; num1 = num1 + 1; num1 += 1;

Ambii operatori ++ i pot fi utilizai n form prefixat sau postfixat. n forma prefixat,
num1 = 3; num2 = ++num1; // num1 = 4, num2 = 4

compilatorul va incrementa prima dat variabila num1 cu 1 i apoi va atribuii aceast valoare variabilei num2. n forma postfixat,
num2 = num1++; // num1 = 4, num2 = 3

compilatorul prima dat va atribuii valoarea variabilei num1 la variabila num2 i apoi incrementeaz variabila num1 cu 1.

2.3 Operatori de atribuire


Operand Descriere = Atribuire simpl += Atribuire aditiv -= Atribuire substractiv *= Atribuire multiplicativ /= Atribuire cu mprire %= Atribuire cu modulo O atribuire compus are forma: <var> op= <expr> i este echivalent cu: 17

<var> = <var> op <expr>,

iar op poate fi unul din operatorii: *, /, %, +, -, <<, >>, &, |, ^

Exemplu:
int i=0; i += 15; echivalent cu i = i + 15;

Exemplu:
using System; class FormattingNumbers { static void Main() { int val = 10; val += 10; Console.WriteLine("val val -= 5; Console.WriteLine("val val *= 10; Console.WriteLine("val val /= 3; Console.WriteLine("val val %= 8; Console.WriteLine("val Console.ReadLine(); } }

+=10 este {0}", val); -=5 este {0}", val); *=10 este {0}", val); /=3 este {0}", val); %=8 este {0}", val);

//val = 20 //val = 15 //val = 150 //val = 50 //val = 2

Citirea datelor de la tastatur i scrierea datelor la consol Citirea unui ir de caractere de la tastatur se face cu metodele Console.Read() sau Console.ReadLine(). Afiarea datelor pe ecran se face cu metodele Console.Write() sau Console.WriteLine(). Diferena dintre cele dou const n trecerea la linie nou n cazul metodelor care se termin cu Line. Exemplu:
using System; namespace ConsoleApplication { class Program { public static void Main() { float a, b; string sir; Console.Write("Dati valoarea pentru variabila a="); sir = Console.ReadLine(); a = float.Parse(sir); Console.Write("Dati valoarea pentru variabila b="); sir = Console.ReadLine(); b = float.Parse(sir); Console.Write("Suma dintre a={0} i b={1} este {2}", a, b, a+b); Console.ReadLine(); } } }

Exemplul de mai sus se poate scrie i astfel: 18

using System; namespace ConsoleApplication { class Program { public static void Main() { float a, b; Console.Write("Dati valoarea pentru variabila a="); a = float.Parse(Console.ReadLine()); Console.Write("Dati valoarea pentru variabila b="); b = float.Parse(Console.ReadLine()); Console.Write("Suma dintre a={0} i b={1} este {2}", a, b, a+b); Console.ReadLine(); } } }

Pentru tipurile numerice, metoda ToString produce o reprezentare ir de caractere a unui numr. Ea poate fi folosit i cu civa parametrii, care permit diverse formatri ale afirii valorii numerice ca i ir de caractere. n C# exist predefinite o mulime de modaliti pentru formatarea afirii valorilor numerice. Lista complet a acestora se poate gsi la adresele de Internet: http://msdn.microsoft.com/en-us/library/dwhawy9k.aspx http://msdn.microsoft.com/en-us/library/0c899ak8.aspx Practic este vorba de nite specificatori de format, reprezentai de obicei de o liter, ns pot fi i cifre sau alte caractere (# % . ,). De exemplu, specificatorul de format c (sau C) va face ca valoarea numeric afiat s conin i un simbol monetar.
decimal value = 123.456m; Console.WriteLine(value.ToString("C2")); Va afia: $123.46

Complementara metodei ToString este metoda Parse. Metoda Parse se folosete astfel:
variabil = tipul_variabilei.Parse(input_string);

unde tipul_variabilei poate fi oricare tip de date predefinit n C#. Exemplu:


int k = int.Parse("12345"); double dd = double.Parse(" -1,234.5678 "); Console.WriteLine("k={0} dd={1}", k, dd);

Exemplu:
using System; class Program { static void Main() { int a = 55000; int b = 676; double c = 555.4;

19

double d = 50870.1155; string a1 = a.ToString(); string a2 = a.ToString(); Console.WriteLine(a1 + " " string b1 = b.ToString(); string b2 = b.ToString(); Console.WriteLine(b1 + " " string c1 = c.ToString(); string c2 = c.ToString(); Console.WriteLine(c1 + " " string d1 = d.ToString(); string d2 = d.ToString(); Console.WriteLine(d1 + " " Console.ReadLine(); } }

+ a2);

// 55000 55000

+ b2);

// 676 676

+ c2);

// 555.4 555.4

+ d2);

// 50870.1155 50870.1155

2.4 Operatori relaionali


Operand
==

!= > < >= <= Exemplu:

Descriere Testarea egalitii Testarea inegalitii Strict mai mare Strict mai mic Mai mare sau egal Mai mic sau egal

using System; class OperatoriRelationali { static void Main() { int v1 = 5, v2 = 6; Console.WriteLine("{0}=={1} este {2}", v1, v2, v1==v2); Console.WriteLine("{0}!={1} este {2}", v1, v2, v1!=v2); Console.WriteLine("{0}>{1} este {2}", v1, v2, v1>v2); Console.WriteLine("{0}<{1} este {2}", v1, v2, v1<v2); Console.WriteLine("{0}<={1} este {2}", v1, v2, v1<=v2); Console.WriteLine("{0}>={1} este {2}", v1, v2, v1>=v2); Console.ReadLine(); } }

//false //true //false //true //true //false

2.5 Operatori logici. Operatori logici la nivel de bii


Operand
&

| ^ ~ ! && ||

Descriere AND ntre bii OR ntre bii XOR ntre bii NOT pe bii NOT logic AND logic OR logic 20

Operatori logici scurtcircuitai: &&, || Aceti operatori se numesc scurtcircuitai deoarece n cazul lui &&, dac primul operand este fals, rezultatul evalurii expresiei este automat fals, fr a mai verifica valoarea celui de-al doilea operand. n cazul lui ||, dac primul operand este adevrat, rezultatul evalurii expresiei este automat adevrat, fr a mai verifica valoarea celui de-al doilea operand. Neevalund al doilea operand se ctig timp la execuie. Exemplu:
using System; class OperatoriLogici { static void Main() { int i = 6, j = 12; bool firstVar = i > 3 && j < 10; Console.WriteLine("{0}>3 && {1}<10 este {2}", i, j, firstVar); // firstVar va avea valoarea false bool secondVar = i > 3 || j < 10; Console.WriteLine("{0}>3 || {1}<10 este {0}", i, j, secondVar); // secondVar va avea valoarea true Console.ReadLine(); } }

2.6 Operatorul condiional ?:


Acesta este un operator care necesit trei operanzi (operator teriar). Forma general a acestuia este: condiie ? expresie1 : expresie2 Rolul acestui operator este de a evalua o condiie i n funcie de valoarea de adevr a acesteia s execute (dac este adevrat) expresie1 sau expresie2 (dac este fals). Exemplu:
int i, x=3, y=4; i = x < y ? 10 : 20 ;

Efect: Dac x<y atunci i va lua valoarea 10, altfel va lua valoarea 20.

Precedena (prioritatea) operatorilor


n cazurile cnd avem expresii cu mai muli operatori este util s cunoatem ordinea n care acetia vor fi evaluai, mai ales cnd nu sunt folosite paranteze. n tabelul de mai jos sunt operatorii, de la cea mai mare prioritate spre cea mai mic i asociativitatea cnd sunt operatori cu aceeai prioritate. Operator ()[]. ++(postfix) --(postfix) Asociativitate stnga spre dreapta

checked new sizeof unchecked

++(prefix) --(prefix) +(unar) -(unar) (cast) ! ~ 21

dreapta spre stnga

* + << < < > ==

/ -

% >> >= !=
is

stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta stnga spre dreapta dreapta spre stnga dreapta spre stnga

& ^ | && || ?: = += -= *= /= %= &= ^= |= <= >>=

22

CAPITOLUL III. INSTRUCIUNI


Instruciuni condiionale 3.1 Instruciunea if-else
Instruciunea if execut o instruciune n funcie de valoarea de adevr a unei expresii logice. Structura instruciunii ifelse este urmtoarea:
if (expresie_boolean) instruciune sau bloc de instruciuni 1; [else instruciune sau bloc de instruciuni 2;]

Clauza else este opional. Exemplu:


int a=10; if (a<0) Console.Write (Negativ); else Console.Write (Pozitiv);

3.2 Instruciunea switch


n cazul unei instruciuni switch, expresia care se evalueaz trebuie s fie de tipul (sau convertibil implicit la tipul) sbyte, byte, short, ushort, long, ulong, char, string sau o enumerare bazat pe unul dintre aceste tipuri. Dac valoarea expresiei se regsete printre valorile specificate la clauzele case, atunci instruciunea corespunztoare va fi executat; dac nu, atunci instruciunea de la clauza default va fi executat (dac ea exist).
switch (expresie) case eticheta1: instruciune sau bloc de instruciuni; instruciunea break sau goto; . . case etichetaN: instruciune sau bloc de instruciuni; instruciunea break sau goto; [default] instruciune sau bloc de instruciuni; instruciunea break sau goto;

O etichet reprezint o expresie constant. n faza de proiectare a limbajului C#, Microsoft a decis s mpiedice trecerea automat la urmtoarea ramur case n lipsa instruciunii break (o facilitate uzual n C i C++); din acest motiv, lipsa instruciunii break pe o ramur case va genera eroare la compilare (exceptnd cazul cnd ramura case nu conine instruciuni). Trecerea de la o ramur case la alta poate fi ns simulat cu instruciunea goto: ... O instruciune poate s i lipseasc i n acest caz se va executa instruciunea de la caseul urmtor, sau de la default. Seciunea default poate s lipseasc. Dac o instruciune este nevid, 23

atunci obligatoriu va avea la sfrit o instruciune break sau goto case expresieConstanta sau
goto default.

Spre deosebire de C i C++, e interzis s se foloseasc trecerea automat de la o etichet la alta, continuarea se face folosind explicit instruciunea goto. Exemplu:
using System; class TestSwitch { static void Main() { int nota=8; switch (nota) { case 4: Console.Write (Nepromovat); break; case 8: Console.Write (Mediu); break; case 10: Console.Write (Foarte bine); break; } Console.ReadLine(); } }

Instruciuni de ciclare 3.3 Instruciunea for


Formatul instruciunii este:
for(expresie_de_iniializare; condiie; incrementare/decrementare) instruciune sau bloc de instruciuni;

Exemplu:
for(int i=1; i<=10; i++) { Console.WriteLine("In acest ciclu valoarea lui i este {0}.", i); }

Toate cele trei argumente ale instruciunii for sunt opionale. Exemple:
for(; ;) for( ; i<10; i++) for(int i=3; ; i--) for( ; i>5; )

Pot exista forme al instruciunii for care folosesc mai multe contoare, separate ntre ele prin virgul, dup cum se poate vedea n exemplul de mai jos:
for(i=0, j=10; i<j; i++, j--)

Dac se declar o variabil n expresia_de_iniializare, atunci ciclul ei de via este doar n corpul instruciunii for. Exemplu:
using System; namespace exemplu_for { class ExempluFor { static void Main()

24

{ for (int i = 1; i <= 10; i++) Console.WriteLine("Valoarea lui i este: {0}.", i); Console.ReadLine(); i++; // eroare !! } } }

Se pot utiliza instruciunile break i continue n orice instruciune de ciclare. Acestea schimb execuia normal a ciclului. Instruciunea break termin ciclul i transfer execuia n afara ciclului. Exemplu:
for(int i=1; i<=10; i++) { if(i>5) { break; } Console.WriteLine("Valoarea lui i in acest ciclu este:{0}.", i); }

Dac dup instruciunea break mai exist cel puin o instruciune, atunci compilatorul va genera o avertizare. Exemplu:
for(int i=3; i<10; i++) { break; //warning, Console.WriteLine (i); is unreachable code Console.WriteLine(i); }

Instruciunea continue ignor partea de instruciuni rmas din iteraia curent i trece la urmtoarea iteraie. Exemplu:
for(int i=1; i<=4; i++) { if(i==2) { continue; } Console.WriteLine("Valoarea lui i este:{0}.", i); }

Rezultatul:
Valoarea lui i in acest ciclu este:1. Valoarea lui i in acest ciclu este:3. Valoarea lui i in acest ciclu este:4.

3.4 Instruciunea do-while


Structura acestei instruciuni este:
do instruciune sau bloc de instruciuni while(condiie);

25

Se vor executa instruciunile de dup do, dup care se verific condiia. Instruciunea de ciclare continu atta timp ct condiia este adevrat (true). Urmtorul program afieaz ntregii de la 1 la 10 pe ecran:
using System; namespace exemplu_Do { class DoExample { static void Main() { int i = 1; do { Console.WriteLine("Valoarea lui i este {0}.", i); i++; } while (i <= 10); Console.ReadLine(); } } }

n cazul instruciunii do-while, instruciunile din corpul acesteia se execut cel puin odat.

3.5 Instruciunea while


Instruciunea while este similar cu instruciunea do-while, cu excepia c verificarea condiiei se face naintea execuiei codului din corpul instruciunii. Forma general a instruciunii este:
while(condiie) instruciune sau bloc de instruciuni

Exemplu:
using System; namespace exemplu_While { class WhileExample { static void Main() { int i = 1; while (i <= 10) { Console.WriteLine("Valoaea lui i este {0}.", i); i++; } Console.ReadLine(); } } }

3.6 Instruciunea foreach


Instruciunea foreach este un alt tip de instruciune de ciclare, care enumer elementele dintr-o colecie sau matrice (array), executnd o instruciune pentru fiecare element. Elementul care se extrage este de tip read-only, neputnd fi transmis ca parametru i nici aplicat un operator care sa-i schimbe valoarea. Structura de baz a instruciunii foreach este:
foreach(<tip_colecie> <nume_variabil> in <array sau colecie>) <instruciune sau bloc de instruciuni>

26

Exemplu:
int[] t = {1, 2, 3}; foreach (int x in t) { Console.WriteLine(x); }

Exemplu:
string[] fructe={Mar, Ciresa, Portocala}; foreach (string fruct in fructe) { Console.Write({0} , fruct); }

Exemplu:
static void Main() { // declararea i iniializarea unui ir de ntregi int [] integers = {3, 7, 2, 14, 65}; // iterarea elementelor din ir i tiprirea lor pe ecran foreach(int i in integers) { Console.WriteLine(i); } }

n instruciunea foreach(int i in integers), se specific tipul elementelor din colecie (int n acest caz). Se declar variabila i care va conine, la fiecare iteraie, valoarea fiecrui element al coleciei. Observaii: Variabila utilizat pentru a memora, la fiecare iteraie, valoarea unui element al coleciei, (i n cazul de mai sus) este de tip read only, deci nu se pot schimba valorile elementelor coleciei prin intermediul ei. Acest fapt nseamn c instruciunea foreach nu permite schimbarea valori elementelor coleciei sau tabloului, ci doar parcurgerea acesteia/acestuia.
Colecia poate s fie orice System.Collections.IEnumerable. instan a unei clase care implementeaz interfaa

clasa string este, de asemenea, o colecie de caractere.

static void Main() { string name = "Alexandru Cel Mare"; foreach(char ch in name) { Console.WriteLine(ch); } }

27

Instruciuni de salt 3.7 Instruciunea break


Instruciunea break permite ieirea forat dintr-un ciclu de tip switch, while, do while, for sau foreach. Exemplu de folosire a instruciunii break ntr-un ciclu for:
using System; class InstrBreak { static void Main() { for (int i = 1; i <= 100; i++) { if (i == 5) break; Console.WriteLine(i); } Console.ReadLine(); } }

Exemplu de folosire a instruciunii break ntr-un ciclu switch.


using System; class Switch { static void Main() { Console.Write("Alegeti un numar (1, string s = Console.ReadLine(); int n = Int32.Parse(s); switch (n) { case 1: Console.WriteLine("Valoarea break; case 2: Console.WriteLine("Valoarea break; case 3: Console.WriteLine("Valoarea break; default: Console.WriteLine("Selectie break; } } }

2, or 3): ");

este {0}", 1);

este {0}", 2);

este {0}", 3);

gresita.");

Exemplu de folosire a instruciunii break ntr-un ciclu for.


using System; class MainClass { public static void Main() { // se va folosi break pentru a iei din ciclu

28

for (int i = -10; i <= 10; i++) { if (i > 0) break; //ciclul se termin cnd i e pozitiv Console.Write(i + " "); } Console.WriteLine("Gata"); Console.ReadLine(); } }

Exemplu de folosire a instruciunii break ntr-un ciclu do-while.


using System; class MainClass { public static void Main() { int i; i = -10; do { if (i > 0) break; Console.Write(i + " "); i++; } while (i <= 10); Console.WriteLine("Gata"); Console.ReadLine(); } }

Exemplu de folosire a instruciunii break ntr-un ciclu foreach.


using System; class MainClass { public static void Main() { int sum = 0; int[] numere = new int[10]; for (int i = 0; i < 10; i++) numere[i] = i; foreach (int x in numere) { Console.WriteLine("Valoarea este: " + x); sum += x; if (x == 4) break; // cand x=4 se iese din ciclu } Console.WriteLine("Suma primelor 5 elemente: " + sum); } }

29

3.8 Instruciunea continue


Instruciunea continue ignor partea rmas din iteraia curent i pornete urmtoarea iteraie, ntr-o instruciune de ciclare de tip switch, while, do-while, for sau foreach. Exemplu de folosire a instruciunii continue, pentru afiarea numerelor pare dintre 0 i 100.
using System; class MainClass { public static void Main() { // afiseaza numerele impare din intervalul 0, 100 for (int i = 0; i <= 100; i++) { if ((i % 2) != 0) continue; // iterate Console.WriteLine(i); } Console.ReadLine(); } }

3.9 Instruciunea goto


Aceast instruciune permite saltul la o anumit instruciune. Are 3 forme:
goto eticheta; goto case expresieconstanta; goto default;

Cerina este ca eticheta la care se face saltul s fie definit n cadrul funciei curente i saltul s nu se fac n interiorul unor blocuri de instruciuni, deoarece nu se poate reface ntotdeauna contextul acelui bloc. Se recomand evitarea utilizrii intense a acestei instruciuni, n caz contrar se poate ajunge la fenomenul de spagetti code. (a se vedea articolul clasic al lui EdsgerW. Dijkstra, Go To Statement Considered Harmful: http://www.acm.org/classics/oct95/). Exemplu de folosire a instruciunii goto, n cazul instruciunii switch.
using System; class SwitchGoto { public static void Main() { for (int i = 1; i < 5; i++) { switch (i) { case 1: Console.WriteLine("In case 1"); goto case 3; case 2: Console.WriteLine("In case 2"); goto case 1;

30

case 3: Console.WriteLine("In case 3"); goto default; default: Console.WriteLine("In default"); break; } Console.WriteLine(); } } }

Exemplu de folosire a instruciunii goto, n cazul instruciunii for.


using System; class MainClass { public static void Main() { for (int i = 0; i < 10; i++) { Console.WriteLine("i" + i); if (i == 3) goto stop; } stop: Console.WriteLine("Stopped!"); } }

Exemplu de folosire a instruciunii goto, n cazul instruciunii while.


using System; class MainClass { static void Main() { int a = 0; while (a < 10) { if (a == 5) goto cleanup; a++; } cleanup: Console.WriteLine(a); Console.ReadLine(); } }

Exemplu de folosire a instruciunii goto, n cazul instruciunii if.


using System; class MainClass { public static void Main() { int total = 0; int counter = 0;

31

myLabel: counter++; total += counter; if (counter < 5) { System.Console.WriteLine(counter); goto myLabel; } Console.ReadLine(); } }

3.10 Instruciunea return


Instruciunea return termin execuia metodei n care aceasta apare, i returneaz controlul metodei apelante. Instruciunea return poate returna, opional, o valoare. Dac metoda care conine instruciunea return este de tip void, atunci instruciunea return poate fi omis. Forma general a instruciunii este:
return [expression];

unde expression este valoarea returnat de metod. Nu este utilizat cu metode de tip void. n exemplul urmtor, metoda A() returneaz variabila Area ca valoare de tip Double:
using System; class ReturnTest { static double CalculateArea(int r) { double area; area = r * r * Math.PI; return area; } public static void Main() { int raza = 5; Console.WriteLine("Aria e {0:0.00}", CalculateArea(raza)); Console.ReadLine(); } }

Indentarea programelor Limbajul C# este independent de format, n sensul c nu are importan unde sunt poziionate instruciunile unele n raport cu celelalte. De-a lungul timpului ns a fost dezvoltat i adoptat la scar larg un sistem de indentare comun, care permite apoi citirea programelor mult mai uor. Acest sistem presupune trecerea la un nou nivel de indentare dup fiecare acolad deschis i revenirea la nivelul de indentare anterior la nchiderea acoladei. Exist de asemenea unele instruciuni care necesit o indentare suplimentar. Se recomand ca programatorii s adopte acest stil de scriere a programelor.

32

CAPITOLUL IV. TIPURI DEFINITE DE UTILIZATOR


4.1 Tipul enumerare
Tipul enumerare este un tip definit de utilizator. Tipul enumerare este un tip valoare, construit pentru a permite declararea constantelor nrudite, ntr-o manier clar i sigur din punct de vedere al tipului. Un exemplu este:
enum Days {Sat, Sun, Mon, Tue, Wed, Thu, Fri};

n aceast enumerare Sat este 0, Sun este 1, Elementele enumerrii pot fi iniializate suprascriind valorile implicite, astfel:
enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri};

n acest caz, secvena de elemente este forat s porneasc de la 1 n loc de 0. Fiecare tip enumerare care este folosit are un tip_dat pentru elementele sale. Dac nu se specific nici un tip_dat, atunci se presupune implicit tipul int. Specificarea unui tip_dat (care poate fi orice tip exceptnd tipul char, se face prin enunarea tipului_dat dup numele enumerrii. Declararea unui tip enumerare este de forma:
enum [Nume_tip] [: Tip_dat] { [identificator1][=valoare], ... [identificatorn][=valoare]}

Exemplu:
enum MyEnum : byte { triunghi, cerc }

Valoarea fiecrei variabile poate fi specificat explicit:


enum { a = b = c = } Values 45, 23, a + b

Exemplu:
using System; namespace tipulEnum { class Program { enum lunileAnului { Ianuarie = 1, Februarie, Martie, Aprilie, Mai, Iunie, Iulie, August, Septembrie, Octombrie, Noiembrie, Decembrie } static void Main() { Console.WriteLine("Luna Mai este a {0}", (int)lunileAnului.Mai + "-a luna din an.");

33

Console.WriteLine("Luna August este a {0}", (int)lunileAnului.August + "-a luna din an."); Valoarea lui i in acest ciclu este:Console.ReadLine(); } } }

De observat c un element din lista de enumerri poate fi accesat astfel:


NumeEnum.NumeElement

Tipurile enumerare pot fi convertite ctre tipul lor de baz i napoi, folosind o conversie explicit (cast):
enum Values { a = 1, b = 5, c = 3 } class Test { public static void Main() { Values v = (Values)3; int ival = (int)v; } }

Exemplu
using System; public class EnumTest { enum Days {Sat=1, Sun, Mon, Tue, Wed, Thu, Fri}; static void Main() { int x = (int)Days.Sun; int y = (int)Days.Fri; Console.WriteLine("Sun = {0}", x); Console.WriteLine("Fri = {0}", y); Console.ReadLine(); } }

4.2 Tipul tablou


Tipul tablou (Array) reprezint o colecie de valori de acelai tip. Tipul Array este un tip referin, fiecare array este un obiect motenit din clasa de baz System.Array. Tipul Array se declar astfel: <tip_dat>[] <nume_variabil>; Prin aceast declaraie nu se aloc spaiu pentru memorare. Pentru a putea reine date n structura de tip tablou, este necesar o operaie de instaniere:
nume = new tip_dat[NumarElemente];

34

Se reamintete c instanierea este procesul de creare a unui obiect i iniializarea sa cu date specifice. Declararea, instanierea i chiar iniializarea tabloului se pot face n aceeai instruciune. Exemplu:
int[] v = new int[] {1,2,3}; sau int[] v = {1,2,3}; //new este implicit

Dimensiunea unui tablou trebuie fixat i definit naintea utilizrii acestuia:


int size = 10; int[] integers = new int[size];

Opional, un tablou se poate declara i iniializa n pai separai:


int[] integers; integers = new int[10];

Exemplu de declarare i iniializare a unui vector cu cinci elemente:


int [] integers = {1, 2, 3, 4, 5};

Accesarea valorilor stocate ntr-un tablou. Pentru a accesa elementele unui tablou, se folosete operatorul de indexare [int index]. Vom folosi acest index pentru a indica elementul din tablou pe care vrem sa-l accesm. Este important de reinut ca valoarea indexului n C# pornete de la 0. Urmtorul cod de program demonstreaz cum poate fi accesat al treilea element al unui tablou:
int [] intArray = {5, 10, 15, 20}; int j = intArray[2];

Urmtorul cod de program prezint declararea, iniializarea i parcurgerea unui tablou:


using System; namespace UtilizareTablou { class DemoArray { // demonstreaz utilizarea arrays n C# static void Main() { // declararea i iniializarea unui array de ntregi int[] integers = { 3, 7, 2, 14, 65 }; // parcurgerea tabloului i afiarea fiecrui element pe ecran for (int i = 0; i < 5; i++) Console.WriteLine(integers[i]); Console.ReadLine(); } } }

n cazul tablourilor cu mai multe dimensiuni se face distincie ntre tablouri regulate i tablouri neregulate (tablouri de tablouri). Declararea n cazul tablourilor regulate bidimensionale se face astfel: Tip_dat[,] nume; Instanierea: nume = new Tip_dat[Linii,Coloane]; 35

Acces: nume[indice1,indice2] Exemple:


int[,] mat = new int[,] {{1,2,3},{4,5,6},{7,8,9}}; int[,] mat = {{1,2,3},{4,5,6},{7,8,9}};

sau

Declarare n cazul tablourilor neregulate bidimensionale: Tip[][] nume; Intaniere:


nume = new Tip[NrLinii],[]; nume[0]=new Tip[NrColoane1] ... nume[NrLinii-1]=new Tip[NrColoaneLinii-1]

Acces: nume[indice1][indice2] Exemple:


int[][] mat = new int[][] { new int[3] {1,2,3}, new int[2] {4,5}, new int[4] {7,8,9,1} };

sau
int[][] mat={new int[3] {1,2,3},new int[2] {4,5},new int[4] {7,8,9,1}};

4.3 Conversii numerice.


n C# exist dou tipuri de conversii numerice: implicite explicite. Conversia implicit se efectueaz (automat) doar dac nu este afectat valoarea convertit. Exemplu:
using System; namespace Conversii { class Program { static void Main() { byte a = 13; // byte ntreg fr semn pe 8 bii byte b = 20; long c; //ntreg cu semn pe 64 bii c = a + b; // conversie Console.WriteLine(c); } } }

Regulile de conversie implicit sunt descrise de tabelul urmtor:

36

Din sbyte byte short ushor t int uint long char float ulong

n short, int, long, float, double, decimal short, ushort, int, uint, long, ulong, float, double, decimal int, long, float, double, decimal int, uint, long, ulong, float, double, decimal long, float, double, decimal long, ulong, float, double, decimal float, double, decimal ushort, int, uint, long, ulong, float, double, decimal double float, double, decimal

Conversia explicit se realizeaz prin intermediul unei expresii cast, atunci cnd nu exist posibilitatea unei conversii implicite. n urma rulrii programului:
using System; namespace Conversii1 { class Program { static void Main(string[] args) { int a = 5; int b = 2; float c; c = (float)a / b; //operatorul cast Console.WriteLine("{0}/{1}={2}", a, b, c); Console.ReadLine(); } } }

se obine:
5/2 = 2.5

n cazul n care nu s-ar fi folosit operatorul cast rezultatul, evident eronat, ar fi fost: 5/2=2. Regulile de conversie explicit sunt descrise de tabelul urmtor: Din n sbyte byte, ushort, uint, ulong, char byte sbyte, char short sbyte, byte, ushort, uint, ulong, char ushort sbyte, byte, short, char int sbyte, byte, short, ushort, uint, ulong, char uint sbyte,byte, short, ushort, int, char long sbyte, byte, short, ushort, int, uint, ulong, char ulong sbyte, byte, short, ushort, int, uint, long, char char sbyte, byte, short float sbyte, byte, short, ushort, int, uint, long, ulong, char, decimal double sbyte, byte, short, ushort, int, uint, long, ulong, char, float, decimal decimal sbyte, byte, short, ushort, int, uint, long, ulong, char, float, double Conversii ntre numere iruri de caractere. 37

n limbajul C# exist posibilitatea efecturii de conversii ntre numere iruri de caractere. Pentru conversia invers, adic din ir de caractere n numr, sintaxa este:
ir int int.Parse(ir) sau Int32.Parse(ir) ir long long.Parse(ir) sau Int64.Parse(ir) ir double double.Parse(ir) sau Double.Parse(ir) ir float float.Parse(ir) sau Float.Parse(ir)

Observaie: n cazul n care irul de caractere nu reprezint un numr valid, conversia din ir n numr va eua. Exemplu:
using System; namespace Conversii { class Program { static void Main() { string s; const int a = 13; const long b = 100000; const float c = 2.15F; double d = 3.1415; Console.WriteLine("CONVERSII\n"); Console.WriteLine("TIP\tVAL. \tSTRING"); Console.WriteLine(""); s = "" + a; Console.WriteLine("int\t{0} \t{1}",a,s); s = "" + b; Console.WriteLine("long\t{0} \t{1}",b,s); s = "" + c; Console.WriteLine("float\t{0} \t{1}",c,s); s = "" + d; Console.WriteLine("double\t{0} \t{1}",d,s); Console.WriteLine("\nSTRING\tVAL \tTIP"); Console.WriteLine(""); int a1; a1 = int.Parse("13"); Console.WriteLine("{0}\t{1}\tint","13",a1); long b2; b2 = long.Parse("1000"); Console.WriteLine("{0}\t{1}\tlong","1000",b2); float c2; c2 = float.Parse("2,15"); Console.WriteLine("{0}\t{1}\tfloat","2,15",c2); double d2; d2 = double.Parse("3.1415"); Console.WriteLine("{0}\t{1}\tdouble","3.1415",d2); Console.ReadLine(); } } }

38

CAPITOLUL V. CLASE NOIUNI DE BAZ


5.1 Clasele. Noiuni de baz
Tipul clas (class) este cel mai important dintre tipurile definite de utilizator, n C#. Clasele sunt tipuri referin definite de utilizator i reprezint o mulime ncapsulat de date i funcii dependente logic, care n general modeleaz obiecte din lumea real sau conceptual. Clasa grupeaz datele i metodele (funciile) de prelucrare a acestora ntr-un modul, unindu-le astfel ntr-o entitate mult mai natural. Dei tehnica se numete "Programare Orientat Obiect", conceptul de baza al ei este clasa. Clasa, pe lng faptul c abstractizeaz foarte mult analiza/sinteza problemei, are proprietatea de generalitate, ea desemnnd o mulime de obiecte care mpart o serie de proprieti. Clasa "floare", de exemplu, desemneaz toate plantele care au flori, precum clasa "Fruct" desemneaz toate obiectele pe care noi le identificam ca fiind fructe. Bineneles, n implementarea efectiv a programului nu se lucreaz cu entiti abstracte, precum clasele ci se lucreaz cu obiecte, care sunt "instanieri" ale claselor. Altfel spus, plecnd de la exemplul de mai sus, dac se construiete un program care s lucreze cu clasa fructe, el nu va prelucra entitatea "fruct" ci va lucra cu entiti concrete ale clasei "fruct", adic "afin", "cirea", "zmeur", etc. Instanierea (trecerea de la clas la obiect) nseamn atribuirea unor proprieti specifice clasei, astfel nct aceasta s indice un obiect anume, care se difereniaz de toate celelalte obiecte din clas printr-o serie de atribute. Dac clasa fruct conine caracteristicile: zon, gust, i culoare, atunci vom considera fructul "zmeur" se gsete n zonele mpdurite, de culoare roz i gust dulce-acrior. Fructul zmeur individualizeaz clasa fruct, astfel c ajungem la un caz concret, care este obiectul. O instan a unui tip de date abstract este o concretizare a tipului respectiv, format din valori efective ale datelor. O instan a unui tip obiectual poart numele de obiect. Membrii unei clase sunt mprii n urmtoarele categorii: constante cmpuri metode proprieti evenimente indexatori operatori constructori (de instan) destructor constructor static tipuri O clas este o structur de date care poate stoca date i executa cod de program. n continuare sunt descrii:

39

Membrii de tip dat (Data members), care stocheaz date asociate clasei sau instane ale clasei. Membrii de tip dat, modeleaz, n general, atributele lumii reale, pe care clasa vrea s o reprezinte. Membrii de tip funcie (Function members), care execut cod de program. Membrii de tip funcie modeleaz, n general, funcii i aciuni ale obiectelor din lumea real, pe care clasa vrea s le reprezinte. Un program care ruleaz este o mulime de obiecte care interacioneaz unul cu cellalt. Declararea claselor. Declararea unei clase definete caracteristicile i metodele unei noi clase. Aceasta nu creeaz o instan a clasei, dar creeaz un ablon pe baza cruia se vor crea instanele clasei. Urmtorul exemplu folosete sintaxa minim pentru crearea unei clase:
cuvnt cheie numele clasei

class ExerciiuClas { DeclaraiiDeMembrii }

ntre cele dou acolade sunt declarai membrii clasei care formeaz, n acelai timp, corpul clasei. Membrii unei clase pot fi declarai n orice ordine n interiorul corpului clasei. 5.2 Cmpuri Cmpurile(fields) i metodele(methods) fac parte din tipurile cele mai importante de membrii ai unei clase. Un cmp este o variabil care aparine unei clase. Acesta poate fi de orice tip: predefinit sau definit de utilizator. Asemenea variabilelor, cmpurile stocheaz date, i au urmtoarele caracteristici: Sintaxa minimal pentru declararea unui cmp este:
tip

Type Identifier;

Nume cmp

De exemplu, urmtoarea clas conine declaraia cmpului CmpulMeu, care poate stoca o valoare ntreag:
class MyClass {

tip

int CmpulMeu;

Nume tip

Iniializarea explicit i implicit a cmpurilor ntruct un cmp este un tip de variabil, sintaxa pentru iniializarea unui cmp este aceeai cu cea de la variabile.

40

class MyClass { int F1 = 17; }

Iniializarea cmpului

Pentru fiecare cmp declarat se va asigna o valoare implicit astfel: numeric: 0 bool: false char: \0 enum: 0 referin: null Exemplu:
class MyClass { int F1; // Iniializat cu 0 tip valoare string F2; // Iniializat cu null tip referin int F3 = 25; // Iniializat cu 25 string F4 = "abcd"; // Iniializat cu "abcd" }

Acelai exemplu poate fi scris i:


class MyClass { int F1, F3 = 25; string F2, F4 = "abcd"; }

Un astfel de cmp se poate folosi fie prin specificarea numelui su, fie printr-o calificare bazat pe numele clasei sau al unui obiect. Exemplu:
using System; class Access { //Variabile declarate nafara funciei Main. int x = 100; int y = 200; public static void Main() { //crearea obiectului Access a = new Access(); //apelul variabilelor instaniate Console.WriteLine(a.x); Console.WriteLine(a.y); Console.ReadLine(); } }

5.3 Metode
O metod este un nume de bloc de cod executabil care poate fi executat din diferite pri ale unui program, chiar i din alte programe. Atunci cnd o metod este apelat (invocat), aceasta 41

execut codul din corpul su, dup care red controlul mai departe programului din care a fost apelat. Unele metode returneaz o valoare n poziia n care au fost apelate. Metodele corespund funciilor membre din C++. Sintaxa minim necesar declaraiei unei metode include urmtoarele componente: Tipul returnat (Return type): tipul valorii returnate de metod. n cazul n care metoda nu returneaz o valoare, tipul returnat este void; Numele (name): reprezint numele metodei; Lista parametrilor (Parameter list): aceasta const din cel puin un set de paranteze deschise (). Dac exist parametrii acetia sunt prezentai ntre paranteze; Corpul metodei (Method body): conine cod executabil inclus ntre dou acolade {}. Exemplu:
class SimpleClass { Tipul returnat Lista de parametrii void PrintNums ( ) { Console.WriteLine("1"); Console.WriteLine("2"); } }

5.3.1 Structura unei metode


n esen o metod este un bloc de cod care are un nume i care poate fi apelat prin acesta. Se pot transmite date ntr-o metod i se pot prelua date de la o metod. O metod este un membru de tip funcie al clasei n care este definit. Orice metod este compus din dou pri: antetul metodei n care se specific caracteristicile metodei cum sunt: o dac metoda returneaz o valoare iar n caz afirmativ care este tipul acesteia, o numele metodei, o ce tip de date sunt transmise metodei. corpul metodei care conine secvene de instruciuni (cod executabil). Execuia instruciunilor pornete de la prima i se continu secvenial prin corpul metodei.

Figura 6. Structura unei metode

Structura antetului unei metode este:


int MyMethod ( int intpar1, string strpar1 )

Tipul Numele returnat metodei

Lista de parametrii

42

5.3.2 Variabile locale


Asemenea cmpurilor, variabilele locale pot stoca date. n timp ce cmpurile unui obiect stocheaz, de obicei, starea unui obiect, variabilele locale sunt folosite pentru calcule locale sau tranzitorii. Urmtoarele linii de cod reprezint sintaxa declaraiei unei variabile locale:
Numele variabilei

Iniializarea opional

Type Identifier = Value;

existena unei variabile locale este limitat la blocul n care a fost declarat, i la blocurile coninute n acesta. variabil local poate fi declarat n orice poziie n corpul unei metode. Urmtorul exemplu ilustreaz declararea i utilizarea a dou variabile locale. Prima este de tip ntreg iar a doua de tip clas SomeClass:
static void Main( ) { int myInt = 15; SomeClass sc = new SomeClass(); ... }

Urmtorul tabel face o comparaie ntre variabilele locale i instana cmpurilor. Instana unui cmp Variabila local Exist n momentul crerii instanei. Exist din momentul n care este Timpul de nceteaz s mai existe atunci cnd declarat. nceteaz n momentul n care via nu mai este accesat ntregul bloc a fost executat. Iniializare Este iniializat cu valoarea implicit Nu sunt iniializate implicit. implicit a tipului Toate cmpurile unei clase sunt Tipul valoare este stocat n memoria Zona de stocate n memoria de tip heap, stack iar tipul referin este stocat n stocare indiferent de tipul acestora. stack i datele n heap. 5.3.3 Cuvntul cheie var ncepnd cu versiunea C# 3.0 se poate utiliza cuvntul cheie var n locul declaraiei tipului unei variabile locale, aa cum se vede n exemplul urmtor:
static void Main( ) { int total = 15; MyExcellentClass mec = new MyExcellentClass(); ... }

este echivalent cu:


static void Main( ) {Keyword var total = 15; var mec = new MyExcellentClass(); ...

43

Cteva condiii importante n utilizarea cuvntului cheie var sunt: poate fi folosit doar la declararea variabilelor locale nu poate fi folosit la declararea cmpurilor unei clase; poate fi folosit numai atunci cnd declararea variabilelor locale include i iniializarea acestora; odat ce compilatorul a determinat tipul variabilelor, acesta nu mai poate fi schimbat.

Vizibilitatea variabilelor locale n interiorul blocurilor imbricate Corpul metodelor poate conine mai multe blocuri imbricate. Variabilele locale pot fi declarate n interiorul blocurilor imbricate, i asemenea tuturor variabilelor locale, timpul acestora de via este limitat la blocul n care au fost definite i la blocurile coninute n acesta. Constantele locale Ciclul de via al constantelor locale este asigurat de aceleai reguli ca la variabilele locale. Sintaxa declaraiei constantelor locale este:
cuvnt cheie
const Type Identifier = Value;

iniializarea este obligatorie

5.3.4 Apelul unei metode


Se pot apela alte metode din corpul unei metode. O metod se poate apela utiliznd numele acesteia mpreun cu lista de parametrii. n urmtorul exemplu n clasa MyClass este declarat metoda PrintDateAndTime care este apelat n interiorul metodei Main.
class MyClass { void PrintDateAndTime( ) { DateTime dt = DateTime.Now; Console.WriteLine("{0}", dt); } static void Main() { MyClass mc = new MyClass(); mc.PrintDateAndTime( ); } } // Declararea metodei. // Det. datei i a orei curente. // Afiarea acesteia. // Declararea metodei principale.

// Apelarea metodei.

numele metodei

lista vid de parametrii

5.3.5 Valoarea returnat de o metod


O metod poate returna o valoare atunci cnd este apelat. Valoarea returnat este inserat n codul apelant n instruciunea n care este apelat metoda. Pentru a putea returna o valoare, trebuie declarat tipul acesteia naintea numelui metodei (la declararea metodei); Dac o metod nu returneaz o valoare, ea trebuie declarat de tip void (vid) 44

Urmtorul cod declar dou metode. Prima returneaz o valoare ntreag iar cea de-a doua o valoare vid. Tipul returnat
int GetHour() { ... } void DisplayHour() { ... }

Nu este returnat nici o valoare. O metod care are returneaz o valoare nevid trebuie s conin urmtoarea form a instruciunii return:
return Expression; // Returnarea unei valori.

Cuvnt cheie

Exemplu:
Tip returnat
int GetHour( ) { int a=1; int b=2; return a+b; }

Instruciunea return

O metod poate returna un obiect definit de programator. De exemplu, urmtorul cod returneaz un obiect de tip MyClass.
Tipul returnat -- MyClass
MyClass method3( ) { MyClass mc = new MyClass(); ... return mc; // returneaz un obiect de tip MyClass. }

Instruciunea return folosit i la metodele ce returneaz tipul void. Dintr-o metod ce returneaz tipul vid, se poate iei simplu prin utilizarea instruciunii return fr parametrii: return; Aceast form a instruciunii return poate fi folosit numai cu metodele declarate void. Execuia instruciunilor din corpul unei metode declarate void, se oprete atunci cnd este ntlnit instruciunea return.
Exemplu: Tipul returnat
void SomeMethod() { ... if ( Prima_condiie ) // Dac ... return; // controlul programului este returnat codului apelant. ...

45

if ( A_doua_condiie ) // Dac ... return; // controlul programului este returnat codului apelant. ... } // controlul programului este returnat codului apelant.

Urmtorul cod este un alt exemplu de utilizare a instruciunii return ntr-o metod declarat void:
class MyClass {

Returneaz tipul void


void TimeUpdate() { DateTime dt = DateTime.Now; // Obinerea datei i orei curente. if (dt.Hour < 12) // Dac ora este mai mic dect 12, return; // atunci return.

Return la metoda apelant.


Console.WriteLine("It's afternoon!"); // Altfel, afieaz mesaj. } static void Main() { MyClass mc = new MyClass(); // Creaz o instan a clasei. mc.TimeUpdate(); // Apelez metoda. } }

5.3.6 Parametrii unei metode


Parametrii formali sunt variabile locale declarate in lista de parametrii a metodei. Urmtoarea declaraie de metod ilustreaz sintaxa declaraiei de parametrii:
public void PrintSum( int x, float y ) { ... } Declararea parametrilor formali

Deoarece parametrii formali sunt variabile locale, acetia au un tip i un nume. Parametrii formali sunt definii nafara corpului metodei i iniializai naintea execuiei corpului metodei, excepie fcnd un anumit tip de parametrii care vor fi discutai n capitolele urmtoare. Numrul parametrilor formali poate fi orict, declaraiile acestora fiind desprite prin virgul. Parametrii formali sunt folosii n corpul metodei, la fel ca i variabilele locale. n exemplul urmtor, declaraia metodei PrintSum folosete doi parametrii formali, x, z i variabila local Sum, toate de tip int.

public void PrintSum( int x, int y ) { int Sum = x + y; Console.WriteLine("Newsflash: {0} + {1} is {2}", x, y, Sum); }

46

Parametrii actuali Atunci cnd programul apeleaz o metod, valorile parametrilor formali trebuie iniializai naintea execuiei codului metodei. Expresiile sau variabilele (cmpurile) folosite la iniializarea parametrilor formali se numesc parametrii actuali. Parametrii actuali sunt plasai n lista de parametrii ai metodei invocate. Exemplul urmtor ilustreaz invocarea metodei PrintSum, care are doi parametrii actuali de tip
int: PrintSum( 5, SomeInt );

Expresie Variabil de tip int

Atunci cnd o metod este apelat, valoarea fiecrui parametru actual este utilizat pentru iniializarea parametrului formal corespunztor. Figura urmtoare explic relaia dintre parametrii actuali i cei formali.

Figura 7. Relaia dintre parametrii actuali i cei formali

Atunci cnd este apelat o metod, trebuie ndeplinite urmtoarele condiii: Numrul parametrilor actuali trebuie s fie exact cu numrul parametrilor formali, cu o singur excepie care va fi discutat n capitolele urmtoare. Fiecare parametru actual trebuie s aib acelai tip cu parametrul formal corespunztor. Exemple:
class MyClass parametrii formali { public int Sum(int x, int y) // Declararea metodei. { return x + y; // Returneaz suma. } parametrii formali public float Avg(float Input1, float Input2) // Declararea metodei. { return (Input1 + Input2) / 2.0F; // Returneaz media. }

47

} class Class1 { static void Main() { MyClass MyT = new MyClass(); int SomeInt = 6; Console.WriteLine("Newsflash: Sum: {0} and {1} is {2}",5, SomeInt, MyT.Sum( 5,SomeInt )); // Invocarea metodei. parametrii actuali Console.WriteLine("Newsflash: Avg: {0} and {1} is {2}",5, SomeInt, MyT.Avg( 5, SomeInt )); // Invocarea metodei. } } parametrii actuali

Codul de mai nainte produce urmtoarea ieire:


Newsflash: Sum: 5 and 6 is 11 Newsflash: Avg: 5 and 6 is 5.5

Parametrii de tip valoare Acesta este un tip implicit de parametri numii i parametrii valoare. Atunci cnd se folosesc parametrii valoare, datele sunt transmise metodei prin copierea valorilor parametrilor actuali n parametrii formali. Atunci cnd o metod este apelat, sistemul parcurge paii urmtori: Aloc spaiu n stiv (stack) pentru parametrii formali Copiaz parametrii actuali n parametrii formali Un parametru actual al unui parametru valoare poate fi, pe lng variabil local, o expresie a crui tip se potrivete cu tipul parametrului valoare. Exemplu:
float func1( float Val ) // Declararea metodei. { ... }

dat de tip float


{ float j = 2.6F; float k = 5.1F;

variabil de tip float


float fValue1 = func1( k ); // Apelul metodei float fValue2 = func1( (k + j) / 3 ); // Apelul metodei ...

Expresie care evalueaz un tip real

Urmtorul cod de program prezint o metod denumit MyMethod, care are doi parametrii: o variabil de tip MyClass i o variabil de tip int:
class MyClass {

48

public int Val = 20; } class Program {

// Iniializeaz cmpul Val cu 20.

parametrii formali
static void MyMethod( MyClass f1, int f2 ) { f1.Val = f1.Val + 5; // Adun 5 la cmpul parametrului f1. f2 = f2 + 5; // Adun 5 la al doilea parametru. } static void Main( ) { MyClass A1 = new MyClass(); int A2 = 10; MyMethod( A1, A2 ); // Apelul metodei. }

parametrii actuali

Parametrii referin

Al doilea tip de parametrii folosii n lista de parametrii ai unei metode sunt parametrii referin. Atunci cnd se utilizeaz un parametru referin, trebuie folosit modificatorul ref att n declaraia metodei ct i n invocarea acesteia. Parametrii actuali trebuie s fie variabile (nu sunt admise valori sau expresii valorice) care trebuie s fie iniializate nainte s fie folosite ca parametrii actuali. Dac parametrii actuali sunt variabile de tip referin, atunci acestora trebuie s li se atribuie, fiecreia, o referin sau referina nul (null). Exemplul urmtor ilustreaz sintaxa declarrii i a invocrii unei metode cu parametrii referin.
include modificatorul ref
void MyMethod( ref int val ) // Declararea metodei { ... } int y = 1; // Variabila pentru parametrul actual MyMethod ( ref y ); // Apelul metodei

include modificatorul ref


MyMethod ( ref 3+5 ); // Error!

trebuie utilizat o variabil

Aa cum am vzut, n cazul parametrilor valoare sistemul aloc memorie n stiv (stack) pentru parametrii formali. Pentru parametrii referin exist urmtoarele caracteristici: Nu se aloc memorie n stiv pentru parametrii formali. n schimb, numele parametrilor formali acioneaz ca un alias pentru variabilele considerate parametrii actuali, referind aceeai locaie de memorie. ntruct numele parametrilor formali i numele parametrilor actuali refer aceeai locaie de memorie, este evident c orice schimbare fcut parametrilor formali, n timpul execuiei codului metodei respective, va avea efect dup execuia metodei, asupra variabilelor desemnate ca parametrii actuali. 49

Exemplu:
class MyClass { public int Val = 20; } // Iniializarea cmpului cu valoarea 20. class Program {

} }

modificatorul ref static void MyMethod(ref MyClass f1, ref int f2) { f1.Val = f1.Val + 5; // Adun 5 la cmpul parametrului f1. f2 = f2 + 5; // Adun 5 la al doilea parametru. } static void Main() { MyClass A1 = new MyClass(); int A2 = 10; MyMethod(ref A1, ref A2); // Apelul metodei. modificatori ref

modificatorul ref

Parametrii de ieire Parametrii de ieire sunt folosii pentru a transmite date dinuntrul unui metode, n codul apelant. Parametrii de ieire sunt asemntori cu parametrii referin, i au urmtoarele caracteristici: Atunci cnd se utilizeaz un parametru de ieire, trebuie folosit modificatorul out att n declaraia metodei ct i n invocarea acesteia. Parametrii actuali trebuie s fie variabile (nu sunt admise valori sau expresii valorice). n exemplul urmtor este declarat metoda MyMethod, care are un singur parametru de ieire:
modificatorul out
void MyMethod( out int val ) // Declaraia metodei { ... } ... int y = 1; // variabila utilizat ca parametru actual MyMethod ( out y ); // Apelul metodei modificatorul out

Asemenea parametrilor referin, parametrii formali ai parametrilor de ieire acioneaz ca aliasuri pentru parametrii actuali. Numele parametrilor formali i numele parametrilor actuali refer, fiecare n parte, aceeai locaie de memorie. Este evident faptul c orice aciune asupra parametrilor formali fcut n interiorul corpului metodei, va avea acelai efect asupra parametrilor actuali. Spre deosebire de parametrii referin, parametrii de ieire au urmtoarele caracteristici: 50

Unui parametru de ieire trebuie s i se atribuie o valoare, n corpul metodei, nainte ca acesta s fie folosit. Aceasta nseamn c valoarea iniial a parametrilor actuali este irelevant i, din aceast cauz, nu trebuie atribuite valori parametrilor actuali naintea apelului metodei. Fiecare parametru de ieire trebuie iniializat. Deoarece parametrii de ieire trebuie iniializai n corpul metodei, este inutil s fie transmise date (prin parametrii actuali) n corpul metodei. Utilizarea unui parametru de ieire naintea iniializrii acestuia produce eroare. Exemplu:
public void Add2( out int outValue ) { int v1 = outValue + 2; //Eroare!Utilizarea unui param de ieire naintea iniializrii acestuia produce eroare. }

Exemplu:
class MyClass { public int Val = 20; } // Iniializarea cmpului cu valoarea 20. class Program { static void MyMethod(out MyClass f1, out int f2, out int f3){ f1 = new MyClass(); // Crearea unui obiect al clasei. f1.Val = 25; // Atribuirea unui valori cmpului clasei. // f2 = f2 + 5; // Eroare !! f2 = 15; // eroare ! parametrul f3 nu este initializat } static void Main() { MyClass A1 = null; int A2, A3; MyMethod(out A1, out A2, out A3); // Apelul metodei. } }

Parametrii de tip vector Caracteristicile importante ale parametrilor de tip vector sunt: Poate exista numai un parametru de tip vector n lista de parametrii. Dac exist unul, acesta trebuie s fie ultimul parametru din list. Pentru a declara un parametru de tip vector trebuie: Utilizat modificatorul params naintea tipului de date. Trebuie plasat un set de paranteze drepte goale dup tipul de date. Antetul metodei prezentate n continuare prezint sintaxa pentru declararea unui parametru de tip vector de ntregi.
vector de ntregi
void ListInts( params int[] inVals ) { ...

modificator

numele parametrului

51

Apelul unei metode ce conine parametrii de tip vector. Un parametru actual de tip vector poate fi transmis unei metode n dou moduri: 1. Printr-o list de elemente de tipul specificat n declararea metodei, separate prin virgul: ListInts( 10, 20, 30 ); Aceast form se mai numete i forma expandat. 2. Printr-o variabil de tip vector:
int[] intArray = {1, 2, 3}; ListInts( intArray );

Aa cum se observ din exemplele date, la apelul metodei nu se utilizeaz modificatorul params. n exemplul urmtor se observ c apelul metodei ListInts poate fi fcut cu un numr variabil de elemente.
void ListInts( params int[] inVals ) { ... } // Declararea metodei ... ListInts( ); // 0 parametrii actuali ListInts( 1, 2, 3 ); // 3 parametrii actuali ListInts( 4, 5, 6, 7 ); // 4 parametrii actuali ListInts( 8, 9, 10, 11, 12 ); // 5 parametrii actuali

Atunci cnd se apeleaz o metod cu parametru vector n forma expandat, compilatorul face urmtoarele lucruri: Ia lista parametrilor actuali i o utilizeaz la crearea i iniializarea unui vector n memoria heap. Memoreaz referina ctre vector, n stiv n locaia parametrului formal. Dac nu exist nu exist parametrii actuali n poziia corespunztoare parametrului formal de tip vector, compilatorul creeaz un vector cu zero elemente. Exemplu:
class MyClass parametrii de tip vector { public void ListInts( params int[] inVals ) { if ( (inVals != null) && (inVals.Length != 0)) for (int i = 0; i < inVals.Length; i++) { inVals[i] = inVals[i] * 10; Console.WriteLine("{0} ", inVals[i]); } } } class Program { static void Main() { int first = 5, second = 6, third = 7; MyClass mc = new MyClass(); mc.ListInts( first, second, third );

parametrii actuali

52

Console.WriteLine("{0}, {1}, {2}", first, second, third); } }

Tabel cu sumarul tipurilor de parametrii


Tipul parametrului Valoare Referin De ieire De tip vector Modificator Nu ref out params Da Da Da Da Da Nu Utilizat la declarare Utilizat la invocare Implementare Compilatorul copiaz parametrii actuali in parametrii formali Parametrii formali devin alias ai parametrilor actuali Parametrii formali devin alias ai parametrilor actuali Este permis transmiterea ctre metod a unui numr variabil de parametrii actuali.

5.4 Crearea variabilelor i instanelor unei clase


Declararea unei clase este un ablon din care instanele clasei sunt create. Clasele sunt tipuri referin, i prin urmare necesit memorie att pentru referina la date ct i pentru datele actuale. Referina la date este stocat ntr-o variabil de tip class. Astfel, pentru a crea o instan a clasei, trebuie, pentru nceput, declarat o variabil de tip clas. Dac variabila nu este iniializat, valoarea sa este nedefinit. Alocarea memoriei pentru date Declararea unei variabile de tip clas aloc memorie pentru stocarea referinei, nu i pentru datele actuale ale obiectului instaniat din clas. Pentru a aloca memorie datelor actuale, trebuie utilizat operatorul de instaniere new. Operatorul new aloc i iniializeaz memorie pentru o instan a unui tip specificat. Acest operator aloc memorie din memoria de tip stack i memoria de tip heap, n funcie de tipul variabilei. Utilizarea operatorului de instaniere new pentru crearea unui obiect const din: Numele variabilei de tip clas; Semnul =; Cuvntul cheie new; Numele tipului de instan pentru care se aloc memorie; Parantezele deschise care pot sau nu s conin parametrii.
paranteze deschise

Cuvnt cheie

Nume_variabil = new TypeName( )

numele tipului

Dac alocarea memoriei este pentru un tip referin, expresia de creare a unui obiect returneaz o referin ctre locaia de memorie de tip heap, unde este alocat i iniializat instana.
Dealer theDealer; theDealer = new Dealer(); // Declararea variabilei pentru referin. // Alocarea memoriei pentru clasa obiect.

53

Expresia de creare a unui obiect

Declararea unei variabile de tip clas i iniializarea ei se pot face ntr-o singur declaraie:
Declararea variabilei
.

Dealer theDealer = new Dealer(); // Declarare i iniializare (instanierea).

Iniializare (instaniere) cu sintaxa de creare a unui obiect

5.5 Membrii unei instane


Declararea unei clase produce un ablon din care se vor putea crea instane ale clasei respective. Membrii instanei (Instance members): Fiecare instan a unei clase este o entitate separat care are propriul set de date membre, distincte fa de alt instan a aceleai clase. Acestea (datele membre) sunt denumite membrii instanei (instance members), deoarece sunt asociai instanei unei clase. Urmtorul exemplu ilustreaz un program cu trei instane ale clasei Player.
class Dealer { ... } //declararea clasei Dealer class Player { //declararea clasei Player string Name; // cmp ... } class Program { static void Main() { Dealer theDealer = new Dealer(); Player player1 = new Player(); Player player2 = new Player(); Player player3 = new Player(); ... } }

5.6 Modificatori de acces


Din interiorul unei clase, orice funcie membru poate accesa oricare alt membru al clasei, simplu prin numele membrului. Modificatorul de acces (access modifier) este o parte opional din declaraia unui membru, care specific care pri din program au acces la membru. Modificatorul de acces este plasat naintea declaraiei unui membru. Urmtoarele sintaxe sunt folosite pentru cmpuri i metode: Fields:
AccessModifier Type Identifier;

Methods:
AccessModifier ReturnType MethodName () { ... }

Acestor membri li se pot ataa urmtorii cinci modificatorii de acces: 54

private public protected internal protected internal

5.7 Accesul privat sau public


Membrii care au specificatorul de acces private sunt accesibili doar n clasa n care au fost declarai alte clase nu au acces la ei. Accesul de tip private este specificatorul implicit. Astfel, dac un membru este declarat fr un modificator de acces, acesta este un membru privat. De exemplu, urmtoarele dou declaraii specific membrii privai de tip ntreg:
int MyInt1; private int MyInt2; // Declarare implicit // Declarare explicit

Modificator de acces

Membrii care au specificatorul de acces public sunt accesibili tuturor obiectelor din program.
Modificator de acces

public int MyInt;

Exemplu de accesare a membrilor unei clase:


class C1 { int F1; private int F2; public int F3; void DoCalc() { ... } public int GetVal() { ... } } // // // // Cmp implicit privat Cmp declarat explicit privat Cmp declarat public Metod implicit privat

// Metod declarat public

Exemplu:
using System; class Access { //Variabile declarate nafara funciei Main. int x = 100; int y = 200; } class program { public static void Main() {

55

//Crearea unui obiect Access a = new Access(); //Apelul instantei variabilelor Console.WriteLine(a.x); // Eroare, x nu e declarat public Console.WriteLine(a.y); // Eroare, y nu e declarat public Console.ReadLine(); } }

Accesarea membrilor din interiorul unei clase Membrii unei clase pot fi accesai din interiorul acesteia utiliznd numele lor. n urmtorul exemplu metodele unei clase acceseaz cmpuri i alte metode ale aceleiai clase:
class DaysTemp { // Cmpuri private int High = 75; private int Low = 45; // Metode private int GetHigh() { return High; // Access private field } private int GetLow() { return Low; // Access private field } public float Average () { return (GetHigh() + GetLow()) / 2; // Accesarea metodelor private } } Accesarea metodelor private

Accesarea membrilor unei clase din afara acesteia Pentru a accesa din afara unei clase membrii publici ai acesteia, acetia trebuie apelai cu numele variabilei de tip clas separat cu punct de numele membrului.
DaysTemp myDt = new DaysTemp(); // Crearea unui obiect al clasei. float fValue = myDt.Average(); // Accesul din afara clasei.

numele variabilei

numele membrului

Urmtorul cod declar dou clase: DaysTemp i Program. Dou cmpuri ale clasei DaysTemp sunt declarate public, prin urmare acestea vor putea fi accesate din afara clasei. n corpul metodei Main sunt create o variabil i un obiect al clasei DaysTemp, dup care sunt atribuite valori cmpurilor obiectului.
using System; class DaysTemp // declararea clasei DaysTemp { public int High = 75; public int Low = 45; } class Program // declararea clasei Program. {

56

static void Main() { DaysTemp temp = new DaysTemp(); // crearea unui obiect. temp.High = 85; // atribuire de valori cmpurilor. temp.Low = 60; Console.WriteLine("High: {0}", temp.High ); // citirea valorii unui cmp. Console.WriteLine("Low: {0}", temp.Low ); Console.ReadLine(); } }

Urmtorul cod creeaz dou instane i stocheaz referina acestora n variabilele cu numele t1 i t2:
using System; class DaysTemp // declararea unei clase. { public int High, Low; // declararea cmpurilor. public int Average() // declararea unei metode. { return (High + Low) / 2; } } class Program { static void Main() { DaysTemp t1 = new DaysTemp(); DaysTemp t2 = new DaysTemp(); // scriere de valori n cmpurile fiecrei instane. t1.High = 76; t1.Low = 57; t2.High = 75; t2.Low = 53; // citirea valorilor cmpurilor fiecrei instane Console.WriteLine("t1: {0}, {1}, {2}", t1.High, t1.Low, t1.Average() ); Console.WriteLine("t2: {0}, {1}, {2}", t2.High, t2.Low, t2.Average() ); } }

57

58

CAPITOLUL VI. PROBLEME REZOLVATE


6.1 ALGORITMI ELEMENTARI
1. Interschimbai coninutul a dou numere de tip ntreg citite de la tastatur. Program
using System; namespace ConsoleApplication1 { class Program { static void Main() { int a, b, aux; Console.Write("Introduceti primul numr a= "); a = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr b= "); b = int.Parse(Console.ReadLine()); Console.WriteLine("a={0}, b={1}", a, b); aux = a; a = b; b = aux; //o alta versiune de interschimbare fara variabila suplimentara // a = a - b; b = a + b; a = b - a; Console.Write("Dupa interschimbare a={0}, b={1}",a,b); Console.ReadKey(); } } }

Analiza programului - pe prima linie n corpul funciei principale se declar trei variabile ntregi: a, b i aux ; - se foloseste de dou ori perechea de funcii Console.Write()/ int.Parse(Console.ReadLine()) pentru a afia un mesaj pe ecran i apoi pentru a citi cele dou valori ntregi de la tastatur, care vor fi depuse n variabilele a, respectiv b; deoarece numerele citite de la tastatur se introduc n valori de tip int, funcia de citire de la tastatur Console.ReadLine() trebuie nsoit de transformarea intrrii de tip String n int cu ajutorul funciei int.Parse(); - urmeaz trei instruciuni de atribuire, care mpreun formeaz metoda celor trei pahare"; - se afieaz rezultatul, folosind un apel de funcie Console.Write(); observm c se va tipri pe ecran att ir de caractere ct i dou secvene de tipul {}, care la tiprire se vor nlocui cu valorile din variabilele a, respectiv b; - urmeaz un apel al funciei Console.ReadKey() care va ine ecranul de Output vizibil pn la apsarea unei taste. n lipsa ei, acesta dispare imediat dup afiarea rezultatelor. Efect Primul numr: 15 Al doilea numr: 21 Dup interschimbare: a=21 b=15 59

2. S se rezolve ecuaia de gradul I de forma ax+b=0, cu coeficieni numere reale. Program


using System; namespace ConsoleApplication2 { class Program { static void Main() { float a, b, x; Console.Write("Introduceti a="); a = float.Parse(Console.ReadLine()); Console.Write("Introduceti b="); b = float.Parse(Console.ReadLine()); if (a == 0) if (b == 0) Console.WriteLine("Ecuatie nedeterm"); else Console.WriteLine("Ecuatie imposibila"); else { x = - b / a; Console.WriteLine("Solutia este x={0}",x); } Console.ReadKey(); } } }

Analiza programului n vederea realizrii unei rezolvri riguroase, nainte de a afla soluia banal x=-b/a, trebuiesc fcute nite teste asupra valorilor a i b. Astfel dac a=0 i b=0 avem de a face cu o ecuaie nedeterminat, iar dac a=0 i b0 avem de a face cu o ecuaie imposibil. Acestea sunt cazuri particulare care trebuiesc tratate. n cazul n care a0 se poate extrage soluia dup formula cunoscut x=-b/a, iar aceast soluie este tiprit i pe ecran cu ajutorul funciei Console.WriteLine(). Pentru a avea instrumentele necesare calculului, n prim faz se vor citi de la tastatur valorile reale a i b, dup care se trece la gsirea soluiei. Se observ ca pentru raionamentul enunat mai sus, au fost folosite n program dou instruciuni if-else cu ajutorul crora se testeaz valorile lui a i b. 3. S se rezolve o ecuaie de gradul II de forma ax2+bx+c=0, cu coeficieni numere reale. Program
using System; namespace ConsoleApplication3 { class Program { static void Main() { float a, b, c, delta; double x1, x2;

60

Console.Write("Introduceti a="); a = float.Parse(Console.ReadLine()); Console.Write("Introduceti b="); b = float.Parse(Console.ReadLine()); Console.Write("Introduceti c="); c = float.Parse(Console.ReadLine()); if (a == 0) if (b == 0) if (c==0) Console.WriteLine("Ecuatie nedet."); else Console.WriteLine("Ecuatie imposibila"); else { x1 = -c / b; Console.WriteLine("Ecuatia este de gradul 1 cu x1={0}", x1); } else { delta = b * b - 4 * a * c; if (delta < 0) Console.WriteLine("Ec. are solutii complexe"); else { if (delta == 0) { x1 = x2 = -b / (2 * a); Console.WriteLine ("x1=x2={0}", x1); } else { x1 = (-b + Math.Sqrt(delta)) / (2 * a); x2 = (-b - Math.Sqrt(delta)) / (2 * a); Console.WriteLine("Solutiile sunt x1={0}, x2={1}", x1, x2); } } } Console.ReadKey(); } } }

Analiza programului n vederea realizrii unei rezolvri riguroase, nainte de a afla soluia banal dat de formula x1,2=(-b )/(2*a), unde =b2-4ac, trebuiesc fcute nite teste asupra valorilor a, b, c. Se detecteaz urmtoarele situaii: - dac a=0, b=0, c=0 avem de-a face cu o ecuaie nedeterminat - dac a=0, b=0, c0 aveam de-a face cu o ecuaie imposibil - dac a=0, b0, iar c are orice valoare, avem de-a face cu o ecuaie de gradul I, situaie n care exist o singur soluie x=-c/b Acestea sunt cazuri particulare care trebuiesc tratate. - dac a0, iar b i c au orice valoare, avem de-a face cu o ecuaie de gradul II, situaie n care se poate trece la calculul lui . Urmeaz acum o alt discuie dup valoarea lui . Astfel: - dac <0 avem de-a face cu soluii complexe (pe care n aceast rezolvare nu le vom mai 61

calcula ci vom afia doar un mesaj) - dac =0 ecuaia are dou soluii egale: x1,2=-b/(2*a) - dac >0 ecuaia are dou soluii diferite: x1,2=(-b )/(2*a) Se observ c pentru raionamentul enunat mai sus, au fost folosite n program trei instruciuni if-else imbricate (if inclus n alt if) cu ajutorul crora se testeaz valorile lui a, b i c. Puin atenie trebuie acordat expresiilor -b/(2*a) i (-b )/(2*a) deoarece lipsa parantezelor din aceste expresii poate duce la rezultate greite. Erorile pot aprea din cauz c n aceste expresii apar operatorii * i / care au aceeai prioritate. Astfel, n lipsa vreunei paranteze ei sar executa n ordinea n care apar n expresie, lucru care nu este de dorit n acest caz. 4. Scriei un program care primete la intrare un numr de secunde i ntoarce numrul maxim de ore, de minute, de secunde care este echivalent ca timp. Exemplu: 7384 secunde este echivalent cu 2 ore, 3 minute i 4 secunde. Program
using System; namespace ConsoleApplication4 { class Program { static void Main() { int secunde, h, m, s; Console.Write("Introduceti numrul de secunde : "); secunde = int.Parse(Console.ReadLine()); m = secunde / 60; s = secunde % 60; h = m / 60; m = m % 60; Console.Write("{0} secunde",secunde); Console.Write("reprez {0} ore, {1} minute i {2} secunde", h, m, s); Console.ReadKey(); } } }

Analiza programului Aceast problem este una simpl care implic cteva calcule. Astfel, n prima faz se calculeaz cte minute reprezint secundele date de problem. Restul mpririi secundelor iniiale la 60 reprezint cte secunde nu pot forma un minut ntreg (s). Minutele obinute se mpart i ele la 60 pentru a afla cte ore reprezint acele minute (h). Restul mpririi minutelor la 60 reprezint cte minute nu pot forma o or ntreag (m). 5. Scriei un program care simuleaz un calculator electronic pentru numere ntregi: se introduc dou numere ntregi i o operaie care poate fi +, -, *, /, reprezentnd adunarea, scderea, nmulirea i ctul. Program
using System; namespace ConsoleApplication5 { class Program {

62

static void Main() { int a,b,rez = 0; char op; short ok = 1; Console.Write("Primul numr : "); a = int.Parse(Console.ReadLine()); Console.Write("Al doilea numr : "); b = int.Parse(Console.ReadLine()); Console.Write("Operatia dorita (+ - * /) : "); op = char.Parse(Console.ReadLine()); switch (op) { case '+': rez = a + b; break; case '-': rez = a - b; break; case '*': rez = a * b; break; case '/': if (b != 0) rez = a / b; else { Console.WriteLine("Impartire la 0!"); Console.ReadKey(); return; } break; default: ok = 0; break; } if (ok == 1) Console.WriteLine("{0} {1} {2} = {3}", a, op, b, rez); else Console.WriteLine("Operator invalid"); Console.ReadKey(); } } }

Analiza programului - se declar numerele ntregi a, b i rez de tip int, reprezentnd operanzii i rezultatul; - se declar caracterul op de tip char, reprezentnd operaia care se va executa; - se declar variabila ok de tip short, care va rmne l dac operaia se termin cu succes, altfel i se va atribui 0 ; - avnd n vedere ca va trebui s comparm valoarea reinut de variabila op cu mai multe valori, folosim instruciunea de selecie switch. Avem 4 ramuri case, una pentru fiecare din valorile +, -, *, / i ramura default pentru cazurile n care op are orice alt valoare nafara celor 4 enumerate anterior, moment n care ok ia valoarea 0. n cazul n care op are una din valorile +, -, *, se efectueaz operaia corespunztoare, iar rezultatul se depune n variabila rez. n cazul n care op are valoarea /, prima dat se va testa cu ajutorul unei instruciuni if, valoarea celui de-al doilea operand, deoarece dac el este 0, mprirea nu se poate realiza, caz n care se va afia pe ecran un mesaj corespunztor. Dac valoarea lui b este diferit de 0, se procedeaz ca i n cazul operaiilor +, -, *. La final, n cadrul unei instruciuni if se testeaz valoarea variabilei ok. Dac ok a rmas l, atunci se va afia operaia efectuat mpreuna cu rezultatul, altfel se va tipri un mesaj c operatorul introdus de la tastatur nu este unul valid. 63

Efect Caz 1: Primul numr: 15 Al doilea numr: 27 Operatia dorita (+ - * /): + 15 + 27 = 42 Caz 2: Primul numr: 23 Al doilea numr: 0 Operatia dorita (+, -, *, /): / Impartire la 0 ! Caz 3: Primul numr: 38 Al doilea numr: 2 Operatia dorita (+, -, *, /): & Operator invalid! 6. nmulirea a dou numere naturale prin adunri repetate. Program
using System; namespace ConsoleApplication6 { class Program { static void Main() { int a, b, produs=0; Console.Write("Introduceti a="); a = int.Parse(Console.ReadLine()); Console.Write("Introduceti b="); b = int.Parse(Console.ReadLine()); for (int i = 1; i <= b; i++) produs += a; Console.WriteLine("{0} * {1} = {2}", a, b, produs); Console.ReadKey(); } } }

Analiza programului Se tie nc din clasele elementare c nmulirea nseamn de fapt nite adunri repetate. Astfel, a*b nseamn a adunat de b ori sau b adunat de a ori. Deoarece se tie c a trebuie adunat de exact b ori pentru a se obine rezultatul dorit, se utilizeaz instruciunea for care are un numr determinat de pai (de cte ori se repet un set de instruciuni). Valoarea a se adun se b ori n variabila p, care la final va conine rezultatul cutat (a*b). Variabila produs este iniializat cu 0 dup care i se va aduga n cadrul instruciunii for cte un a.

64

7. mprirea a dou numere prin scderi repetate. Program


using System; namespace ConsoleApplication7 { class Program { static void Main() { int a, b, a1 = 0, c=0, r=0; Console.Write("Introduceti a="); a = int.Parse(Console.ReadLine()); Console.Write("Introduceti b="); b = int.Parse(Console.ReadLine()); a1 = a; while (a1 >= b) { a1 -= b; //a1=a1-b; c++; } r = a1; Console.WriteLine("{0}:{1}={2} rest {3}", a, b, c, r); Console.ReadKey(); } } }

Analiza programului Se tie nc din clasele elementare c mprirea nseamn de fapt nite scderi repetate. Astfel, a:b nseamn b sczut de c ori i este posibil s existe i un rest[0, b-1]. Nu se tie de cte ori se va scdea b din a, acest lucru se va afla doar la final, de asemenea i eventualul rest. n acest sens, pentru a repeta scderea se va utiliza o instruciune repetitiv cu numr necunoscut de pai i anume while. Condiia ca scderea s se mai repete este ca a>=b. De fiecare dat cnd se mai face o scdere se va incrementa variabila c, care n final va reprezenta ctul. Valoarea care rmne n final n a reprezint restul. Variabilele c i r se iniializeaz cu 0, urmnd ca la final s conin ctul (obinut n cadrul ciclului while) i restul mpririi. Deoarece valoarea lui a se altereaz n timpul calculului, dac se dorete se poate face o copie a sa nainte de a intra n ciclul while. 8. S se ghiceasc un numr ntreg din intervalul 1 100. Program
using System; namespace ConsoleApplication8 { class Program { static void Main() { Random sol = new Random();//generam un numr int solutie = sol.Next(100);//aleator ca i solutie int n; do

65

{ Console.Write("Dati un numr intre 0 i 100: "); n = int.Parse(Console.ReadLine()); if (n < solutie) Console.WriteLine("Numrul e prea mic!"); else if (n == solutie) { Console.WriteLine(); Console.WriteLine("BRAVO! Ati ghicit!"); } else Console.WriteLine("Numrul e prea mare!"); } while (n != solutie); Console.ReadKey(); } } }

Analiza programului Acesta este un exemplu de utilizare a instruciunii repetitive do-while cu numr nedeterminat de pai. Se seteaz din program o valoare din intervalul 0-100 (n variabila soluie) care urmeaz s fie ghicit de ctre utilizator pe baza indicaiilor mai mare sau mai mic pe care le va primi. Pentru generarea numerelor aleatoare s-a creat un obiect sol din clasa Random dup care s-a generat un numr aleator din intervalul 0-100 cu ajutorul metodei Next, valoare care a fost atribuit variabilei soluie. Atta timp ct soluia nu este ghicit, dac se introduce de la tastatur o valoare mai mic dect soluia se va afia mesajul Numrul e prea mic, altfel se va afia mesajul Numrul e prea mare, iar dac se ghicete se va afia mesajul BRAVO! Ati ghicit ! i programul se ncheie. 9. S se calculeze n!=1*2*3**n (factorialul lui n), pentru un n natural citit de la tastatur. Program
using System; namespace ConsoleApplication9 { class Program { static void Main() { short n, i; long fact=1; Console.Write("Introduceti n="); n=int.Parse(Console.ReadLine()); for (i = 1; i <= n; i++) fact *= i; //fact = fact * i; Console.WriteLine("{0}! = {1}", n, fact); Console.ReadKey(); } } }

66

Analiza programului n! nseamn nmulirea tuturor numerelor naturale de la 1 pn la n. Aceasta nseamn c trebuiesc parcurse toate valorile de la 1 la n i trebuiesc nmulite. Pentru aceasta este potrivit instruciunea for cu limitele 1 i n. La fiecare pas al lui for o valoare i din intervalul [1,n] va fi nmulit la fact. Variabila fact este iniializat cu 1 i la final, n urma nmulirilor repetate va conine valoarea factorialului lui n. Deoarece factorialul are o cretere foarte rapid, variabila fact a fost declarat de tip long (cel mai mare interval de numere ntregi din C#). 10. Calculai suma cifrelor unui numr natural dat cu maximum 9 cifre. Raionament Pentru a rezolva aceast problem trebuie s ne folosim de uneltele de care dispunem pn n acest moment. Problema care se pune este cum s obinem cifrele individuale ale numrului dat. O modalitate simpl i usor de implementat este de a ncepe ruperea numrului n cifre ncepnd cu cea mai din dreapta (cea mai nesemnificativ), fapt care se poate realiza calculnd restul mpririi la 10 a numrului dat. n acest fel se face primul pas. Trebuiesc ns obinute toate cifrele numrului, n vederea nsumrii lor. Acest lucru l vom realiza n acelai mod n care am obinut prima cifr i anume: dup obinerea primei cifre, vom mpri numrul dat la 10; aceast operaie va avea ca i efect pierderea ultimei cifre din numrul iniial. n continuare, pentru numrul nou obinut calculm restul mpririi la 10 i vom obine ca i mai sus, ultima cifr a sa, pe care o vom aduga-o la sum. Dac mergem puin napoi vom observa c aceast a dou cifr obinut reprezint de fapt penultima cifr a numrului iniial. Vom continua acest raionament de mprire a numerelor i de adugare a ultimei cifre la suma pn cnd la o mprire la 10 vom obine ctul 0. n acel moment vom ti suma tuturor cifrelor numrului iniial. Program
using System; namespace ConsoleApplication10 { class Program { static void Main() { int n, m, suma = 0; Console.Write("Dati un numr de maxim 9 cifre : "); n = int.Parse(Console.ReadLine()); m = n; while (m != 0) { suma += m % 10; // suma=suma+m%10; m /= 10; // m=m/10; } Console.WriteLine("Suma cifrelor lui {0} este {1}", n, suma); Console.ReadKey(); } } }

Analiza programului - pe prima linie sunt declarate variabilele m i n de tip ntreg i variabila s, n care vom calcula suma cifrelor lui n (observam iniializarea acesteia de la declarare cu 0, deoarece nsumarea cifrelor 67

se va face pornind de la 0); - citirea de la tastatur numrului n; - lui m i se atribuie variabila n, pentru a nu pierde valoarea n; aceasta este o tehnica utilizata ntotdeauna cnd avem de modificat valoarea reinut de o variabila, ns nu dorim sa pierdem valoarea iniial. Dac nu am folosi atribuirea m=n, am mprit variabila n la 10 pn cnd valoarea acesteia ar deveni 0 i evident nu am mai ti care a fost valoarea iniial. Utiliznd nsa atribuirea m=n, valoarea lui n rmne nealterata. - urmeaz o instruciune while care conine dou instruciuni de atribuire compus (n prima se adaug la s ultima cifr a lui m, iar n a dou se trunchiaz m de ultima cifr); aceste instruciuni se repet pn cnd m va avea valoarea 0 ; - se afieaz rezultatul folosind o funcie Console.WriteLine(); se vor afia valorile reinute de variabilele n i s. Efect Introducei numrul: 247 Suma cifrelor lui 247 este 13. Exemplu de funcionare pas cu pas a programului Sa consideram ca n=247 Urmrind linie cu linie programul de mai sus vom obine: s=0 Dai un numr de maxim 9 cifre: 247 m=247 m=247 != 0 s=s+247%10 s=0+7=7 m=m/10 m=24 m=24 != 0 s=s+24%10 s=7+4=11 m=m/10 m=2 m=2 != 0 s=s+2%10 s=11+2=13 m=m/10 m=0 m=0 => s=13 Suma cifrelor lui 247 este 13. Cu funcie : Program
using System; namespace ConsoleApplication10b { class Program { static int suma(int nr) { int s = 0; while (nr != 0) { s += nr % 10; nr /= 10; } return s;

68

} static void Main() { int n; Console.Write("Dati un numr de maxim 9 cifre : "); n = int.Parse(Console.ReadLine()); Console.WriteLine("Suma cifrelor lui {0} este {1}", n, suma(n)); Console.ReadKey(); } } }

11. S se scrie un program care s calculeze cifra de control a unui numr natural. Aceasta se obine nsumnd cifrele numrului i dac suma obinut este >=10 se repet algoritmul pn cnd se obine o sum format dintr-o singur cifr (deci un numr <10). Ex: n=9989879 s=9+9+8+9+8+7+9=59 s=5+9=14 s=1+4=5 Cu funcie : Program
using System; namespace ConsoleApplication11 { class Program { static int suma(int nr) { int s = 0; while (nr != 0) { s += nr % 10; nr /= 10; } return s; } static void Main() { int n, control; Console.Write("Dati un numr de maxim 9 cifre : "); n = int.Parse(Console.ReadLine()); do { Console.Write(" -> "); control = suma(n); Console.Write(control); n = control; } while (control >= 10); Console.WriteLine("\nCifra de control a nr de mai sus este {0}", control); Console.ReadKey(); } } }

Analiza programului se citete numrul n de la tastatur pornind de la numrul iniial, cu ajutorul instruciunii while, se calculeaz suma cifrelor 69

numrului atta timp ct ea este >=10; dac este >=10 se va calcula suma cifrelor pentru acest nou numr. Calculul de oprete n momentul n care suma obinut este <10, iar aceasta va reprezenta cifra de control a numrului iniial funcia suma calculeaz suma cifrelor unui numr primit ca i parametru i returneaz valoarea obinut 12. Se citete de la tastatur un numr natural n9. S se afieze toate numerele de n cifre care adunate cu rsturnatul lor dau un ptrat perfect. Cu funcie : Program
using System; namespace ConsoleApplication12 { class Program { static int rasturnat(int nr) { int r = 0; while (nr != 0) { r = (r*10)+nr % 10; nr = nr/10; } return r; } static void Main() { int sum, rsum, n, i, start, stop; Console.Write("Cate cifre? "); n = int.Parse(Console.ReadLine()); start=(int)Math.Pow(10, n-1); stop=(int)Math.Pow(10, n); for (i = start; i < stop; i++) { sum = i + rasturnat(i); rsum = (int)Math.Sqrt(sum); if ( (rsum*rsum) == sum) Console.WriteLine("{0} + {1} = {2} este patrat perfect: {3}^2", i,rasturnat(i),sum,rsum); } Console.ReadKey(); } } }

Analiza programului Se citete de la tastatur numrul de cifre n. Conform acestuia, verificrile se vor face pe intervalul de valori [10n-1,10n-1] (Ex: n=3 [100, 999]). Pentru a ridica pe 10 la o putere se folosete metoda Math.Pow, creia i se mai aplic suplimentar i operatorul de cast (int) deoarece rezultatul returnat de metoda Math.Pow este de tip double i nu ar fi posibil atribuirea unei astfel de valori la o variabil de tip int.

70

Cu ajutorul instruciunii for se parcurg toate valorile de la 10n-1 la 10n-1. Fiecare din ele se adun cu rsturnatul lor. Rsturnatul se obine cu ajutorul unei funcii care este asemntoare cu cea de obinere a sumei cifrelor unui numr. Pentru a testa dac suma dintre un numr i rsturnatul su este ptrat perfect se procedeaz astfel: Se calculeaz n variabila rsum radicalul sumei cu ajutorul metodei Math.Sqrt, creia i se mai aplic suplimentar i operatorul de cast (int) deoarece rezultatul returnat de metoda Math.Sqrt este de tip double i nu ar fi posibil atribuirea unei astfel de valori la o variabil de tip int. Se testeaz apoi dac ptratul acestei valori este egal cu suma dintre numr i rsturnatul su (Ex 1: i=346, rasturnat(i)=643, sum=989, rsum=31, rsum*rsum=961 989, deci nu are loc egalitatea; Ex 2: i=164, rasturnat(i)=461, sum=625, rsum=25, rsum*rsum=626=625, deci are loc egalitatea). 13. Se citeste de la tastatur un ir de numere ntregi pn la citirea lui 0. S se afieze valoarea minim i maxim citit i media lor aritmetica (fr vectori). Program
using System; namespace ConsoleApplication13 { class Program { static void Main(string[] args) { int nr, min, max, tot=1; float sum, ma; Console.WriteLine("Se vor citi numere pana la intr. lui 0"); Console.Write("Dati un numr: "); nr = int.Parse(Console.ReadLine()); min = max = nr; sum = nr; do { if (nr < min) min = nr; if (nr > max) max = nr; Console.Write("Dati un numr: "); nr = int.Parse(Console.ReadLine()); sum = sum + nr; tot++; } while (nr != 0); tot--; ma = sum / tot; Console.Write("min={0}, max={1}, media aritm.={2}", min, max, ma); Console.ReadKey(); } } }

Analiza programului n prima faz se citete de la tastatur primul numr i se iniializeaz minimul, maximul i suma numerelor cu aceast valoare. Pentru ca la final s se poat calcula media aritmetic a numerelor introduse, se folosete variabile tot care iniial are valoarea 1 i care se va incrementa cu 1 la citirea fiecrui nou numr. 71

n cadrul unei instruciuni repetitive do-while se vor citi numere de la tastatur pn la introducerea lui 0. Cu fiecare numr nou citit se fac cteva operaii: se compar cu minimul curent i dac este mai mic dect acesta se actualizeaz minimul, se compar cu maximul curent i dac este mai mare dect acesta se actualizeaz maximul, se adun la suma numerelor. Dup ce s-a citit de la tastatur valoarea 0, se decrementeaz cu 1 valoarea variabilei tot pentru a exclude ultima valoare citit care era 0 i care nu mai ia parte la calcule, dup care se calculeaz media aritmetic, mprind suma numerelor citite la totalul lor. Se observ c variabila sum a fost declarat de tip float dei ea conine suma unor numere ntregi. S-a apelat la acest artificiu deoarece dac era declarat de tip int i la final efectuam operaia sum / tot, aceasta implicnd numere ntregi, ddea tot un numr ntreg (Ex: 27/5=5, dei media aritmetic era 5.4). Folosind ns variabila sum de tip float, rezultatul operaiei sum / tot va fi i el de tip float, adic exact ceea ce avem nevoie. La final se afieaz valoare minim, maxim i media aritmetic. Se sublinia n enun ca rezolvarea s nu implice vectori, deoarece se observ c ei nu sunt necesari pentru a memora toate valorile introduse de la tastatur. Este suficient o variabil simpl cu ajutorul creia se va citi cte o valoare, se fac operaiile necesare, dup care poate stoca o nou valoare, cea veche nemaifiind necesar. 14. Fiind date dou numere naturale n i m, s se formeze un nou numr care s conin cifrele maxime de pe fiecare poziie din n i m. Ex: n=2618, m=3456 3658 Program
using System; namespace ConsoleApplication14 { class Program { static void Main() { int n, m, max = 0, p10 = 1, cifra; Console.Write("Introduceti primul numr: "); n = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); m = int.Parse(Console.ReadLine()); while (n != 0 || m != 0) { if (n % 10 > m % 10) cifra = n % 10; else cifra = m % 10; max = max + cifra * p10; p10 *= 10; n /= 10; m /= 10; } Console.WriteLine("Noul numr este : {0}", max); Console.ReadKey(); } } }

72

Observaie :
if ((n%10)>(m%10)) cifra = n%10; else cifra = m%10; cifra=(n%10)>(m%10) ? n%10 : m%10;

Analiza programului Aceast problem deriv i ea din problema aflrii cifrelor unui numr natural. Rezolvarea acestei probleme merge pe ideea de a descompune n paralel cele dou numere n i m, pn cnd ambele devin 0 (e posibil ca acest lucru s se ntmple n momente diferite dac cele dou numere nu au acelai numr de cifre). Cifrele de pe aceeai poziie obinute din cele dou numere se compar i care este mai mare va face parte din numrul care se dorete s se obin. Noul numr max se obine printr-un procedeu invers celui de obinere a cifrelor unui numr, n sensul c de data aceasta cte o cifr maxim obinut de la cele dou numere iniiale se nmulete cu 10 la o anumit putere corespunztoare poziiei cifrei n numrul max (prima cifr cea mai din dreapta - se nmulete cu 100, a dou cifr cu 101, a treia cu 102, .a.m.d.) i se nsumeaz. nmulirea cu 10 la o putere corespunztoare ajut a plasa o cifr n poziia care trebuie n numrul care se dorete s se obin max. Se observ c nu s-a folosit metoda Math.Pow, ci s-a aplicat o metoda optimizat din punct de vedere al calculelor, folosind variabila p10 n construirea valorii 10putere. Variabila p10 are la nceput valoarea 1 i pe parcurs, prin nmulire cu 10 va avea valoarea 101, 102, etc. Aceasta este o variant mai bun dect a folosi metoda Math.Pow, care pentru a calcula 10putere folosete mai mult de o nmulire, pe cnd varianta utilizat n acest program folosete numai una, avnd deja calculat de la pasul anterior 10putere-1. Exemplu : n=2618, m=3456 (8,6) 8*100+ (1,5) 5*101+ 8+50+600+3000=3658 2 (6,4) 6*10 + (2,3) 3*103 Cu funcie : Program
using System; namespace ConsoleApplication14b { class Program { static int cifre_maxime(int n1, int n2) { int n3 = 0, cifra, p10 = 1; while (n1 != 0 || n2 != 0) { if (n1 % 10 > n2 % 10) cifra = n1 % 10; else cifra = n2 % 10; n3 += cifra * p10; p10 *= 10; n1 /= 10; n2 /= 10; } return n3; }

73

static void Main() { int n1, n2; Console.Write("Introduceti primul numr: "); n1 = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); n2 = int.Parse(Console.ReadLine()); Console.WriteLine("Numrul format este {0}", cifre_maxime(n1, n2)); Console.ReadKey(); } } }

15. S se determine c.m.m.d.c. a dou numere naturale. (2 variante) Varianta 1: Program


using System; namespace ConsoleApplication15 { class Program { static void Main() { int nr1, nr2, n, m; Console.Write("Introduceti primul numr: "); nr1 = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); nr2 = int.Parse(Console.ReadLine()); n = nr1; m = nr2; while (nr1 != nr2) if (nr1 > nr2) nr1 -= nr2; else nr2 -= nr1; Console.WriteLine("C.m.m.d.c.({0},{1}) = {2}", n, m, nr1); Console.ReadKey(); } } }

Analiza programului Aceasta este o metod foarte simplu de aplicat i de reinut n aflarea c.m.m.d.c. a dou numere, ns probabil necesit mai multe calcule dect ali algoritmi. Ideea acestui algoritm este urmtoarea: atta timp ct cele dou numere date sunt diferite, din cel mai mare se scade cel mai mic, iar prin acest procedeu la un moment dat cele dou numere vor deveni egale. Acea valoare final pe care o au ambele numere reprezint c.m.m.d.c. al lor. Avnd n vedere faptul c ambele numere vor fi alterate n acest calcul, pentru a nu pierde valoarea lor iniial, nainte de instruciunea while se poate face cte o copie a lor cu care s se lucreze mai departe.

74

Varianta 2: Algoritmul lui Euclid Program


using System; namespace ConsoleApplication15b { class Program { static void Main() { int nr1, nr2, temp, r, n, m; Console.Write("Introduceti primul numr: "); nr1 = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); nr2 = int.Parse(Console.ReadLine()); n = nr1; m = nr2; if (nr1 < nr2) { temp = nr1; nr1 = nr2; nr1 = temp; } do { r = nr1 % nr2; nr1 = nr2; nr2 = r; } while (r != 0); Console.WriteLine("C.m.m.d.c.({0},{1}) = {2}", n, m, nr1); Console.ReadKey(); } } }

Analiza programului Acesta este un algoritm destul de celebru de determinare a c.m.m.d.c a dou numere naturale. Ideea pe care se bazeaz ns este puin mai dificil dect cea a primului algoritm prezentat, ns cel mai probabil c necesit mai puin calcul. Prima dat se citesc cele dou numere i se asigur c primul dintre ele este cel mai mare. Ideea algoritmului lui Euclid este de a ncepe prin a mpri numrul mai mare din perechea de numere date, la cel mai mic. Dac restul obinut este diferit de 0, se repet mprirea, de data aceasta mprindu-se mpritorul la restul de la mprirea anterioar. Acest mecanism se repet pn cnd se obine restul 0. n acel moment este aflat c.m.m.d.c., iar el este penultimul rest obinut (nenul). n cazul n care se obine din start restul 0 nseamn c numrul mai mic din cele dou reprezint c.m.m.d.c. Ex : (60, 25)=5 60 : 25=2 rest 15 25 : 15=1 rest 10 15 : 10=1 rest 5 10 : 5=2 rest 0 Cu funcie : Program
using System; namespace ConsoleApplication15c {

75

class Program { static int cmmdc(int n1, int n2) { int r; do { r = n1 % n2; n1 = n2; n2 = r; } while (r != 0); return n1; } static void Main() { int a, b, temp; Console.Write("Introduceti primul numr: "); a = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); b = int.Parse(Console.ReadLine()); if (a < b) { temp = a; a = b; b = temp; } Console.WriteLine("C.m.m.d.c.({0},{1}) = {2}", a, b, cmmdc(a, b)); Console.ReadKey(); } } }

16. S se afieze toi divizorii (proprii) comuni a dou numere naturale. Program
using System; namespace ConsoleApplication16 { class Program { static void Main() { int m, n, c; Console.Write("Introduceti primul numr: "); m = int.Parse(Console.ReadLine()); Console.Write("Introduceti al doilea numr: "); n = int.Parse(Console.ReadLine()); if (m >= n) c = n / 2; else c = m / 2; Console.WriteLine("Divizorii comuni pentru {0} i {1}", m, n); for (int i = 2; i <= c; i++) if ((n % i == 0) && (m % i == 0)) Console.Write(i + " "); Console.ReadKey(); } } }

76

Analiza programului Cnd se pune problema determinrii divizorilor unui numr n, la nceput se pune ntrebarea: n ce mulime de valori de va face cutarea divizorilor? Un rspuns ar putea fi intervalul [1, n]. n cazul n care nu dorim i divizorii impropri (1 i numrul nsui) ar rmne intervalul [2, n-1]. n situaia aceasta ns ar trebui s ne punem ntrebarea: care este cel mai mare divizor propriu al unui numr n? Fr prea multe dificulti ar trebui s realizm c aceast valoare este la jumtatea numrului, deoarece aceasta nmulit cu 2 ar da numrul n. De la jumtate ncolo, orice valoare am nmuli cu 2, va trece de valoarea lui n, deci nu mai are cum s fie divizor al lui n. Astfel, deducem c divizorii proprii i vom cuta n intervalul [2, n/2]. n problema de fa, avnd de-a face cu divizorii a dou numere, din nou trebuie luat o decizie asupra intervalului n care se vor cuta divizorii comuni. Ar putea aprea mai multe variante de rspuns, ns cea corect este de a cuta n intervalul de la 2 pn la jumtatea numrului mai mic din cele dou. De ce pn la jumtatea numrului mai mic? Deoarece dac de exemplu s-ar merge pn la jumtatea numrului mai mare, valorile de la jumtatea numrului mai mic pn la jumtatea celui mai mare sigur nu vor mai putea fi divizori ai numrului mai mic din considerentele enunate n paragraful anterior. Divizor comun nseamn o valoare la care se mpart exact ambele numere. De fiecare dat cnd va fi gsit o astfel de valoare, ea va fi afiat pe ecran. Ex : n=60 intervalul de cutare [2, 30] m=42 intervalul de cutare [2, 21] Dac s-ar mai cuta divizori comuni n intervalul [22, 30] nu s-ar mai gsi nici unul, deoarece orice valoare >=22 nu mai poate fi divizor propriu al lui 42. Din acest motiv, divizorii comuni ai celor dou numere se caut pn la jumtatea celui mai mic dintre ele. Pentru a decide care dintre numerele n i m este mai mare s-a utilizat instruciunea
c = m>=n ? n/2 : m/2;

Aceasta este echivalent cu o instruciune if-else:


if (m>=n) c = n/2; else c = m/2;

S-a optat pentru operatorul de decizie ?: mai mult din motive de economie de scriere dect din alte considerente. Astfel, dac m>=n rezultatul evalurii va fi n/2 care apoi i se atribuie lui c, altfel va fi m/2 care se va atribui lui c. 17. S se determine toate numerele perfecte mai mici dect 10000. Un numr este perfect dac este egal cu suma tuturor divizorilor si (inclusiv 1). Program
using System; namespace ConsoleApplication17 { class Program { static void Main() { int nr, i, s; Console.WriteLine("Nr perfecte < 10000 sunt:"); for (nr = 4; nr <= 10000; nr++) { s = 0;

77

for (i = 1; i <= nr / 2; i++) if (nr % i == 0) s += i; if (s == nr) Console.WriteLine(nr); } Console.ReadKey(); } } }

Analiza programului Acest program necesit aflarea tuturor divizorilor unui numr (inclusiv 1) i nsumarea lor. Cu ajutorul unei instruciuni for se vor testa toate numere naturale de la 4 (cel mai mic numr natural care are divizori proprii) pn la 10000. S-a discutat n problema anterioar modul de aflare a tuturor divizorilor unui numr natural. n cazul n care suma divizorilor este egal cu numrul analizat, acesta va fi tiprit pe ecran. Cu funcie : Program
using System; namespace ConsoleApplication17b { class Program { static int suma_div(int nr) { int s = 1, i; for (i = 2; i <= nr / 2; i++) if (nr % i == 0) s += i; return s; } static void Main() { int n, i; Console.Write("Introduceti numrul n= "); n = int.Parse(Console.ReadLine()); Console.WriteLine("Numerele perfecte mai mici decat {0} sunt", n); for (i = 4; i <= n; i++) if (suma_div(i) == i) Console.WriteLine(i); Console.ReadKey(); } } }

18. Testai dac un numr natural dat este prim. (Prin numr prim nelegem orice numr natural care se mparte doar la 1 i la el nsui; se considera ca 2 este cel mai mic numr prim). Program
using System; namespace ConsoleApplication18 {

78

class Program { static void Main() { int i, n, rad_n; bool prim = true; Console.Write("Introduceti n = "); n = int.Parse(Console.ReadLine()); rad_n = (int)Math.Sqrt(n); for (i = 2; i <= rad_n; i++) //for (i=2; i*i<=n; i++) if (n % i == 0) { prim = false; break; } if (prim) Console.WriteLine("Numrul {0} este prim", n); else Console.WriteLine("Numrul {0} nu este prim", n); Console.ReadKey(); } } }

Analiza programului - n scopul verificrii dac un anumit numr este prim, va trebui sa testam dac se mparte la vreun alt numr nafara de 1 i el nsui. Problema care se pune este n ce interval vom cuta posibilele valori la care s-ar putea mpri numrul. S-ar putea propune variantele de intervale [2, n-1] sau [2, n/2], nsa varianta optima este de a cuta n intervalul [2, n ]. Astfel, se vor parcurge cu ajutorul unei instruciuni for toate numerele naturale cuprinse ntre 2 i n ; dac n se divide cu vreunul dintre ele (restul mpririi lui n la i este 0), atunci se oprete forat instruciunea for cu ajutorul instruciunii break i variabila prim ia valoarea false. Dac s-a terminat normal instruciunea for nseamn c numrul n este prim, deoarece nu s-a gsit nici un divizor, iar variabila prim are valoarea true; - se observ c nainte de instruciunea for, am depus valoarea lui n n variabila rad_n. Scopul acestei atribuiri este de a evita calculul radicalului la fiecare pas de for. De reinut c aceast operaie este util de aplicat oricnd apare un calcul care nu se modific (constant), ntr-o instruciune repetitiv. Astfel, el poate fi efectuat o singur dat, nainte de a intra n instruciunea repetitiv. - cu ajutorul unei instruciuni if testm valoarea variabilei prim, astfel dac ea este true se va afia mesajul ca n este numr prim i altfel se va afia mesajul ca n nu este numr prim. Cu funcie : Program
using System; namespace ConsoleApplication18b { class Program { static bool test_prim(int n) { int i, rad_n; bool prim = true; rad_n = (int)Math.Sqrt(n);

79

for (i = 2; i <= rad_n; i++) if (n % i == 0) { prim = false; break; } return prim;

//for (i=2; i*i<=n; i++)

} static void Main() { int n; Console.Write("Introduceti n = "); n = int.Parse(Console.ReadLine()); if (test_prim(n)) Console.WriteLine("Numrul {0} este prim", n); else Console.WriteLine("Numrul {0} nu este prim", n); Console.ReadKey(); } } }

19. Se citete de la tastatur un numr natural x mai mare dect 2. S se gseasc p i q numere prime astfel nct p<x<q, iar diferena q-p este minim. Cu funcie : Program
using System; namespace ConsoleApplication19 { class Program { static bool test_prim(int n) { int i, rad_n; bool prim = true; rad_n = (int)Math.Sqrt(n); for (i = 2; i <= rad_n; i++) //for (i=2; i*i<=n; i++) if (n % i == 0) { prim = false; break; } return prim; } static void Main() { int x, p, q; bool prim; Console.Write("Introduceti x = "); x = int.Parse(Console.ReadLine()); p = x; do { p--; prim = test_prim(p); } while (prim == false); q = x; do { q++;

80

prim = test_prim(q); } while (prim == false); Console.Write("Soluia gsita:{0}<{1}<{2} ", p, x, q); Console.Write("iar {0}-{1}={2}", q, p, q - p); Console.ReadKey(); } } }

Analiza programului Aceasta problem presupune de fapt gsirea primului numr prim mai mic dect x i a primului numr prim mai mare dect x. n felul acesta diferena q-p va fi minim. n acest sens, se pornete prima dat de la valoarea x-1 i se testeaz n jos cu ajutorul unei instruciuni repetitive do-while toate valorile pn cnd se va gsi primul numr prim. Acela va fi numrul p. Dup aceea, se pornete de la valoarea x+1 tot cu o instruciune repetitiv do-while i se testeaz n sus toate valorile pn cnd se va gsi primul numr prim. Acela va fi numrul q. Modul de testare a unui numr dac este prim este acelai cu cel de la problema anterioar. 20. Se citete de la tastatur un numr natural par. S se decid dac acesta poate fi scris ca i suma de dou numere prime i s se afieze toate soluiile gsite (se va considera c i 1 este numr prim). (Conjectura lui Goldbach: Orice numr par mai mare dect 2 este suma a dou numere prime.) Cu funcie : Program
using System; namespace ConsoleApplication20 { class Program { static bool test_prim(int n) { int i, rad_n; bool prim = true; rad_n = (int)Math.Sqrt(n); for (i = 2; i <= rad_n; i++) //for (i=2; i*i<=n; i++) if (n % i == 0) { prim = false; break; } return prim; } static void Main() { int nr, nr1, nr2 = 0; bool prim; Console.Write("Introduceti nr: "); nr = int.Parse(Console.ReadLine()); for (nr1 = 1; nr1 <= nr / 2; nr1 = nr1 + 2) { prim = test_prim(nr1); if (prim == true) { nr2 = nr - nr1; prim = test_prim(nr2);

81

} if (prim == true) //nr=nr1+nr2 i nr1, nr2 sunt prime Console.WriteLine("Solutie:{0}+{1}",nr1,nr2); } Console.ReadKey(); } } }

Analiza programului n cadrul acestei probleme, n ncercarea de a scrie numrul nr ca i sum de dou numere prime se vor cuta valori n intervalul [1, nr/2]. Dac se gsete un numr prim nr1 din acest interval, se va testa apoi dac i nr2=nr-nr1 este i el prim. Dac da, aceasta nseamn ca nr=n1+nr2, iar nr1 i nr2 sunt prime. Aceast pereche se va tipri pe ecran. nr1 se caut n intervalul [1, nr/2] deoarece dac se trece de jumtatea numrului, se vor obine perechi duplicate. De asemenea, valorile lui nr1 n cadrul instruciunii for merg din 2 n 2, deoarece se merge doar pe valori impare. Ex : Dac nr=26, atunci s-ar obine soluia nr1=3, nr2=23 dar i nr1=23, nr2=3. Modul de testare a unui numr dac este prim este acelai cu cel de la problema 18. 21. Se citete de la tastatur un numr natural. S se decid dac acesta poate fi scris ca i sum de dou patrate i s se afieze toate soluiile gsite. Program
using System; namespace ConsoleApplication21 { class Program { static void Main() { int n, i, j, t1, t2, rad_n, sol=0; Console.Write("Introduceti numrul n="); n = int.Parse(Console.ReadLine()); rad_n = (int)Math.Sqrt(n); for (i = 1; i <= rad_n; i++) { t1 = i * i; j = (int)Math.Sqrt(n - i * i); t2 = j * j; if ((t1 <= t2) && (n == t1 + t2)) { Console.WriteLine("Solutie: {0}={1}*{2}+{3}*{4}", n, i, i, j, j); sol++; } } Console.Write("Au fost gasite {0} solutii", sol); Console.ReadKey(); } } }

82

Analiza programului Pentru un n citit de la tastatur se testeaz toate valorile din intervalul [1, n ] pentru a vedea dac poate fi ndeplinit condiia din enun. Astfel, pentru fiecare valoare i din acest interval se calculeaz j= n i * i . n cazul n care n=i*i+j*j nseamn c a fost gsit soluia (i, j). Intervalul de testare este [1, n ] deoarece dac i= n , atunci i*i=n, deci nu se mai poate gsi un al doilea numr pozitiv j pentru care i*i+j*j=n. Pentru a ne verifica, (i, j) este soluie a problemei deoarece n=i*i+j*j= i*i+ n i * i * n i * i =i*i+n-i*i=n. S-a mai adugat i testul dac t1<=t2 pentru a evita generarea de soluii identice. Ex: (2, 5), (5, 2) La final se afieaz numrul total de soluii gasite (care poate fi i 0). Exemplu : n=29, i[1, 5] i=1, i*i=1, n-i*i=28, j= 28 =5, i*i+j*j=26 28 i=2, i*i=4, n-i*i=25, j= 25 =5, i*i+j*j=28=28 (2, 5) ... 22. S se afieze primele n perechi de numere prime care sunt consecutive n mulimea numerelor impare. Cu funcie : Program
using System; namespace ConsoleApplication22 { class Program { static bool test_prim(int n) { int i, rad_n; bool prim = true; rad_n = (int)Math.Sqrt(n); for (i = 2; i <= rad_n; i++) //for (i=2; i*i<=n; i++) if (n % i == 0) { prim = false; break; } return prim; } static void Main() { int n, i, c; Console.Write("Introduceti numrul de perechi n="); n = int.Parse(Console.ReadLine()); c = 0; i = 3; while (c < n) { if (test_prim(i) && test_prim(i + 2)) { // i, i+2 sunt prime Console.WriteLine("{0}, {1}", i, i + 2); c++; } i = i + 2; } //while Console.ReadKey(); }

83

} }

Analiza programului Soluiile acestei probleme se vor cuta ncepnd cu numrul 3, dup care se va merge din 2 n 2. Astfel se vor testa perechile de valori (3, 5), (5, 7), (7, 9), .a.m.d. Prima dat se testeaz prima valoare a perechii. Dac este numr prim se trece la testarea celei de-a doua valori (egal cu prima valoare + 2). Dac i ea este numr prim nseamn c a fost gsit o soluie, care se tiprete pe ecran. De fiecare dat cnd se gsete o soluie, se va incrementa un contor c, pentru a se ti cnd vor fi gsite cele n perechi cutate. Mecanismul de testare dac un numr este prim este acelai cu cel de la problema 21. Optimizare :
while (c < n) { if (test_prim(i)) if (test_prim(i + 2)) { // i, i+2 sunt prime //Console.WriteLine("{0}, {1}", i, i + 2); c++; i = i + 2; } else i = i + 4; else i = i + 2; }

Dac n perechea (i, i+2), i+2 nu este numr prim, atunci nu se va mai testa perechea (i+2, i+4), ci se va trece direct la testarea perechii (i+4, i+6). Ex: (7, 9): i=7 este nr prim, i+2=9 nu este nr prim nu se va mai testa perechea (9, 11), ci se va trece la testarea perechii (11, 13). n felul acesta am economisit de la testare o pereche de valori i implicit am ctigat puin timp la rularea programului, ceea ce pentru un n suficient de mare poate s devin un timp simitor. 23. S se descompun un numr natural n n factori primi. Ex: 360=23*32*51 Program
using System; namespace ConsoleApplication23 { class Program { static void Main() { int n, m, i, putere; Console.Write("Introduceti numrul n = "); n = int.Parse(Console.ReadLine()); Console.Write("{0} = ", n); m = n; for (i = 2; i <= n / 2; i++) { if (m % i == 0) { putere = 0; while (m % i == 0) { putere++;

84

m = m / i; } Console.Write("{0}^{1} * ", i, putere); } if (m == 1) break; } Console.Write("1"); Console.ReadKey(); } } }

Analiza programului Aceast problem i propune s afle toi divizorii primi ai unui numr natural n i puterea la care intr acei divizori n descompunerea lui n. n acest sens, se vor cuta toi divizorii lui n n intervalul [2, n/2]. De fiecare dat cnd este gsit un divizor, se va calcula puterea la care intr acel divizor n descompunerea lui n, mprind n mod repetat acel divizor la n pn cnd acest lucru nu mai este posibil. Noul numr n va fi n-ul iniial mprit la divizorul gsit la puterea maxim ce intr n descompunerea lui n, dup care se va trece s se testeze o nou valoare. Calculul se va opri n momentul n care n devine 1. Ex : n=360 Primul divizor gsit este 2. Se mparte n la 2 pn cnd acest lucru nu mai este posibil: 360:2=180:2=90:2=45. Noul n cu care se va lucra mai departe va fi 45, i s-a aflat c 2 3 intr n descompunerea n-ului iniial. Se va trece la testarea lui 3. Deoarece 3 este divizor al lui 45 se trece la aflarea puterii la care intr 3 n descompunerea lui n: 45:3=15:3=5. Noul n cu care se va lucra mai departe va fi 5, i s-a aflat c 32 intr n descompunerea n-ului iniial. Se va trece la testarea lui 4, dar acesta nu este divizor al lui 5. Se va trece la testarea lui 5. Deoarece 5 este divizor al lui 5 se trece la aflarea puterii la care intr 5 n descompunerea lui n: 5:5=1. S-a aflat c 51 intr n descompunerea n-ului iniial. Acum n a devenit 1, moment n care calculul se oprete. Din rezolvarea acestei probleme se observ c atunci cnd este gsit un divizor, acesta nu este testat dac este prim sau nu. De ce? Deoarece nu se lucreaz tot timpul cu n iniial, ci de la o testare a unui divizor la alta, n a fost mprit la divizorii si gsii pn la un moment dat. Astfel, n exemplul de mai sus, 360 a fost mprit la 23, iar pe mai departe nu s-a mai lucrat cu 360, ci cu 360:23=45. Acest fapt influeneaz semnificativ mersul rezolvrii, deoarece numrul iniial fiind mprit la puterea maxim posibil a lui 2, pe mai departe nici un multiplu al lui 2 nu va mai fi gsit ca i divizor al unui nou n. Pe cnd dac s-ar fi lucrat tot cu n iniial, att 4 ct i 8 ar fi fost gsii ca i divizori ai lui 360, caz n care era necesar i testul de primalitate. n modul n care este gndit aceast rezolvare, orice numr se va testa i este gsit ca i divizor, sigur este prim, deoarece toi posibilii si divizori au fost deja testai, iar numrul iniial a fost mprit deja la ei. Revenind la numrul 360, divizorii si sunt: 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 18, 20, 24, 30, 36, 40, 45, 60, 120, 180.

85

n momentul n care 2 a fost gsit ca divizor al lui 360, iar apoi 360 a fost mprit la 23 i s-a obinut 45, toi multiplii lui 2 cad de la analizare, adic rmn de testat doar divizorii 3, 5, 9, 15, 45. n momentul n care 3 a fost gsit ca divizor al lui 45, iar apoi 45 a fost mprit la 32 i s-a obinut 5, toi multiplii lui 3 cad de la analizare, adic rmn de testat doar divizorii 5, 15, 45. n momentul n care 5 a fost gsit ca divizor al lui 5, iar apoi 5 a fost mprit la 51 i s-a obinut 1, calculul se ncheie, iar concluzia este c 360=23*32*51. 24. Se citesc de la tastatur n numere naturale i un numr prim p. Se cere s se gseasc un numr k maxim astfel nct produsul celor n numere s se divid cu pk, fr a calcula produsul. Ex: Dac p=2, iar cele 4 numere sunt: 10=21*5, 8=23, 3=20*3, 28=22*7 k=6 Program
using System; namespace ConsoleApplication24 { class Program { static void Main() { int n, nr, p, k = 0, i; Console.Write("Dati numrul total de numere n="); n = int.Parse(Console.ReadLine()); Console.Write("Introduceti numrul prim p="); p = int.Parse(Console.ReadLine()); for (i = 1; i <= n; i++) { Console.Write("Introduceti un nr: "); nr = int.Parse(Console.ReadLine()); while (nr % p == 0) { k++; nr = nr / p; } } Console.Write("k maxim={0}", k); Console.ReadKey(); } } }

Analiza programului Rezolvarea acestei probleme merge pe ideea c puterea la care se divide p n cadrul produsului celor n numere este aceeai cu puterile lui p nsumate de la cele n numere pe rnd. n exemplul dat 10*8*3*28=6720, iar aceast valoare se divide cu 26. Se poate observa ns i fr a face produsul c 10*8*3*28=21*5*23*20*3*22*7=26* Este de fapt de evitat pe ct posibil calcularea produsului deoarece la un moment dat s-ar putea obine o valoare care s depeasc cea mai mare valoare ntreag predefinit n C# (2 64) . Dac ns nu se realizeaz produsul, aceast problem este eliminat. Rezolvarea acestei probleme const n a citi pe rnd cele n numere i a verifica puterea lui p care intr n descompunerea fiecruia dintre ele. Aceste puteri se nsumeaz, iar rezultatul obinut este exact acel k maxim care se caut. 86

25. Se citesc n numere naturale de la tastatur. S se determine n cte zerouri se va termina produsul acestora, fr a calcula efectiv produsul. Ex: 12, 35, 30, 75 3 zerouri Program
using System; namespace ConsoleApplication25 { class Program { static void Main() { int n, nr, p2 = 0, p5 = 0, i, zero; Console.Write("Introduceti numrul de elemente n="); n = int.Parse(Console.ReadLine()); for (i = 1; i <= n; i++) { Console.Write("Introduceti un numr nr="); nr = int.Parse(Console.ReadLine()); if (nr % 2 == 0) while (nr % 2 == 0) { p2++; nr /= 2; } if (nr % 5 == 0) while (nr % 5 == 0) { p5++; nr /= 5; } } if (p2 < p5) zero = p2; else zero = p5; Console.WriteLine("Produsul celor {0} numere se termina n {1} zerouri", n, zero); Console.ReadKey(); } } }

Analiza programului Rezolvarea acestei probleme seamn cu cea de la problema 24.Se merge pe aceeai idee c nu este necesar (i nici recomandat) de a calcula produsul tuturor celor n numere pentru a afla rezultatul cutat. De data aceasta ns, pentru fiecare numr din cele n se va studia cu 2 la ce putere se divide i cu 5 la ce putere se divide, deoarece fiecare 0 n care se termin produsul numerelor nseamn o putere a lui 10, iar 10=2*5. Toate puterile lui 2 i 5 care apar n descompunerea celor n numere se nsumeaz, iar la final care dintre cele dou valori este mai mic reprezint numrul de zerouri n care se termin produsul celor n numere.

87

Ex:12*35*30*75=22*3*51*7*21*51*3*52*3=23*54*=23*53*= 103*=1000* Se deduce astfel c produsul celor 4 numere se termin n 3 zerouri. (n descompunere se obinuse 23 i 54, 3<4 103, deci 3 zerouri). Cu funcie : Program
using System; namespace ConsoleApplication25b { class Program { static int putere(int p, int x) { int putere_p = 0; while (x % p == 0) { x /= p; putere_p++; } return putere_p; } static void Main() { int x, p2=0, p5=0; Console.Write ("Introduceti un numr: "); x=int.Parse(Console.ReadLine()); while (x!=0) { p2+=putere(2,x); p5+=putere(5,x); Console.Write("Introduceti un numr: "); x = int.Parse(Console.ReadLine()); } Console.WriteLine ("Produsul se divide cu 2 la puterea {0}", p2); Console.WriteLine("Produsul se divide cu 5 la puterea {0}", p5); if (p2 >= p5) Console.WriteLine("Produsul se divide cu 10 la puterea {0}", p5); else Console.WriteLine("Produsul se divide cu 10 la puterea {0}", p2); Console.ReadKey(); } } }

26. Sa se calculeze nm efectund mai puin de m-1 nmuliri. (Atenie la valorile n i m, ca rezultatul s nu depeasc cel mai mare ntreg definit n C#) Program
using System; namespace ConsoleApplication26 { class Program { static void Main() { long prod;

88

int n, m, p, i, op=0; Console.Write("Introduceti n="); n = int.Parse(Console.ReadLine()); Console.Write("Introduceti m="); m = int.Parse(Console.ReadLine()); prod = n; p = 1; while ((p * 2) <= m) { prod *= prod; p *= 2; op++; } if (p < m) for (i = p + 1; i <= m; i++) { prod *= n; op++; } Console.WriteLine("{0}^{1}={2} din {3} operatii", n, m, prod, op); Console.ReadKey(); } } }

Analiza programului Rezolvarea acestei probleme merge pe ideea de a ridica la putere n urmtorul mod: n*n=n 2, n2*n2=n4, n4*n4=n8,etc. atta timp ct acest lucru este posibil. Cnd nu mai este posibil se va continua nmulirea simpl cu cte un n. Ex: m=20 n20 se calculeaz astfel: n*n=n2, n2*n2=n4, n4*n4=n8, n8*n8=n16; nu se mai poate continua n acest mod, deci pn la 20 se va nmuli cu cte un n: n16*n*n*n*n=n20. Se observ c fa de a nmuli n de 20 de ori, s-au fcut mai puine nmuliri (s-au fcut doar 7 nmuliri).

89

6.2 VECTORI
27. Dat fiind un tablou unidimensional (vector) cu numere ntregi, determinai minimul i maximul din acest tablou. Program
using System; namespace ConsoleApplication27 { class Program { static void Main() { int n, i; int MIN, MAX; Console.Write("Dati dimensiunea vectorului A: n="); n = int.Parse(Console.ReadLine()); int[] a = new int[n]; Console.WriteLine("Dati elementele vectorului: "); for (i = 0; i < n; i++) { Console.Write("A[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } MIN = MAX = a[0]; for (i = 1; i < n; i++) { if (a[i] < MIN) MIN = a[i]; if (a[i] > MAX) MAX = a[i]; } Console.WriteLine("Minimul din tablou este {0}", MIN); Console.WriteLine("Maximul din tablou este {0}", MAX); Console.ReadKey(); } } }

Analiza programului Aceast problem determin n paralel att valoarea minim dintr-un vector, ct i cea maxim. Mecanismul de determinare a valorii minime : se ia o variabil MIN care este iniializat cu prima valoare din tablou. Se parcurge apoi tabloul de la a doua poziie pn la ultima i se compar fiecare valoare cu cea din MIN. De cte ori se ntlnete o valoare mai mic dect MIN, acea valoare se atribuie lui MIN. Astfel, la final, variabila MIN va conine cea mai mic valoare din tablou, deci valoarea minim. Mecanismul de determinare a valorii maxime : se ia o variabil MAX care este iniializat cu prima valoare din tablou. Se parcurge apoi tabloul de la a doua poziie pn la ultima i se compar fiecare valoare cu cea din MAX. De cte ori se ntlnete o valoare mai mare dect MAX, acea valoare se atribuie lui MAX. Astfel, la final, variabila MAX va conine cea mai mare valoare din tablou, deci valoarea maxim. 90

28. S se determine primii n termeni ai irului lui Fibonacci. Istoric : Cunoscut i ca Leonardo din Pisa, Fibonacci a trit n secolul XIII i este considerat a fi unul din cei mai talentai matematicieni din Evul Mediu. Unii consider c Fibonacci este cel care a nlocuit sistemul de cifre romane cu cele arabe. irul lui Fibonacci este o secven recursiv de numere, n care fiecare numr se obine din suma precedentelor dou din ir. Primele dou valori se dau i sunt 1 i 1. Secvena numerelor lui Fibonacci a fascinat de-a lungul istoriei pe foarte muli oameni de tiin, matematicieni, fizicieni, biologi, i continu s o fac chiar i n prezent. Formula de recuren: F0=1, F1=1, Fi=Fi-1+Fi-2, i>=2 Program
using System; namespace ConsoleApplication28 { class Program { static void Main() { int i,n,fn,fn_1,fn_2; Console.Write ("Dati nr. de termeni ai sirului: "); n = int.Parse(Console.ReadLine()); fn_1=1; fn_2=1; Console.WriteLine("Fibo(0)=1"); Console.WriteLine("Fibo(1)=1"); for (i = 2; i < n; i++) { fn = fn_1 + fn_2; fn_2 = fn_1; fn_1 = fn; Console.WriteLine("Fibo({0})={1}", i, fn); } Console.ReadKey(); } } }

Analiza programului Acest program dezvolt formula de recuren descris mai sus. Astfel, primii doi termeni, fn_1 i fn_2 sunt iniializai cu 1. Apoi se intr n ciclul for care va calcula termenii irului de la 2 pn la n. Deoarece aceast rezolvare nu folosete tablouri, tot calculul se realizeaz cu ajutorul variabilelor fn_1, fn_2 i fn. Variabila fn reprezint termenul de ordinul i, iar fn_1 i fn_2 sunt predecesorii si de gradul 1 i 2. Pentru urmtorul pas, fn_2 devine vechiul fn_1, iar fn_1 devine fn. Transformarea unui numr din baza de numeraie 10 ntr-o alt baz b: numrul n baza 10 se mparte la b pn cnd se obine ctul 0. n acel moment toate resturile obinute n urma acestor mpriri, luate de la ultimul pn la primul, vor reprezenta numrul n baza b. Ex : 5510=1101112 55:2=27:2=13:2=6:2=3:2=1:2=0 54 26 12 6 2 0 1 1 1 0 1 1 91

Transformarea unui numr dintr-o baz b n baza 10: Se iau toate cifrele numrului n baza b ncepnd cu cea mai din dreapta (considerat poziia 0), se nmulesc cu bpoziia i se adun toate aceste valori. Ceea ce se obine reprezint numrul n baza 10. Ex : 1101112=5510 1*25+1*24+0*23+1*22+1*21+1*20=32+16+4+2+1=55 Ex : 1238=8310 1*82+2*81+3*80=64+16+3=83 Baze de numeraie >=11. O baz b din intervalul [2, 10] utilizeaz cifre din intervalul [0, b-1]. Baza 10 utilizeaz toate cifrele de la 0 la 9, iar alte cifre nu mai exist. Astfel, pentru a reprezenta valori n baze de numeraie mai mari dect 10 sunt necesare i alte simboluri. Aceste simboluri vor fi litere ale alfabetului, ncepnd cu litera A. n felul acesta, baza 16 care este cea mai adesea folosit din bazele mai mari dect 10, pe lng cifrele de la 0 la 9 va mai folosi i literele alfabetului, de la A la F. Uzual spus, cifra 10 va fi reprezentat de litera A,..., cifra 15 va fi reprezentat de litera F. Trecerea din baza 10 ntr-o baz >=10 se face dup acelai mecanism enunat mai sus. Similar, trecerea dintr-o baz >=10 n baza 10 se face dup acelai mecanism enunat mai sus. Ex : 70210=2BE16 702:16=43:16=2:16=0 688 32 0 14 11 2 Ex : 2BE16=70210 2*162+B*161+E*160=2*162+11*161+14*160=512+176+14=702 29. S se transforme un numr natural din baza 10 n baza 2. Ex: 2510=110012 Program
using System; namespace ConsoleApplication29 { class Program { static void Main() { int nr, cifre=0, i; int[] cifbin = new int[20]; Console.Write ("Dati un numr n baza 10: "); nr = int.Parse(Console.ReadLine()); while (nr!=0) { cifbin[cifre]=nr%2; nr=nr/2; cifre++; } Console.Write ("Reprezentarea n baza 2 a nr: ",nr);

92

for (i=cifre-1; i>=0; i--) Console.Write (cifbin[i]); Console.ReadKey(); } } }

Analiza programului Conform teoriei enunate mai sus, pentru a obine numrul din baza 10 n baza 2, nr se mparte la 2 pn cnd se ajunge la 0. Fiecare rest obinut se adaug n tabloul cifbin. La final, acest tablou va conine cifrele n baza 2 ale numrului dat, i se va tipri de la capt spre nceput, tot conform teoriei care spune c numrul n baza b reprezint resturile obinute n urma mpririlor repetate la b, scrise de la ultimul spre primul. 30. S se transforme un numr natural din baza 10 n baza 16. Program
using System; namespace ConsoleApplication30 { class Program { static void Main() { int nr, cifre=0, c=1, i; char [] cifhex = new char [20]; Console.Write ("Dati un numr n baza 10: "); nr=int.Parse(Console.ReadLine()); while (nr!=0) { c=nr%16; if (c <= 9) cifhex[cifre] = (char)(c + 48); else cifhex[cifre] = (char)(c + 55); nr=nr/16; cifre++; } Console.Write ("Reprezentarea n baza 16 este: "); for (i=cifre-1; i>=0; i--) Console.Write (cifhex[i]); Console.ReadKey(); } } }

Analiza programului Conform teoriei enunate mai sus, pentru a obine numrul din baza 10 n baza 16, nr se mparte la 16 pn cnd se ajunge la 0. Fiecare rest obinut se adaug n tabloul cifhex. Trecerea n baza 16 reprezint un caz mai special, deoarece intervin i cifre formate din litere. n acest sens, pentru a memora resturile obinute nu se mai poate folosi un tablou de int, ci unul de char. Dat fiind acest fapt, numerele obinute ca i resturi n urma mpririlor trebuiesc transformate n caractere. 93

Caracterele sunt privite din punctul de vedere al codului lor Unicode. De exemplu, codul Unicode al cifrelor 0-9 se afl n intervalul 48-57. Astfel, pentru a transforma cifra 0 n caracterul 0 (care are codul Unicode 48), va trebui s adunm 48. Dac se vor obine resturile 10-15, acestea vor trebui transformate n caracterele A-F. Codul Unicode al literelor A-F se afl n intervalul 65-70. Astfel, pentru a transforma numrul 10 n caracterul A (care are codul Unicode 65), va trebui s adunm 55. La final, acest tablou va conine cifrele n baza 16 ale numrului dat, i se va tipri de la capt spre nceput, tot conform teoriei care spune c numrul n baza b reprezint resturile obinute n urma mpririlor repetate la b, scrise de la ultimul spre primul. Observaie: n C# exist i o variant mult mai simpl de a obine reprezentarea n baza 16 a unei valori ntregi i anume folosind funcia ToString cu parametrul X astfel:
int nr; Console.Write ("Dati un numr n baza 10: "); nr=int.Parse(Console.ReadLine()); Console.Write ("Numarul in baza 16: "+nr.ToString("X"));

31. S se transforme un numr natural din baza 10 n baza b[2, 9]. Program
using System; namespace ConsoleApplication31 { class Program { static void Main() { int nr, cifre=0, i, b; int[] cifbaza=new int[20]; Console.Write ("Dati un numr n baza 10: "); nr=int.Parse(Console.ReadLine()); Console.Write ("Dati baza de conversie(2-9): "); b=int.Parse(Console.ReadLine()); while (nr!=0) { cifbaza[cifre]=nr%b; nr=nr/b; cifre++; } Console.Write ("Reprez. n baza {0} a nr. este: ", b); for (i=cifre-1; i>=0; i--) Console.Write (cifbaza[i]); Console.ReadKey(); } } }

Analiza programului Conform teoriei enunate mai sus, pentru a obine numrul din baza 10 n baza b, nr se mparte la b pn cnd se ajunge la 0. Fiecare rest obinut se adaug n tabloul cifbaza. La final, acest tablou va conine cifrele n baza b ale numrului dat, i se va tipri de la capt spre nceput, tot conform teoriei care spune c numrul n baza b reprezint resturile obinute n urma mpririlor repetate la b, scrise de la ultimul spre primul. 94

32. S se transforme un numr natural din baza 2 n baza 10. Program


using System; namespace ConsoleApplication32 { class Program { static void Main() { int cifre, p2=1, nb10=0, i, c; Console.Write ("Cte cifre are numrul n baza 2: "); cifre=int.Parse(Console.ReadLine()); Console.WriteLine ("Dati pe rand cifrele numrului n baza 2 incepand din dreapta: "); for (i=1; i<=cifre; i++) { Console.Write ("Cifra {0} : ",i); c=int.Parse(Console.ReadLine()); nb10+=c*p2; p2=p2*2; } Console.WriteLine ("Reprez. n baza 10 a numrului {0} este ", nb10); Console.ReadKey(); } } }

Analiza programului Se citesc pe rnd de la tastatur toate cifrele numrului n baza 2, ncepnd cu cea mai din dreapta (considerat poziia 0), se nmulesc cu 2poziia i se adun toate aceste valori. Ceea ce se obine reprezint numrul n baza 10. 33. S se transforme un numr natural din baza 16 n baza 10.
using System; namespace ConsoleApplication33 { class Program { static void Main() { int cifre, p16 = 1, nb10 = 0; string numr; Console.Write("Dati cifrele de la dreapta la stanga:"); numr = Console.ReadLine(); Console.Write("Reprez. in baza 10 a nr. este: "); foreach (char cb16 in numr) { if (((char)cb16 >= 65) && ((char)cb16 <= 70)) nb10 += (cb16 - 55) * p16; if (((char)cb16 >= 48) && ((char)cb16 <= 57)) nb10 += (cb16 - 48) * p16; p16 = p16 * 16; }

95

Console.Write(nb10); Console.ReadKey(); } } }

Analiza programului Se citesc pe rnd de la tastatur toate cifrele numrului n baza 16, ncepnd cu cea mai din dreapta (considerat poziia 0), ns se citesc ca i caractere datorit posibilelor litere care pot aprea. Pentru a putea face calculul mai departe, aceste caractere trebuiesc transformate n numerele 0-15. Dac este vorba de o cifr, nseamn c are codul Unicode n intervalul 48-57, deci pentru a obine cifra corespunztoare va trebui s scdem 48. Dac este vorba de o liter, nseamn c are codul Unicode n intervalul 65-70, deci pentru a obine numrul corespunztor va trebui s scdem 55. Numerele astfel obinute se nmulesc cu 16poziia i se adun toate aceste valori. Ceea ce se obine reprezint numrul n baza 10. 34. S se transforme un numr natural din baza b[2, 9] n baza 10. Program
using System; namespace ConsoleApplication34 { class Program { static void Main() { int b, cifre, pb=1, nb10=0, i, c; Console.Write ("Dati baza (2-9): "); b=int.Parse(Console.ReadLine()); Console.Write ("Cte cifre are nr n baza {0} ? ", b); cifre=int.Parse(Console.ReadLine()); Console.WriteLine ("Dati pe rand cifrele numrului n baza {0} incepand din dreapta: ", b); for (i=1; i<=cifre; i++) { Console.Write ("Cifra {0} : ",i); c=int.Parse(Console.ReadLine()); nb10+=c*pb; pb=pb*b; } Console.WriteLine ("Reprez. n baza 10 a numrului este {0}", nb10); Console.ReadKey(); } } }

Analiza programului Se citesc pe rnd de la tastatur toate cifrele numrului n baza b, ncepnd cu cea mai din dreapta (considerat poziia 0), se nmulesc cu bpoziia (care se calculeaz progresiv n variabila pb) i se adun toate aceste valori. Ceea ce se obine este stocat n variabila nb10 i reprezint numrul n baza 10. 96

35. Fiind dat un vector de numere ntregi, s se determine cea mai lung secven de numere consecutive aflate n ordine cresctoare. Ex: 1 3 6 9 5 4 2 4 6 8 11 17 15 cea mai lung secven cresctoare este: 2 4 6 8 11 17 Program
using System; namespace ConsoleApplication35 { class Program { static void Main(string[] args) { int n, i, lung=0, lung_max, poz_start, poz_max; Console.Write("Cate elemente are vectorul ? "); n = int.Parse(Console.ReadLine()); int[] a = new int[n]; Console.WriteLine("Dati elementele vectorului :"); for (i = 0; i < n; i++) { Console.Write("a[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } Console.Write("Vectorul: "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); lung_max = 0; poz_max=0; for (i = 0; i < n-1; i++) { poz_start = i; lung = 1; while (i<n-1) { if (a[i] < a[i + 1]) { lung++; i++; } else break; } if (lung > lung_max) { lung_max = lung; poz_max = poz_start; } } Console.WriteLine(); Console.Write("Cea mai lunga secv crescatoare "); Console.WriteLine ("se afla intre pozitiile {0}-{1}", poz_max, poz_max+lung_max-1); Console.Write ("si are {0} elemente: ",lung_max); for (i = poz_max; i < poz_max+lung_max; i++) Console.Write("{0} ", a[i]); Console.ReadKey(); } } }

97

Analiza programului n vederea rezolvrii problemei, se folosesc urmtoarele variabile de tip int: lung care reprezint lungimea secvenei curente lung_max care reprezint cea mai lung secven i care e posibil s fie actualizat de mai multe ori pe parcursul traversrii vectorului poz_start care reprezint poziia din vector la care ncepe secvena curent poz_max care reprezint poziia din vector la care ncepe cea mai lung secven Paii rezolvrii sunt urmtorii: dup ce se citete vectorul de la tastatur, ncepem s l traversm cu ajutorul unei instruciuni for ncepnd cu poziia 0 variabila poz_start este iniializat cu poziia curent din vector, iar lung este iniializat cu 1 n cadrul unei instruciuni while, atta timp ct nu se ajunge la sfritul vectorului, iar valorile sunt n ordine cresctoare, se merge mai departe n vector i se incrementeaz variabila lung n momentul n care ordinea cresctoare nu se mai pstreaz, se compar lungimea secvenei gsite (lung) cu cea mai lung secven de pn atunci (lung_max) i dac este cazul, se actualizeaz lung_max i poz_max la final se afieaz elementele din vector care fac parte din cea mai lung secven cresctoare. 36. Se d un vector de numere ntregi (pozitive i negative). S se transforme vectorul astfel nct toate valorile negative s fie plasate la nceput, iar valorile pozitive dupa ele. Ex: 2 3 -1 5 -3 -4 7 9 10 -5 2 3 10 5 9 7 -4 -3 -1 -5 Program
using System; namespace ConsoleApplication36 { class Program { static void Main(string[] args) { int n, i, j, aux; Console.Write ("Dati n: "); n=int.Parse(Console.ReadLine()); int[] a=new int[n+1]; for (i = 1; i <= n; i++) a[i] = int.Parse(Console.ReadLine()); i = 1; j = n; while (i<j) { if ((a[i] > 0) && (a[j] > 0)) j--; if ((a[i] < 0) && (a[j] < 0)) i++; if ((a[i] < 0) && (a[j] > 0)) { i++;

98

j--; } if ((a[i] > 0) && (a[j] < 0)) { aux = a[i]; a[i] = a[j]; a[j] = aux; i++; j--; } } for (i = 1; i <= n; i++) Console.Write("{0} ", a[i]); Console.ReadLine(); } } }

Analiza programului Se va parcurge vectorul dinspre ambele capete cu ajutorul a doua contoare i i j (i creste, j scade), atta timp ct i<j. Dac se gsete o pereche (pozitiv, negativ) valorile se schimb ntre ele i ambele contoare se modific. Celelalte cazuri posibile presupun diverse modificri ale celor dou contoare: dac a[i]>0 si a[j]>0 atunci j--; dac a[i]<0 i a[j]<0 atunci i++; dac a[i]<0 si a[j]>0 atunci i++, j--. La final se afieaz vectorul rezultat. 37. Fiind dat polinomul de gradul n cu coeficieni reali P(X)=anXn+an-1Xn-1+...+a1X+a0, s se calculeze P(x), unde x este un numr real dat. Ex: P(X)=3X^2-X+1, x=2, P(2)=11 Program
using System; namespace ConsoleApplication37 { class Program { static void Main() { int n, i; float x, p = 0; string semn=""; float[] c = new float[20]; Console.Write("Dati gradul polinomului: "); n = int.Parse(Console.ReadLine()); for (i = n; i >= 0; i--) { Console.Write("coeficient pt x^{0}=", i); c[i] = float.Parse(Console.ReadLine()); } Console.Write("P(X)= "); for (i = n; i >= 1; i--) if (c[i] != 0) {

99

if (c[i] >= 0 && i < n) semn = "+"; if (c[i] == 1) Console.Write(semn + "X^{0}", i); else if (c[i] == -1) Console.Write(semn + "-X^{0}", i); else Console.Write(semn + "{0}*X^{1}",c[i],i); semn = ""; } if (c[0] > 0) Console.Write("+{0}", c[0]); else if (c[0] < 0) Console.Write(c[0]); Console.WriteLine(); Console.Write("Introduceti valoarea lui x="); x = float.Parse(Console.ReadLine()); for (i = 0; i <= n; i++) p = p + c[i] * (float)Math.Pow(x,i); Console.WriteLine("P({0}) = {1}", x, p); Console.ReadKey(); } } }

Analiza programului Dup citirea gradului polinomului n variabila n, se citesc coeficienii polinomului n tabloul c. Valorile se pun n tablou de la poziia n pn la poziia 0, pentru a respecta forma natural a coeficienilor unui polinom (se ncepe de la gradul cel mai mare). Dup aceasta se citete valoarea lui x i se poate merge mai departe la calcularea lui P(x). Pentru a face aceasta, ca i la matematic, se nlocuiete peste tot necunoscuta X cu valoarea concret x i se nmulete cu coeficienii polinomului. Mai trebuiesc fcute i ridicri la putere, iar pentru aceasta s-a optat pentru funcia predefinit n C#, Math.Pow. Aceasta primete ca i parametrii baza i exponentul. Se vor calcula pe rnd perechi aiXi i se vor nsuma. Se observ c pentru afiarea polinomului s-au folosit cteva elemente care s permit o afiare ct mai apropiat de varianta matematic. n cazul n care un coeficient este 0, termenul corespunztor din polinom nu mai este tiprit. Se putea opta i pentru a construi progresiv puterile lui x i a nu mai utiliza funcia Math.Pow. Pentru aceasta, bucata de cod:
for (i=n; i>=0; i--) p = p + c[i] * (float)Math.Pow(x, i);

se nlocuia cu:
int px=1; for (i=0; i<=n; i++) { p = p + c[i] * px; px *= x; }

Observaie: Pentru Math.Pow s-a folosit operatorul de conversie explicit (float), deoarece aceast metod returneaz double i ar fi fost un conflict ntre tipurile de date, p fiind de tip float. 100

38. Fiind dat polinomul de gradul n cu coeficieni reali P(X), s se calculeze P(x)(x-b), unde b este un numr real dat. Program
using System; namespace ConsoleApplication38 { class Program { static void Main() { int n, i, b; string semn = ""; Console.Write("Dati gradul polinomului: "); n = int.Parse(Console.ReadLine()); int[] a = new int[n+1]; int[] ab = new int[n+2]; Console.WriteLine("Introduceti coeficientii lui X"); for (i = n; i >= 0; i--) { Console.Write("Coeficient pt x^{0}=", i); a[i] = int.Parse(Console.ReadLine()); } Console.Write("P(X)= "); for (i = n; i >= 1; i--) if (a[i] != 0) { if (a[i] >= 0 && i < n) semn = "+"; if (a[i]==1) Console.Write(semn + "X^{0}", i); else if (a[i]==-1) Console.Write(semn + "-X^{0}", i); else Console.Write(semn+"{0}*X^{1}", a[i], i); semn = ""; } if (a[0] > 0) Console.Write("+{0}", a[0]); else if (a[0] < 0) Console.Write(a[0]); Console.WriteLine(); Console.Write("Dati valoarea pentru b: "); b = int.Parse(Console.ReadLine()); ab[n + 1] = a[n]; for (i = n; i >= 1; i--) ab[i] = a[i - 1] - b * a[i]; ab[0] = -b * a[0]; Console.Write("P(X)(X-{0})=", b); for (i = n + 1; i >= 1; i--) if (ab[i] != 0) { if (ab[i] >= 0 && i <= n) semn = "+"; if (ab[i] == 1) Console.Write(semn + "X^{0}", i); else if (ab[i] == -1) Console.Write(semn + "-X^{0}", i);

101

else Console.Write(semn+"{0}*X^{1}", ab[i], i); semn = ""; } if (ab[0] > 0) Console.Write("+{0}", ab[0]); else if (ab[0] < 0) Console.Write(ab[0]); Console.ReadKey(); } } }

Analiza programului P(x)(x-b)=x(anXn+an-1Xn-1+...+a1X+a0)-b(anXn+an-1Xn-1+...+a1X+a0)= anXn+1+an-1 banXn-ban-1Xn-1+...-ba1X-ba0 = anXn+1+(an-1-ban) Xn+...+(a1-ba2)X2+(a0-ba1)X-ba0=


i = anXn+1+ ( ai 1 ba i ) X -ba0 i =1 n

Xn+...+a1X2+a0X-

Se observ c noul polinom care se va obine n urma produsului are gradul n+1, iar coeficienii si sunt cei dedui mai sus. Coeficienii de la 1 la n se vor calcula dup formula: coeficientul termenului de grad i este ai-1-bai. Coeficientul de grad n+1 este an, iar coeficientul de grad 0 este -ba0. Pentru afiarea polinomului s-au folosit cteva elemente care s permit o afiare ct mai apropiat de varianta matematic. n cazul n care un coeficient este 0, termenul corespunztor din polinom nu mai este tiprit. 39. S se calculeze derivata de ordin nti a unui polinom de grad n cu coeficieni ntregi, reprezentat cu ajutorul unui vector. Program
using System; namespace ConsoleApplication39 { class Program { static void Main() { int n, i; string semn = ""; Console.Write("Dati gradul polinomului: "); n = int.Parse(Console.ReadLine()); int[] a = new int[n+1]; int[] ad = new int[n]; Console.WriteLine("Introduceti coeficientii lui x"); for (i = n; i >= 0; i--) { Console.Write("Coeficientul pt x^{0}=", i); a[i] = int.Parse(Console.ReadLine()); } Console.Write("P(X)="); for (i = n; i >= 0; i--) if (a[i] != 0) { if (a[i] >= 0 && i < n) semn = "+"; if (i != 0)

102

Console.Write(semn+" {0}*X^{1}", a[i], i); else Console.Write(semn + " " + a[i]); semn = ""; } Console.WriteLine(); for (i = n; i >= 1; i--) ad[i - 1] = a[i] * (i); Console.Write("P'(X)="); for (i = n - 1; i >= 0; i--) if (ad[i] != 0) { if (ad[i] >= 0 && i < n - 1) semn = "+"; if (i != 0) Console.Write(semn+" {0}*X^{1}",ad[i],i); else Console.Write(semn + " " + ad[i]); semn = ""; } Console.ReadKey(); } } }

Analiza programului Dac P(X)=anXn+an-1Xn-1+...+a1X+a0 , atunci P(X)= nanXn-1+(n-1)an-1Xn-2+...+a1 Polinomul care va reprezenta derivata de ordin nti a lui P(X) are gradul n-1, iar coeficienii si se calculeaz dup formula: coeficientul de grad i este egal cu coeficientul de grad i+1 din polinomul iniial, nmulit cu i+1. Pentru afiarea polinomului s-au folosit cteva elemente care s permit o afiare ct mai apropiat de varianta matematic. n cazul n care un coeficient este 0, termenul corespunztor din polinom nu mai este tiprit. 40. S se adauge un element n interiorul unui vector de numere reale, fr a suprascrie elementele deja existente. Program
using System; namespace ConsoleApplication40 { class Program { static void Main() { int n, i, poz, v; Console.Write("Dati dimensiunea tabloului: "); n = int.Parse(Console.ReadLine()); float[] a = new float[n + 1]; Console.WriteLine("Dati elementele tabloului:"); for (i = 0; i < n; i++) { Console.Write("A[{0}]=", i + 1); a[i] = float.Parse(Console.ReadLine());

103

} Console.Write("Pozitia pe care se face inserarea (1-{0} ): ",n); poz = int.Parse(Console.ReadLine()); poz--; if ((poz >= 0) && (poz < n)) // test validitate { Console.Write("Dati valoarea de inserat: "); v = int.Parse(Console.ReadLine()); for (i = n - 1; i >= poz; i--) a[i + 1] = a[i]; a[poz] = v; Console.WriteLine("Vectorul dup inserare:"); for (i = 0; i <= n; i++) Console.Write("{0} ", a[i]); } else Console.Write("Pozitie inexistenta!"); Console.ReadKey(); } } }

Analiza programului Pentru a insera un element pe poziia poz ntr-un vector care deja conine elemente, este necesar ca prima dat s se elibereze poziia poz pentru a nu se scrie peste elementul deja existent acolo. Deoarece captul din stnga al vectorului este fix, elementele de la poziia poz pn la capt vor trebui mutate cu o poziie spre dreapta. Deplasarea teoretic se poate face de la poz la n sau de la n la poz. Practic ns, deplasarea de la poz la n nu funcioneaz corect, deoarece dac se scrie elementul de pe poziia poz pe poziia poz+1, atunci elementul care era pe poziia poz+1 se pierde. n schimb, dac se ncepe de la poziia n, acest element este mutat pe poziia n+1 unde nainte nu exista nimic, iar pe mai departe, elementul de pe poziia n-1 este mutat pe poziia n, ns acum nu mai este o problem, deoarece elementul de pe poziia n a fost deja scris pe poziia n+1, .a.m.d. n momentul cnd toate elementele de la poziia poz pn la n au fost deplasate spre dreapta cu o poziie, se poate citi noua valoare care se va plasa n vector pe poziia poz. nainte de inserare este important s se fac un test pentru a verifica dac poziia introdus de la tastatur este valid. 41. S se tearg un element din interiorul unui vector de numere reale i s se acopere spaiul rmas gol prin deplasarea spre stnga a tuturor elementelor din dreapta sa. Program
using System; namespace ConsoleApplication41 { class Program { static void Main() { int n, i, poz; Console.Write("Dati dimensiunea tabloului: "); n = int.Parse(Console.ReadLine()); float[] a = new float[n]; Console.WriteLine("Introduceti elementele:"); for (i = 0; i < n; i++) {

104

Console.Write("A[{0}]=", i + 1); a[i] = float.Parse(Console.ReadLine()); } Console.Write("Pozitia de pe care se face stergerea (1-{0}): ",n); poz = int.Parse(Console.ReadLine()); poz--; if ((poz >= 0) && (poz < n)) // test validitate { for (i = poz + 1; i < n; i++) a[i - 1] = a[i]; n--; Console.Write("Vectorul dup stergere: "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); } else Console.Write("Pozitie inexistenta!"); Console.ReadKey(); } } }

Analiza programului n momentul cnd se terge un element de pe o poziie poz dintr-un vector, rmne un loc gol care ar trebui acoperit. Pentru a-l acoperi se vor deplasa toate elementele de la poziia poz+1 pn la n cu o poziie spre stnga. De observat i faptul c n urma tergerii unui element, vectorul va avea n-1 elemente. nainte de tergere este important s se fac un test pentru a verifica dac poziia introdus de la tastatur este valid. 42. S se simuleze ciurul lui Eratostene (algoritm cu ajutorul cruia pot fi determinate numerele prime mai mici dect un numr dat) intr-un vector de n numere naturale. Istoric: Geograful i astronomul grec Eratostene din Cirena a avut ideea de a transforma proprietatea numerelor prime de a nu fi multiplii nici unuia din numerele mai mici dect ele, ntr-un criteriu de selecie (cernere) astfel: din irul primelor n numere naturale se elimin pe rnd multiplii lui 2, 3, 5 etc., elementele rmase fiind cele prime. Astfel, 2 fiind prim, din ir se elimin multiplii lui 2 adic 4, 6, 8 etc. Urmtorul numr rmas neeliminat la pasul anterior este 3, deci 3 este prim i se vor elimina numerele 9, 15, 21, etc. (multiplii pari ai lui 3 fiind deja eliminai). i aa mai departe, pn la determinarea tuturor numerelor prime mai mici dect un numr dat. Varianta 1 : Program
using System; namespace ConsoleApplication42 { class Program { static void Main() { int n, i, j; Console.Write ("Dati n: "); n=int.Parse(Console.ReadLine()); int[] c = new int[n+1]; for (i=2; i<=n; i++) c[i]=i;

105

for (i=2; i<=Math.Sqrt(n); i++) if (c[i]!=0) { j=2; while (i*j<=n) { c[i*j]=0; j++; } } for (i=2; i<=n; i++) if (c[i]!=0) Console.Write ("{0} ", c[i]); Console.ReadKey(); } } }

Analiza programului Aceast variant de simulare a ciurului lui Eratostene cu ajutorul unui vector presupune plasarea n vector a tuturor valorilor de la 2 la n. Dup aceasta se va trece la cernerea valorilor care nu sunt prime. Cernerea se face astfel: se parcurg toate valorile de la 2 la n i se elimin toi multiplii lor din vector. Eliminarea const de fapt n setarea pe 0 a valorii acelor multiplii. Ceea ce rmne n final n tablou i este diferit de 0, reprezint toate numerele prime mai mici dect n, care se vor tipri i pe ecran. De ce se merge doar pn la n ? Deoarece n momentul n care s-a ajuns la n , toate valorile de la n pn la n au fost deja eliminate sau sunt numere prime. Demonstraie: Orice valoare x> n , dac nu este numr prim, nseamn c are cel puin 2 divizori. Se tie ns c niciunul din divizori nu poate fi < n , deoarece deja toi multiplii valorilor < n au fost deja eliminai. Ar rmne varianta n care ambii divizori sunt > n , ns deoarece n * n =n, produsul oricror dou valori > n va da o valoare >n. Deci nu exist doi divizori ai lui x, ambii mai mari dect n . Rezult de aici c orice valoare mai mare dect n neeliminat este sigur numr prim. Varianta 2 : Program
using System; namespace ConsoleApplication42b { class Program { static void Main() { int n, i, j; Console.Write ("Dati n: "); n=int.Parse(Console.ReadLine()); int[] c = new int [n+1]; for (i=2; i<=n; i++) c[i]=1; for (i=2; i<=Math.Sqrt(n); i++)

106

if (c[i]!=0) { j=2; while (i*j<=n) { c[i*j]=0; j++; } } for (i=2; i<=n; i++) if (c[i]!=0) Console.Write ("{0} Console.ReadKey(); } } }

", i);

Analiza programului Aceast variant de simulare a ciurului lui Eratostene cu ajutorul unui vector presupune plasarea n vector pe toate poziiile, a valorii 1. Cernerea valorilor care nu sunt prime se face de data aceasta pe baza indicelui de poziie n tablou a elementelor (ex: indicele 2 este considerat ca fiind numrul 2). Se face n felul acesta o anume economie n memorarea de valori n tablou. Cernerea se face astfel: se parcurg toate poziiile de la 2 la n i se seteaz toi multiplii lor din vector pe 0. Indicii elementelor rmase n final n tablou i diferite de 0, reprezint toate numerele prime mai mici dect n, care se vor tipri i pe ecran. 43. S se verifice dac un vector de ntregi citit de la tastatur ndeplinete condiia de mulime (nu are valori duplicate). n caz contrar, s se transforme n mulime (se vor terge valorile duplicate). Exemplu: Vectorul : 1 2 3 1 4 5 1 2 6 2 7 3 8 9 nu este mulime. n urma transformrii el va deveni : 1 2 3 4 5 6 7 8 9 Program
using System; namespace ConsoleApplication43 { class Program { static void Main(string[] args) { int n, i, j, k; Console.Write("Cate elemente are vectorul ? "); n=int.Parse(Console.ReadLine()); int[] a=new int[n]; Console.WriteLine("Dati elementele vectorului :"); for (i = 0; i < n; i++) { Console.Write("a[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } Console.Write("Vectorul: "); for (i = 0; i < n; i++)

107

Console.Write("{0} ", a[i]); for (i = 0; i < n-1; i++) for (j=i+1; j<n; j++) if (a[i] == a[j]) { if (j != n - 1) for (k = j + 1; k < n; k++) a[k - 1] = a[k]; n--; j--; } Console.WriteLine(); Console.Write("Vectorul multime: "); for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); Console.ReadKey(); } } }

Analiza programului Testul de mulime se face astfel: se parcurge vectorul cu un contor i. Oricnd se ajunge la o poziie i, cu ajutorul unei a doua instruciuni for se parcurge bucata de vector [i+1, n]. n cazul n care a[i]=a[j] nseamn ca s-a gsit o pereche de valori duplicate i cea de pe poziia j este tears din vector conform algoritmului de la problema 41. Dup ce va fi parcurs ntregul vector, vom avea toate valorile duplicate eliminate, deci vectorul ndeplinete condiia de mulime i este afiat. 44. Se dau dou mulimi de numere ntregi memorate cu ajutorul vectorilor. S se calculeze reuniunea celor dou mulimi. Program
using System; namespace ConsoleApplication44 { class Program { static void Main() { int n, m, i, j, poz, gsit; Console.Write("Numrul de elem ale primei multimi: "); n = int.Parse(Console.ReadLine()); Console.Write("Numrul de elem ale celei de-a doua multimi: "); m = int.Parse(Console.ReadLine()); int[] a = new int[n+m]; int[] b = new int[m]; Console.WriteLine("Dati elementele multimii 1:"); for (i = 0; i < n; i++) { Console.Write("a[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } Console.WriteLine("Dati elementele multimii 2:");

108

for (i = 0; i < m; i++) { Console.Write("b[{0}]=", i); b[i] = int.Parse(Console.ReadLine()); } poz = n; for (j = 0; j < m; j++) { gsit = 0; for (i = 0; i < n; i++) if (b[j] == a[i]) { gsit = 1; break; } if (gsit == 0) { a[poz] = b[j]; poz++; } } Array.Sort(a); Console.WriteLine("Rezultatul reuniunii: "); n = poz; for (i = 0; i < n; i++) Console.Write("{0} ", a[i]); Console.ReadKey(); } } }

Analiza programului Conform cunotinelor de la matematic se tie c reuniunea a dou mulimi nseamn o nou mulime care reprezint punerea n comun a valorilor celor dou mulimi. Se tie de asemenea c ntr-o mulime nu pot aprea valori duplicate. Programul de mai sus folosete doi vectori a i b pentru reprezentarea mulimilor. Reuniunea se realizeaz astfel: se adaug la captul vectorului a toate valorile din b care nc nu exist n a. Pentru a face aceasta, fiecare element din vectorul b este cutat n vectorul a. Dac este gsit se trece peste el, iar dac nu este gsit se adaug la sfritul lui a. Deoarece dimensiunea iniial a lui a se va modifica pe cum se adaug elemente din b, pentru a cuta elementele din b exclusiv printre cele din a, se va reine ntr-o variabil suplimentar poz numrul curent de elemente din a. Variabila poz se va modific pe parcursul prelucrrii, dar cutarea elementelor din b n a se face tot timpul pn la poziia n, care este numrul iniial de elemente din a. Ex : a: 1 3 4 6; n=4 b: 2 4 5 9; m=4 poz=4 - se caut valoarea 2 n a; nu se gsete se adaug la sfritul lui a; poz=5 a: 1 3 4 6 2 - se caut valoarea 4 n a, pn la poziia n=4; este gsit, deci nu se adaug la a - se caut valoarea 5 n a, pn la poziia n=4; nu se gsete se adaug la sfritul lui a; poz=6 a: 1 3 4 6 2 5 - se caut valoarea 9 n a, pn la poziia n=4; nu se gsete se adaug la sfritul lui a; poz=7 109

a: 1 3 4 6 2 5 9 Se tiprete la final vectorul reuniune a, care are acum poz elemente.

45. S se calculeze intersecia a dou mulimi de numere reale reprezentate cu ajutorul vectorilor. Program
using System; namespace ConsoleApplication45 { class Program { static void Main() { int n, m, q, i, j, poz; bool mvida = true; Console.Write("Numrul de elem ale primei multimi: "); n = int.Parse(Console.ReadLine()); Console.Write("Numrul de elem ale celei de-a doua multimi: "); m = int.Parse(Console.ReadLine()); int[] a = new int[n]; int[] b = new int[m]; q = Math.Min(n, m); int[] c = new int[q]; Console.WriteLine("Dati elementele multimii 1"); for (i = 0; i < n; i++) { Console.Write("a[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } Console.WriteLine("Dati elementele multimii 2"); for (i = 0; i < m; i++) { Console.Write("b[{0}]=", i); b[i] = int.Parse(Console.ReadLine()); } poz = 0; for (i = 0; i < n; i++) for (j = 0; j < m; j++) if (a[i] == b[j]) { c[poz] = a[i]; poz++; mvida = false; break; } Console.Write("Rezultatul intersectiei: "); if (mvida==false) for (i = 0; i < poz; i++) Console.Write("{0} ", c[i]); else Console.WriteLine("multimea vida"); Console.ReadKey(); } } }

Analiza programului Conform cunotinelor de la matematic se tie c intersecia a dou mulimi nseamn o 110

nou mulime care conine toate elementele comune ale celor dou mulimi. Se tie de asemenea c ntr-o mulime nu pot aprea valori duplicate. Programul de mai sus folosete doi vectori a i b pentru reprezentarea mulimilor, iar intersecia se va depune n vectorul c. Intersecia se realizeaz astfel: se parcurge vectorul a element cu element. Fiecare element din a este cutat n vectorul b. Dac este gsit, se adaug acest element la vectorul c, dac nu, se trece mai departe n a. Cutarea se face cu ajutorul a dou instruciuni for imbricate, primul for mergnd pe elementele vectorului a, iar al doilea for merge pe elementele vectorului b. Se tiprete la final vectorul intersecie c, care are poz elemente. Vectorul c va avea cel mult dimensiunea celei mai mici mulimi, dintre a i b. Din acest motiv, numrul de elemente ale lui c a fost stabilit la Math.Min(n, m). (Ex: a are 5 elemente, b are 8 elemente c are maxim 5 elemente). S-a folosit variabila mvida de tip bool care dac mulimea c nu are nici un element are valoarea false. Ea este util pentru a ti la final dac avem ce s afim. 46. S se calculeze diferena A/B a dou mulimi A, B de numere reale reprezentate cu ajutorul vectorilor (diferena semnific elementele care sunt n A i nu sunt i n B). Program
using System; namespace ConsoleApplication46 { class Program { static void Main() { int n, m, i, j, poz; bool mvida = true, gasit; Console.Write("Numrul de elem ale primei multimi: "); n = int.Parse(Console.ReadLine()); Console.Write("Numrul de elem ale celei de-a doua multimi: "); m = int.Parse(Console.ReadLine()); int[] a = new int[n]; int[] b = new int[m]; int[] c = new int[n]; Console.WriteLine("Dati elementele multimii 1"); for (i = 0; i < n; i++) { Console.Write("a[{0}]=", i); a[i] = int.Parse(Console.ReadLine()); } Console.WriteLine("Dati elementele multimii 2"); for (i = 0; i < m; i++) { Console.Write("b[{0}]=", i); b[i] = int.Parse(Console.ReadLine()); } poz = 0; for (i = 0; i < n; i++) { gasit=false; for (j = 0; j < m; j++) if (a[i] == b[j]) {

111

gasit = true; break; } if (gasit==false) { c[poz] = a[i]; mvida=false; poz++; } } Console.Write("A / B= "); if (mvida==false) for (i = 0; i < poz; i++) Console.Write("{0} ", c[i]); else Console.Write("multimea vida"); Console.ReadKey(); } } }

Analiza programului Conform cunotinelor de la matematic se tie c diferena a dou mulimi A/B nseamn o nou mulime care conine toate elementele din A care nu se afl i n B. Programul de mai sus folosete doi vectori a i b pentru reprezentarea mulimilor, iar diferena se va depune n vectorul c. Diferena se realizeaz astfel: se parcurge vectorul a element cu element. Fiecare element din a este cutat n vectorul b. Dac nu este gsit, se adaug acest element la vectorul c, iar dac da, se trece mai departe n a. Cutarea se face cu ajutorul a dou instruciuni for imbricate, primul for mergnd pe elementele vectorului a, iar al doilea for merge pe elementele vectorului b. Se tiprete la final vectorul diferen c, care are poz elemente. Vectorul c a fost definit ca avnd maxim n elemente, attea cte are i vectorul a. S-a folosit variabila mvida de tip bool care dac mulimea c nu are nici un element are valoarea false. Ea este util pentru a ti la final dac avem ce s afim.

112

6.3 MATRICI
47. S se construiasc transpusa unei matrice oarecare de elemente reale. Program
using System; namespace ConsoleApplication47 { class Program { static void Main() { int i, j, m, n; Console.Write("Dati nr de linii ale matricii m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricii n="); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; int[,] ta = new int[n, m]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Elementele matricii : "); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } for (i = 0; i < n; i++) for (j = 0; j < m; j++) ta[i, j] = a[j, i]; Console.WriteLine("Elementele matricii transpuse: "); // Transpusa are n linii i m coloane for (i = 0; i < n; i++) { for (j = 0; j < m; j++) Console.Write(ta[i, j] + " "); Console.WriteLine(); } Console.ReadKey(); } } }

Analiza programului Se tie de la matematic faptul c transpusa unei matrici nseamn inversarea liniilor cu coloanele. Astfel o matrice de dimensiuni (mxn) va avea transpusa de dimensiuni (nxm). n acest program, transpusa se construiete parcurgnd toat matricea a i folosind o a doua matrice ta n care se depun valorile matricei iniiale inversat, adic ceea ce era pe linii n cea iniial se depune pe coloane n a doua: ta[i][j]=a[j][i] (linia j din a se pune pe coloana j din ta, iar coloana i din a se pune pe linia i n ta) i la final se afieaz matricea ta. 113

48. S se interschimbe dou linii (coloane) dintr-o matrice oarecare de elemente reale. Interschimbarea a 2 linii : Program
using System; namespace ConsoleApplication48 { class Program { static void Main() { int i, j, m, n, aux, l1, l2; Console.Write("Dati nr de linii ale matricii m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricii n="); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Elementele matricii :"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } Console.Write("Indicele liniei de schimbat (1-{0}):",m); l1 = int.Parse(Console.ReadLine()); l1--; Console.Write("Indicele liniei cu care se schimba (1-{0}): ", m); l2 = int.Parse(Console.ReadLine()); l2--; for (i = 0; i < n; i++) { aux = a[l1, i]; a[l1, i] = a[l2, i]; a[l2, i] = aux; } Console.WriteLine("Matricea dup interschimbarea liniilor:); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } Console.ReadKey(); } } }

114

Analiza programului Interschimbarea unui linii a matricei cu o alta presupune parcurgerea celor dou linii n paralel i interschimbarea a cte unei perechi de valori de pe aceeai coloan, lucru care se realizeaz cu metoda celor trei pahare prezentat n problema 1. Aici metoda celor trei pahare este folosit n bucata de cod:
for (i=0; i<n; i++) { aux=a[l1][i]; a[l1][i]=a[l2][i]; a[l2][i]=aux; }

n felul acesta, elementul de pe linia l1, coloana i se va schimba cu elementul de pe linia l2, coloana i, iar i merge de la prima pn la ultima coloan de pe o linie, practic pe toat linia. La final se afieaz din nou matricea pentru a se observa interschimbarea liniilor. Pentru un plus de corectitudine, programul ar trebui s testeze validitatea indicilor celor dou linii de interschimbat care se citesc de la tastatur. 49. S se calculeze valoarea maxim dintr-o matrice oarecare de elemente reale i s se afieze toate poziiile din matrice unde se gsete aceasta. Program
using System; namespace ConsoleApplication49 { class Program { static void Main() { int m, n, i, j, max; Console.Write("Dati nr de linii ale matricei m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricei n="); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Matricea introdusa:"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } max = a[0, 0]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) if (a[i, j] > max) max = a[i, j]; Console.WriteLine("Maximul= {0} i se afla pe pozitiile : ", max);

115

for (i = 0; i < m; i++) for (j = 0; j < n; j++) if (a[i, j] == max) Console.WriteLine("({0},{1}) Console.ReadKey(); } } }

", i+1,j+1);

Analiza programului Rezolvarea acestei probleme seamn cu cea a gsirii valorii maxime dintr-un vector. i aici se ia o variabil max care este iniializat cu prima valoare din matrice (valoarea de pe prima linie i prima coloan). Se parcurge apoi toat matricea i se compar fiecare valoare cu cea din max. De cte ori se ntlnete o valoare mai mare dect max, acea valoare se atribuie lui max. Astfel, la final, variabila max va conine cea mai mare valoare din matrice, deci valoarea maxim. Pentru a afia toate poziiile din matrice unde se gsete valoarea maxim trebuie parcurs din nou toat matricea i fiecare element al ei este comparat cu maximul. Dac sunt egale, se tiprete linia i coloana acelui element. 50. S se calculeze valoarea minim dintr-o matrice oarecare de elemente reale i s se afieze numrul de apariii a acestei valori n matrice. Program
using System; namespace ConsoleApplication50 { class Program { static void Main() { int m, n, i, j, min, c = 0; Console.Write("Dati nr de linii ale matricei : "); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricei :"); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Matricea introdusa:"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } min = a[0, 0];

116

for (i = 0; i < m; i++) for (j = 0; j < n; j++) { if (a[i, j] < min) { min = a[i, j]; c = 1; } if (a[i, j] == min) c++; } Console.Write("Minimul={0} i apare n matrice de {1} ori", min, c); Console.ReadKey(); } } }

Analiza programului Rezolvarea acestei probleme seamn cu cea a gsirii valorii minime dintr-un vector. i aici se ia o variabil min care este iniializat cu prima valoare din matrice (valoarea de pe prima linie i prima coloan). Se parcurge apoi toat matricea i se compar fiecare valoare cu cea din min. De cte ori se ntlnete o valoare mai mic dect min, acea valoare se atribuie lui min. Astfel, la final, variabila min va conine cea mai mic valoare din matrice, deci valoarea minim. Pentru a afia numrul de apariii al valorii minime n matrice exist cel puin dou variante : 1) dup aflarea minimului s se mai parcurg o dat toat matricea i s se numere de cte ori este ntlnit valoarea minim sau 2) numrul de apariii s se calculeze odat cu calculul valorii minime, astfel : iniial numrul de apariii c este setat pe 1. Dac este gsit n matrice o valoare egal cu minimul temporar, se incrementeaz numrul de apariii. Dac minimul este modificat, se iniializeaz din nou numrul de apariii cu 1. 51. S se calculeze suma elementelor de pe diagonala principal dintr-o matrice ptratic de elemente ntregi. Program
using System; namespace ConsoleApplication51 { class Program { static void Main() { int m, i, j, suma = 0; Console.Write("Dati nr de linii/coloane ale matricei patratice:"); m = int.Parse(Console.ReadLine()); int[,] a = new int[m, m]; for (i = 0; i < m; i++) for (j = 0; j < m; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Matricea introdusa: "); for (i = 0; i < m; i++)

117

{ for (j = 0; j < m; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } for (i = 0; i < m; i++) suma = suma + a[i, i]; Console.Write("Suma elem. de pe diag. principala = {0}", suma); Console.ReadKey(); } } }

Analiza programului Toate elementele de pe diagonala principal a unei matrice ptratice au proprietatea c indicele liniei este acelai indicele coloanei. Astfel, se vor nsuma toate elementele din matrice de forma ai,i , unde i merge pe toate liniile (coloanele) matricei. 52. S se calculeze suma elementelor de pe diagonala secundara dintr-o matrice ptratic de elemente ntregi. Program // declararea, citirea i tiprirea matricei ca i la problema 51. //calcul suma:
for (i = 0; i < m; i++) suma = suma + a[i, m - i - 1]; Console.Write("Suma elementelor de pe diagonala secundara={0}", suma);

Analiza programului Toate elementele de pe diagonala secundar a unei matrice ptratice de dimensiune m au proprietatea c indicele coloanei este egal cu m-indicele liniei pe care se afl. Astfel, la modul general, se vor nsuma toate elementele din matrice de forma ai,m-i-1 , unde i merge pe toate liniile (coloanele) matricei. De exemplu, ntr-o matrice ptratic de dimensiune 4, elementele de pe diagonala secundar au indicii (dac numerotarea ncepe de la 0): (0, 3), (1, 2), (2, 1), (2, 0). 53. S se calculeze suma elementelor din triunghiul de deasupra diagonalei principale dintr-o matrice ptratic de elemente ntregi. Program // declararea, citirea i tiprirea matricei ca i la problema 51. //calcul suma:
for (i = 0; i < m for (j = i + 1; suma = suma Console.Write("Suma 1; i++) j < m; j++) + a[i,j]; elem. de deasupra diag principale = {0}", suma);

Analiza programului Elementele de deasupra diagonalei principale a unei matrici ptratice de dimensiune m au 118

proprietatea c se afl pe liniile (dac numerotarea ncepe de la 0) i0..m-2, iar pe aceste linii se afl pe coloanele ji+1..m-1. n acest sens, sunt necesare dou instruciuni for care s parcurg liniile i coloanele corespunztoare i s nsumeze valorile. 54. S se calculeze suma elementelor din triunghiul de sub diagonala principala dintr-o matrice ptratic de elemente ntregi. Program // declararea, citirea i tiprirea matricei ca i la problema 51. //calcul suma:
for (i = 1; i < m; i++) for (j = 0; j < i; j++) suma = suma + a[i,j]; Console.Write("Suma elem. de sub diag. principala = {0}", suma);

Analiza programului Elementele de sub diagonala principal a unei matrice ptratice de dimensiune m au proprietatea c se afl pe liniile (dac numerotarea ncepe de la 0) i1..m-1, iar pe aceste linii se afl pe coloanele j0..i-1. n acest sens, sunt necesare dou instruciuni for care s parcurg liniile i coloanele corespunztoare i s nsumeze valorile. 55. S se calculeze suma elementelor din triunghiul de deasupra diagonalei secundare dintr-o matrice ptratic de elemente ntregi. Program // declararea, citirea i tiprirea matricei ca i la problema 51. //calcul suma:
for (i = 0; i < m for (j = 0; j < suma = suma Console.Write("Suma 1; i++) m - i - 1; j++) + a[i, j]; elem de deasupra diag. secundare = {0}", suma);

Analiza programului Elementele de deasupra diagonalei secundare a unei matrici ptratice de dimensiune m au proprietatea c se afl pe liniile (dac numerotarea ncepe de la 0) i0..m-2, iar pe aceste linii se afl pe coloanele j0..m-i-2. n acest sens, sunt necesare dou instruciuni for care s parcurg liniile i coloanele corespunztoare i s nsumeze valorile. 56. S se calculeze suma elementelor din triunghiul de sub diagonala secundara dintr-o matrice ptratic de elemente ntregi. Program // declararea, citirea i tiprirea matricei ca i la problema 51. //calcul suma:
for (i = 1; i < m; i++) for (j = m - i; j < m; j++) suma = suma + a[i, j]; Console.Write("Suma elem de sub diag. secundara = {0}", suma);

Analiza programului Elementele de sub diagonala secundar a unei matrice ptratice de dimensiune m au proprietatea c se afl pe liniile (dac numerotarea ncepe de la 0) i1..m-1, iar pe aceste linii se afl pe coloanele jm-i..m-1. n acest sens, sunt necesare dou instruciuni for care s parcurg 119

liniile i coloanele corespunztoare i s nsumeze valorile. 57. S se verifice care dintre liniile unei matrice oarecare de elemente ntregi este simetric (elementele egal deprtate de capetele liniei sunt egale). Program
using System; namespace ConsoleApplication64 { class Program { static void Main() { int m, n, i, j; bool egale; Console.Write("Dati nr de linii ale matricei m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricei n="); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Matricea introdusa: "); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } for (i = 0; i < m; i++) { egale = true; for (j = 0; j < n / 2; j++) if (a[i, j] != a[i, n - j - 1]) egale = false; if (egale == true) Console.WriteLine("Linia {0} este simetrica", i+1); } Console.ReadKey(); } } }

Analiza programului Pentru a determina dac o linie dintr-o matrice este simetric, se parcurge acea linie pn la jumtate i se compar pe rnd fiecare element din prima jumtate a liniei cu simetricul su din cealalt jumtate (dac numerotarea ncepe de la 0 i e vorba de poziia j din prima jumtate dintrun total de n elemente, atunci simetricul su este n-j-1). 120

Pentru a rezolva problema, se parcurg toate liniile matricei, i pentru fiecare linie se aplic raionamentul enunat mai sus. Se va ncepe de fiecare dat prin a presupune c linia este simetric. Dac cumva n linie este gsit o pereche de valori simetrice care nu sunt egale, concluzia va fi c linia respectiv nu este simetric. 58. S se calculeze produsul dintre o matrice i un vector de elemente ntregi. Program
using System; namespace ConsoleApplication58 { class Program { static void Main() { int m, n, i, j; Console.Write("Dati nr de linii ale matricei m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de coloane ale matricei n="); n = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; int[] b = new int[n]; int[] c = new int[m]; for (i = 0; i < m; i++) for (j = 0; j < n; j++) { Console.Write("a[{0},{1}]=", i, j); a[i, j] = int.Parse(Console.ReadLine()); } Console.WriteLine("Dati elementele vectorului:"); for (i = 0; i < n; i++) { Console.Write("b[{0}]=", i); b[i] = int.Parse(Console.ReadLine()); } Console.WriteLine("Matricea introdusa:"); for (i = 0; i < m; i++) { for (j = 0; j < n; j++) Console.Write(a[i, j] + " "); Console.WriteLine(); } Console.WriteLine("Vectorul introdus: "); for (i = 0; i < n; i++) Console.WriteLine(b[i] + " "); for (i = 0; i < m; i++) { c[i] = 0; for (j = 0; j < n; j++) c[i] += a[i, j] * b[j]; } Console.WriteLine(); Console.WriteLine("Rezultatul produsului matrice x vector: "); for (i = 0; i < m; i++) Console.WriteLine(c[i] + " "); Console.ReadKey(); } } }

121

Analiza programului Produsul dintre o matrice i un vector se poate face prin nmulirea vectorului la dreapta sau la stnga matricei. Acest program face nmulirea la dreapta. Pentru ca nmulirea s fie posibil, matricea trebuie s aib dimensiunea (mxn), iar vectorul trebuie s aib n elemente. Rezultatul nmulirii va fi un vector cu m elemente. n program este folosit matricea a de dimensiune (mxn) care urmeaz a fi nmulit cu vectorul b de dimensiune (n), iar rezultatul se va depune n vectorul c de dimensiune (m). Vectorul c se calculeaz dup formula: ci=ai,j*bj, j0..n-1, iar i0..m-1. Se observ c n program au fost necesare dou instruciuni for, pentru a parcurge cu i liniile matricei i cu j coloanele. Pentru fiecare linie i din matrice va exista cte un ci. La final se afieaz vectorul rezultat c. 59. S se calculeze produsul a dou matrice de elemente ntregi de forma (m,n) i (n,p). Cu funcii: Program
using System; namespace ConsoleApplication59 { class Program { static void citire(int[,] matrice, int l, int c) { int i, j; for (i = 0; i < l; i++) for (j = 0; j < c; j++) { Console.Write("[{0},{1}]=", i, j); matrice[i, j] = int.Parse(Console.ReadLine()); } } static void tiparire(int[,] matrice, int l, int c) { int i, j; for (i = 0; i < l; i++) { for (j = 0; j < c; j++) Console.Write(matrice[i, j] + " "); Console.WriteLine(); } } static void Main() { int m, n, p, i, j, k; Console.Write("Dati nr de linii ale matricei A: m="); m = int.Parse(Console.ReadLine()); Console.Write("Dati nr de col ale matricei A: n="); n = int.Parse(Console.ReadLine()); Console.Write("Dati nr de col. ale matricei B: p="); p = int.Parse(Console.ReadLine()); int[,] a = new int[m, n]; int[,] b = new int[n, p]; int[,] c = new int[m, p]; Console.WriteLine(); Console.WriteLine("Dati elementele matricei A:");

122

citire(a, m, n); Console.WriteLine(); Console.WriteLine("Dati elementele matricei B:"); citire(b, n, p); Console.WriteLine(); Console.WriteLine("Matricea A:"); tiparire(a, m, n); Console.WriteLine(); Console.WriteLine("Matricea B:"); tiparire(b, n, p); Console.WriteLine(); //produsul 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] += a[i, k] * b[k, j]; } Console.WriteLine("Matricea produs A x B:"); tiparire(c, m, p); Console.ReadKey(); } } }

Analiza programului Pentru ca produsul celor dou matrice s fie posibil, este necesar ca prima s aib dimensiunea (mxn), iar cea de-a doua dimensiunea (nxp). Cu alte cuvinte, numrul de coloane al primei s fie egal cu numrul de coloane al celei de-a doua. Rezultatul nmulirii este tot o matrice, de dimensiune (mxp). n program este folosit matricea a de dimensiune (mxn) care urmeaz a fi nmulit cu matricea b de dimensiune (nxp), iar rezultatul se va depune n matricea c de dimensiune (mxp). Valorile lui c se calculeaz dup formula: ci,j= ai ,k * bk , j , iar i0..m-1, iar j0..n-1.
k =0 n 1

Se observ c n program au fost necesare trei instruciuni for, una pentru a parcurge cu i liniile matricei a, una pentru a parcurge cu j coloanele lui b i una pentru a parcurge cu k coloanele lui a. La final se afieaz rezultatul nmulirii aflat n matricea c. S-a construit o funcie pentru citirea unei matrice i una pentru afiarea unei matrice, pentru a nu repeta de mai multe ori acelai cod n funcia Main().

123

124

BIBLIOGRAFIE
1. Jeff Ferguson, Brian Patterson, Jason Beres, Pierre Boutquin, and Meeta Gupta - C# Bible, 2002, Wiley Publishing. 2. Daniel Solis- Illustrated C# 2005, Apress, 2006. 3. Herbert Schildt - C#: A begginers Guide, McGraw-Hill Company, 2001 4. Faraz Rasheed - Programmers Heaven: C# School, Synchron Data, 2006. 5. Charles Petzold - Programming Microsoft Windows with C# (Microsoft), 2002. 6. Andy Harris - Microsoft C# Programming for the Absolute Beginner, Course Technology, 2002. 7. Michael Mcmillan - Data Structures And Algorithms Using C#, Cambridge University Press, 2007. 8. Jack Purdum Beginning - C# 3.0, Wiley Publishing, Inc., 2007. 9. Carmen Fifor Introducere n programare. Limbajul C teorie i probleme rezolvate, Ed. Univ. Aurel Vlaicu Arad, 2007 P.O.O. 1. Grady Booch, Robert A. Maksimchuk, Michael W. Engle, Bobbi J. Young, Ph.D. Jim Conallen, Kelli A. Houston - Object-Oriented Analysis and Design with Applications, Third Edition, Pearson Education, Inc., 2007. Software Visual Studio 2010 Express Editions - http://www.microsoft.com/Express/ Visual Studio Professional - http://msdn.microsoft.com/enus/vstudio/products/aa700831.aspx

125

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