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:
#include <stdio.h>
 
int main()
{
    printf("Programarea Calculatoarelor\n");
    return 0;
}
  • 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:

#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;
}

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:

int a;
float b;
unsigned int c;
scanf("%d%f%u", &a, &b, &c);

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.

O greşeală frecventă este să uitaţi să puneţi operatorul & înainte numelor variabilelor ce vor fi citite!

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!

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!

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 scanf(“Numarul N = %d”, &n);. Folosiţi în schimb:

printf("Numarul N = ");
scanf("%d", &n);

Scrierea datelor

Ca şi la citire, vom ilustra folosirea funcţiei printf printr-un exemplu:

printf("Ana are %d mere. Ele costa %.2f RON/kg.", n, price);

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:

printf("sin(1 rad) = %f", sin(1));
printf("Codul ASCII al literei 'A' este: %d", 'A');

Î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!

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:
     printf("%*d", 10, i); 

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

Scrieți un program care citește două numere naturale (de tip int) pe aceeași linie, separate prin câte un spațiu. Calculați suma și produsul pentru aceste numere și afișați rezultatele obținute.

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

  • 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

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.

#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; 
}

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.

Pentru a folosi funcţiile din math.h trebuie să adăugaţi opţiunea -lm la compilare.

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.

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.

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

Problema 10

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 :

// 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;

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)

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 ?

programare-cc/laboratoare/02.txt · Last modified: 2024/10/16 10:02 by mihai.nan
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