Differences

This shows you the differences between two versions of the page.

Link to this comparison view

programare-cc:laboratoare:02 [2020/10/12 23:40]
viorel.mocanu
programare-cc:laboratoare:02 [2023/09/26 17:05] (current)
mihai.nan
Line 1: Line 1:
-===== Laboratorul ​02 =====+===== Laborator ​02 - Funcții de citire și scriere  ​=====
  
 +==== Breviar ====
  
 +**În acest laborator veţi învăţa să:**
  
 +  * Compilaţi şi rulaţi programe în C, sub Linux, din linia de comandă
 +  * Editaţi programe folosind mediul integrat de dezvoltare Code::​Blocks
 +  * Faceţi afişare şi citire formatată
 +  * Folosiţi corect flag-urile de formatare
 +  * Folosiţi corect specificatorii de format
 +
 +**Implementarea programelor:​ editare şi compilare**
 +
 +Atunci când dorim să implementăm un program, primul pas îl reprezintă scrierea instrucţiunilor acestuia într-un limbaj de programare (în acest caz, limbajul C). Pentru a realiza acest lucru se poate folosi orice editor simplu de texte, de exemplu:
 +
 +  * Sub **Windows**:​ Notepad, Notepad++, EditPlus
 +  * Sub **Linux**: kate, vim, emacs, gedit, mousepad
 +  * Sub **Mac OS**: emacs, TextMate
 +
 +
 +Fişierul astfel obţinut este un simplu fişier text şi se numeşte **fişier sursă**. Conţinutul unui fişier sursă se numeşte **cod sursă**. Fişierele sursă pentru limbajul C au in mod convenţional extensia .c.
 +
 +În continuare, pentru a obţine un program executabil, avem nevoie de un **compilator** specific limbajului care sa "​traducă"​ codul sursă în instrucţiuni specifice procesorului. Conţinutul fişierului executabil rezultat se numeşte cod maşină, iar fişierele compilate (nu neapărat executabile) poartă numele de **fişiere binare**.
 +
 +Există numeroase compilatoare pentru limbajul C. Cel mai cunoscut si mai răspândit este de departe gcc (denumirea vine de la GNU C Compiler), care poate fi instalat atât pe Linux, cât şi pe Windows sau Mac OS.
 +
 +Există, bineînţeles,​ şi altele:
 +
 +  *   ​Microsoft C (doar pentru Windows)
 +  *   ​Borland C Compiler (doar pentru Windows si DOS)
 +  *   LCC (disponibil pentru Windows, Linux şi OS X -- folosit pentru a compila maşinile virtuale pentru Quake III)
 +
 +
 +**Cerinţă**
 +
 +  * Deschideţi un editor de texte (de exemplu, VS Code sau GEdit) şi scrieţi următorul cod C:
 +
 +<code c>
 +#include <​stdio.h>​
 +
 +int main()
 +{
 +    printf("​Programarea Calculatoarelor\n"​);​
 +    return 0;
 +}
 +</​code>​
 +
 +  * Salvaţi fişierul în directorul **$HOME** cu numele **exemplu.c**.
 +  * Deschideţi un terminal şi introduceţi comanda: //gcc exemplu.c//
 +  * Executabilul creat se va numi implicit **a.out**. Pentru a-l rula, folosiţi comanda: **./​a.out**!
 +
 +Puteţi specifica voi un nume pentru fişierul executabil cu ajutorul opţiunii -o astfel:
 +
 +  * gcc -o exemplu exemplu.c
 +
 +**Folosirea unui mediu integrat de dezvoltare (IDE): Code::​Blocks**
 +
 +Pentru a putea folosi Code::​Blocks pe sistemele Linux, trebuie să îl instalaţi folosind comanda:
 +
 +  * sudo apt-get install codeblocks
 +
 +Mai ales la început, vi s-ar putea părea mai uşor să folosiţi un mediu de programare care vă permite să editaţi codul sursă şi să compilaţi şi rulaţi programele direct dintr-o interfaţă grafică. Există foarte multe medii integrate de dezvoltare pentru limbajul C, fiecare cu avantajele şi dezavantajele sale. Dintre cele mai cunoscute, amintim doar câteva:
 +
 +  * Code::​Blocks (pentru Windows, Linux şi Mac)
 +  * DevCpp (preponderent Windows, dar şi Linux)
 +  * Microsoft Visual Studio (pentru Windows)
 +  * Eclipse (pentru Windows, Linux şi Mac)
 +  * KDevelop (preponderent Linux, dar practic Cross-Platform)
 +  * Anjuta (pentru Linux şi Mac)
 +
 +Vă încurajăm să le încercaţi în timpul liber pentru a vă forma o părere despre care vi se potriveşte mai bine :-).
 +
 +**Cerinţă**
 +
 +Deschideţi Code::​Blocks şi creaţi un nou fişier ( File -> New -> Empty File ).
 +
 +Copiaţi programul de mai sus şi salvaţi-l. Compilaţi şi rulaţi programul (folosind meniul, iconiţele, shortcut-urile etc).
 +
 +Pentru depanarea programelor va fi necesar să creaţi un nou proiect (// File -> New -> Project// ). Alegeţi Console Application şi în fereastra următoare, limbajul C. Completaţi numele proiectului şi calea unde doriţi să fie creat (de exemplu, în **$HOME**).
 +
 +Copiaţi următorul program:
 +
 +<code c>
 +
 +#include <​stdio.h>​
 +
 +int main()
 +{
 +    int a, b, rest;
 +    a = 150;
 +    b = 84;
 +    while (b > 0) {
 +        rest = a % b;
 +        a = b;
 +        b = rest;
 +    }
 +    printf("​cmmdc(150,​ 84) = %d\n", a);
 +    getchar();
 +    return 0;
 +}
 +
 +</​code>​
 +
 +Adăugaţi un breakpoint la linia a = 150; (click la dreapta numărului corespunzător liniei) şi porniţi programul în modul de depanare (debugging) cu ajutorul tastei F8. Pentru a urmări valorile unor variabile pe parcursul execuţiei programului pas cu pas, faceţi vizibilă fereastra watch (_Debug -> Debugging Windows -> Watches_) şi adăugaţi numele variabilelor pe care vreţi să le monitorizaţi (click dreapta în interiorul ferestrei şi alegeţi //Add Watch//). Rulaţi programul instrucţiune cu instrucţiune (cu ajutorul tastei F7) şi urmăriţi cum se modifică valorile variabilelor.
 +
 +Încercaţi să vă familiarizaţi cu editorul şi cu debuggerul şi cereţi explicaţii suplimentare dacă este cazul.
 +
 +**Despre citirea şi scrierea în C**
 +
 +În limbajul C, cele mai utilizate funcţii standard pentru citirea şi afişrea datelor sunt **printf** şi **scanf**, definite în biblioteca <​stdio.h>​
 +
 +
 +**Citirea datelor**
 +
 +Vom ilustra folosirea funcţiei **scanf** printr-un exemplu:
 +
 +<code c>
 +
 +int a;
 +float b;
 +unsigned int c;
 +scanf("​%d%f%u",​ &a, &b, &c);
 +
 +</​code>​
 +
 +Primul parametru al funcţiei scanf este un şir între ghilimele alcătuit dintr-o succesiune de specificatori de forma **%_**, unde al doilea caracter este o litera. Acest şir de specificatori descrie datele pe care le va citi funcţia. În continuare, urmează o lista de nume de variabile precedate de **&**, care descrie variabilele în care se vor stoca datele citite.
 +
 +<note warning>​O greşeală frecventă este să uitaţi să puneţi operatorul **&** înainte numelor variabilelor ce vor fi citite!</​note>​
 +<note important>​Este foarte important ca numărul de variabile să fie egal cu numărul de specificatori din interiorul şirului! În caz contrar, programul vostru se va comporta imprevizibil!</​note>​
 +<note important>​ Este foarte important ca tipul şi ordinea variabilelor să se potrivească,​ cu tipul şi ordinea specificatorilor! În caz contrar, programul vostru se va comporta imprevizibil!</​note>​
 +<note important>​Atunci când vreţi doar să citiţi date, nu puneţi şi alte caractere în şirul de specificatori. Nu scrieţi apeluri de forma <​del>​scanf("​Numarul N = %d", &​n);</​del>​. Folosiţi în schimb:</​note>​
 +
 +<code c>
 +printf("​Numarul N = ");
 +scanf("​%d",​ &n);
 +</​code>​
 +
 +**Scrierea datelor**
 +
 +Ca şi la citire, vom ilustra folosirea funcţiei **printf** printr-un exemplu:
 +
 +<code c>
 +printf("​Ana are %d mere. Ele costa %.2f RON/​kg.",​ n, price);
 +</​code>​
 +
 +Sintaxa este asemănătoare cu sintaxa pentru funcţia scanf, dar există câteva diferenţe. Şirul dintre ghilimele poate conţine şi alt text pe lângă specificatorii de format. La execuţie, specificatorii vor fi pur şi simplu înlocuiţi cu valorile preluate din lista de parametri.
 +
 +De asemenea, nu trebuie să precedaţi variabilele din lista de valori cu &, şi nu sunteţi obligaţi nici să specificaţi variabile în acea listă, putând insera şi constante numerice sau valori returnate de apeluri de funcţii. De exemplu:
 +
 +<code c>
 +printf("​sin(1 rad) = %f", sin(1));
 +printf("​Codul ASCII al literei '​A'​ este: %d", '​A'​);​
 +</​code>​
 +
 +<note important>​ În continuare, trebuie să verificaţi că ordinea şi tipul specificatorilor corespunde cu ordinea şi tipul valorilor afişate. În caz contrar, programul vostru se va comporta imprevizibil!</​note>​
 +
 +**Descriptorii de formatare au următorul prototip (ce se afla între [ ] este optional):​**
 +
 +//​%[flags][lăţime][.precizie][specificatori de lungime]specificatori de tip//
 +
 +  * flags:
 +      * **-** Valoarea afişată va fi aliniată la stânga
 +      * **+** (pentru numere: int, float, etc.) Forţează afişarea semnului şi pentru numerele pozitive
 +      * **#** Modifică suplimentar afişarea (vezi explicaţie la fiecare specificator)
 +      * **0** (pentru numere) Completează cu zerouri până la atingerea lăţimii câmpului
 +  * lăţime şi precizie sunt specificate fie prin întregi, fie prin caracterul *, caz în care vor fi trimise ca parametri. De exemplu: <code c> printf("​%*d",​ 10, i); </​code>​
 +  va afişa întregul **i** pe **10** spaţii (aliniat la dreapta). De exemplu, dacă **i** este egal cu **1000**, atunci el va fi precedat de **6** spaţii astfel: **______1000**. ​
 +  * specificatorii de lungime: ​
 +    *  **hh** char 
 +    *  **h** short ​
 +    *  **l** long ​
 +    *  **ll** long long 
 +    *  **L** long double
 +  * specificatorii de tip: 
 +    * **d**, **i** întreg ​
 +    * **o** întreg în baza 8 
 +    * **x**, **X** întreg în baza 16 (fără 0x la Început - folosiţi # pentru a afişa şi 0x) folosind abcdef sau ABCDEF ​
 +    * **u** întreg fără semn 
 +    * **c** caracter ​
 +    * **s** şir de caractere ​
 +    * **f** număr real în format cu virgulă (de exemplu, -56.340000) ​
 +    * **e** număr real în format mantisă-exponent (de exemplu -5.634000e+001) ​
 +    * **g** număr real în format %e daca numărul este mai mic de 1e-4 sau decât precizia specficată,​ altfel în format %f, dar fără 0-uri la sfârşit (de exemplu -56.34)
 +
 +Pentru formatele //f, e// şi //g//, folosirea //#// forţează afişarea punctului zecimal, chiar dacă numărul afişat nu are cifre zecimale.
 +
 +Mai găsiţi detalii şi pe: [[http://​www.cplusplus.com/​reference/​cstdio/​printf/​]]
 +
 +==== Probleme propuse ====
 +
 +=== Problema 1 ===
 +
 +Problema generării unor numere aleatoare poate fi considerată iniţial una complicată,​ dar limbajul C ne pune la dispoziţie biblioteca **stdlib**, cu ajutorul căreia lucrurile vor deveni foarte simple. Funcţiile şi constantele acestei biblioteci sunt declarate în header-ul **stdlib.h** pe care va trebui să-l includeţi la începutul programului pe care îl scrieţi.
 +
 +Utilizând funcţia **rand()** veţi genera numere aleatoare cu valori cuprinse între **0** si **RAND_MAX**,​ unde **RAND_MAX** este o constanta definită în **stdlib.h**,​ având în general valoarea maximă a tipului **int**.
 +
 +Valorile returnate de această funcţie sunt de fapt termenii unui şir de numere generat după o anumită formula ce foloseşte ca punct de plecare o valoare dată. Din cauza acestui aspect, pentru aceeasi valoare iniţială fixată, programul va genera la fiecare rulare aceleaţi numere aleatoare. Pentru a evita acest lucru, biblioteca pune la dispozitie funcţia **srand()** care primeşte ca parametru un număr întreg reprezentând valoarea iniţiala utilizată în calcularea şirului de numere aleatoare.
 +
 +Astfel, paşii pentru rezolvarea problemei noastre sunt următorii :
 +
 +<code c>
 +
 +// fixarea valorii utilizate în generarea numerelor:
 +srand( seed ); // unde seed este o valoare de tip intreg;
 +// obţinerea unui număr pseudoaleator: ​
 +n = rand(); // unde n este numarul intreg generat aleator;
 +
 +</​code>​
 +
 +<note important>​Pentru a garanta că la fiecare rulare a programului valoarea seed este unică, recomandăm apelarea funcţiei srand cu ora locală a calculatorului în secunde. (Acest lucru va fi prezentat în laboratoarele următoare)</​note>​
 +
 +Afişati pe ecran o linie conţinând 3 numere întregi, separate prin spaţiu, generate în mod aleator.
 +Rulaţi programul de mai multe ori cu aceeasi valoare seed. Ce observaţi ?
 +Schimbaţi valoarea seed şi rulaţi din nou. Ce observaţi ?
 +
 +=== Problema 2 ===
 +
 +Scrieţi un program care citeşte şi apoi afişează 3 numere de tip **float** pe aceeaşi linie, separate prin câte un spaţiu, folosind, succesiv, descriptorii **%f**, **%e** şi **%g** pentru cele 3 valori. Folosiţi, pe rând, următoarele date de intrare:
 +
 +  * 1e2 1e2 1e2
 +  * 23.22e+03 23.22e+3 23.22e+03
 +  * 21 1201 122234215001
 +
 +
 +<note tip>
 +  * nu contează în ce format introducem datele de intrare (normal sau exponenţial),​ atât timp cât ele sunt scrise corect, vor fi citite de către **scanf()**
 +  * **%g** afişeaza, în funcţie de mărimea numărului, fie în format **%f** (dar fără zerouri la sfârşit), fie în format **%e**, scopul fiind să ocupe cât mai puţin spaţiu numărul afişat
 +</​note>​
 +
 +=== Problema 3 ===
 +
 +Programul următor afişează valorile funcţiei **sin(x)** pentru valori ale lui x între **0** şi **2*PI**, cu pasul **PI/10.**
 +
 +<code c>
 +#include <​stdio.h> ​
 +#include <​math.h> ​
 +
 +int main() ​
 +
 +     ​double x, PI = M_PI;
 +     for (x = 0; x <= 2 * PI; x = x + PI / 10) {
 +          printf("​%lf \n", sin(x)); ​
 +     }
 +     ​getchar(); ​
 +     ​return 0; 
 +}
 +</​code>​
 +
 +Modificaţi programul astfel încat pentru fiecare x între **0** şi **2*PI** cu pasul **PI/20** să fie afişate valorile lui x şi ale funcţiilor **sin(x)**, **cos(x)** sub formă de tabel. Adăugati apoi un cap de tabel şi modificaţi programul astfel încat fiecare coloană din tabel să aibă 8 caractere, iar numerele să fie afişate cu 3 zecimale şi semnul + să apară în faţa numerelor pozitive.
 +
 +<note tip>​Pentru a folosi funcţiile din **math.**h trebuie să adăugaţi opţiunea **-lm** la compilare.</​note>​
 +
 +^ Intrare ​     ^ Ieşire ​      ^
 +| Programul nu are date de intrare. \\ Observaţie:​ punctele mediane din exemplul \\ alăturat sunt doar pentru a vă ajuta să \\ număraţi spaţierea! \\ Ele nu trebuie afişate! ​   | ¦·······x¦··sin(x)¦··cos(x)¦ \\ ¦==================¦ \\ ¦··+0.000¦··+0.000¦··+1.000¦ \\ .......................................... ​  |
 +
 +
 +=== Problema 4 ===
 +
 +Scrieţi un program care să determine cadranul în care se află un punct dat prin coordonatele sale reale. Se va afişa un număr între **1** şi **4** sau mesajul **punct pe axe**.
 +
 +**Date de Intrare**
 +----
 +O singură linie pe care se află două numere reale, **X** şi **Y**, reprezentând coordonatele punctului pe axa **Ox**, respectiv **Oy**.
 +
 +**Date de Ieşire**
 +----
 +O singură linie care va conţine numărul cadranului în care se află punctul, sau mesajul "punct pe axe".
 +
 +**Restricţii şi Precizări**
 +----
 +  * -1000 ≤ X, Y ≤ +1000
 +
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| -23.15 1.2    | 2 |
 +| 19.2 1    | 1 |
 +| 0 0    | punct pe axe | 
 +
 +=== Problema 5 ===
 +
 +Scrieţi un program care să verifice dacă 3 numere întregi date **a, b, c** pot forma lungimile laturilor unui triunghi.
 +
 +**Date de Intrare**
 +----
 +O singură linie care va conţine trei numere întregi: **a, b şi c** separate prin spaţii.
 +
 +**Date de Ieşire**
 +----
 +O singură linie care va contine un mesaj din mulţimea { **DA**, **NU** }. Nu afişaţi spaţii sau alte caractere suplimentare.
 +
 +
 +**Restricţii şi Precizări**
 +----
 +  * -1.000.000.000 ≤ a, b, c ≤ +1.000.000.000
 +  * a + b + c ≠ 0
 +  * Se consideră triunghi şi un triunghi cu un unghi de 180 de grade şi două unghiuri de 0 grade.
 +
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 5 4 3    | DA |
 +| -1 2 0     | NU |
 +| 6 6 0     | DA | 
 +
 +=== Problema 6 ===
 +
 +Scrieţi un program care citeşte 3 numere reale reprezentând lungimile laturilor unui triunghi şi care afişează tipul de triunghi cu aceste laturi: //oarecare, isoscel, echilateral,​ dreptunghic sau dreptunghic isoscel//.
 +
 +**Date de Intrare**
 +----
 +Trei numere reale: **a, b şi c.**
 +
 +
 +**Date de Ieşire**
 +----
 +O singură **linie** care va contine un mesaj din mulţimea { **oarecare, echilateral,​ dreptunghic,​ isoscel, dreptunghic isoscel** }, în funcţie de tipul de triunghi.
 +Nu afişaţi spaţii sau alte caractere suplimentare.
 +
 +**Restricţii şi Precizări**
 +----
 +  * Cele trei numere pot forma întotdeauna laturile unui triunghi.
 +  * Două numere reale se vor considera egale dacă diferenţa lor în modul este mai mică decât 0.001.
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 10 10 10  | echilateral|
 +| 4 5 3     | dreptunghic|
 +| 5 10 10   | isoscel | 
 +| 2.8284 2 2| dreptunghic isoscel| ​
 +
 +=== Problema 7 ===
 +
 +Scrieţi un program care determină minimul şi maximul dintre 4 numere, folosind doar instructiunea **if**.
 +
 +**Date de Intrare**
 +----
 +O singură linie care va conţine patru numere întregi, **A, B, C şi D** separate prin spaţii.
 +
 +**Date de Ieşire**
 +----
 +O singură **linie** care va conţine două numere întregi, separate printr-un singur spaţiu, reprezentând în ordine minimul şi maximul dintre cele patru numere.
 +
 +
 +**Restricţii şi Precizări**
 +----
 +  * 1 ≤ A, B, C, D ≤ 2.000.000.000
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 23 5321 331245 2000000000 ​  | 23 2000000000|
 +
 +=== Problema 8 ===
 +
 +Afişaţi trei numere în ordine crescătoare,​ folosind doar instrucţiunea **if**.
 +
 +**Date de Intrare**
 +----
 +O singură linie care va conţine trei numere întregi, **A, B, şi C** separate prin spaţii.
 +
 +**Date de Ieşire**
 +----
 +O singură **linie** care va conţine numerele în ordine crescătoare,​ separate printr-un singur spaţiu.
 +
 +**Restricţii şi Precizări**
 +----
 +  * 1 ≤ A, B, C ≤ 2.000.000.000
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 123109 2342 12   | 12 2342 123109 |
 +
 +=== Problema 9 ===
 +
 +Scrieţi un program care citeşte trei numere întregi, **H, M şi S** reprezentând ora, minutul şi secunda dintr-un anumit moment al zilei, şi le afişează în format de ceas digital.
 +
 +**Date de Intrare**
 +----
 +O singură linie pe care se află trei numere întregi **H, M şi S**.
 +
 +**Date de Ieşire**
 +----
 +O singură linie care va conţine momentul zilei exprimat în format de ceas digital **HH:​MM:​SS**.
 +
 +**Restricţii şi Precizări**
 +----
 +  * 0 ≤ H ≤ 23
 +  * 0 ≤ M, S ≤ 59
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 15 42 3   | 15:42:03 |
 +
 +=== Problema 10 ===
 +
 +În programul anterior observaţi că dacă în loc de a introduce o valoare numerică tastaţi altceva (o literă, de exemplu) programul se va comporta anormal. Încercati să modificaţi programul astfel încat să aveţi protecţie la datele eronate.
 +<note tip>//​**Scanf** returnează numărul de argumente citite, care se potrivesc cu formatul căutat. Astfel, scanf("​%d",&​a) va returna 1 dacă a citit un întreg sau 0 altfel.//</​note>​
 +
 +**Date de Intrare**
 +----
 +O singură linie pe care se află trei numere întregi **H, M şi S** sau alte caractere eronate.
 +
 +**Date de Ieşire**
 +----
 +O singură linie care va conţine momentul zilei exprimat în format de ceas digital **HH:​MM:​SS** sau mesajul Date incorect introduse!
 +
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 1a 42 3   | Date incorect introduse! |
 +| 11 4.2 3   | Date incorect introduse! |
 +
 +=== Problema 11 ===
 +
 +Scrieţi un program pentru rezolvarea ecuaţiei de gradul 2.
 +
 +**Date de Intrare**
 +----
 +Trei numere reale a, b, c ce reprezintă coeficienţii ecuaţiei de gradul 2 în ordine descrescătoare după puterile lui x.
 +
 +
 +**Date de Ieşire**
 +----
 +Soluţiile reale ale ecuaţiei în ordine crescătoare,​ cu 2 zecimale.
 +În caz că ecuaţia nu are soluţie se va afişa mesajul "Nu exista solutii"​.
 +În caz că ecuaţia are o infinitate de soluţii se va afişa mesajul "​Infinit"​.
 +
 +
 +**Exemplu**
 +----
 +^ Intrare ​     ^ Ieşire ​      ^
 +| 1 -2 1   | 1.00 |
 +| 1 1 1   | Nu exista solutii |
 +| 1 -3 2   | 1.00 2.00 |
programare-cc/laboratoare/02.1602535203.txt.gz · Last modified: 2020/10/12 23:40 by viorel.mocanu
CC Attribution-Share Alike 3.0 Unported
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0