Lectia 2 - Intrări/ieșiri, instrucțiuni și funcții
Rezumat curs 2
În acest curs se vor discuta despre funcțiile de citire și scriere (cu accent pe funcțiile printf, scanf
din stdio.h,, apoi despre instrucțiunile limbajului C, iar în final despre declararea și definirea
funcțiilor în C, cu accent pe transmiterea parametrilor.
În limbajul C avem strong>operații de citire și scriere de la tastatură (stdin) și la ecran (stdout), prin fișiere sau
prin intermediul funcțiilor de bibliotecă
Pentru citirea de la tastatură și scrierea la ecran avem următoarele funcții/macrodefiniții:
fără formatare: getchar, putchar, getch, getche, putch, gets, puts
cu formatare: scanf, printf
incluse în bibliotecile stdio.h (getchar, putchar, gets, puts, scanf, prinh)
sau conio.h (getch, getche, putch)
Versiuni mai vechi de Code::Blocks nu includ biblioteca conio.h, dar se poate folosi biblioteca conio2.hdetalii biblioteca conio2.h
Pentru a verificarea tastelor apăsate, pentru afișare de texte cu culori și oriunde pe ecran, puteți folosi în
Code::Blocks biblioteca conio2.h, care este o extensie a bibliotecii conio.h, dezvoltată în urmă cu câțiva ani
de firma Borland, în produsul său Borland C++. La laborator pot fi date probleme care să utilizeze această bibliotecă.
Pentru a folosi această bibliotecă, descărcați de aici fișierele necesare:
https://github.com/Fernando-Lafeta/Biblioteca-Conio-2
și instalați-o astfel:
obțineți fișierele conio2.h și libconio.a
copiați fișierul conio2.h în folderul „include” al compilatorului vostru MinGW, din CodeBlocks
copiați fișierul libconio.a în folderul „lib” al compilatorului vostru MinGW, din CodeBlocks
navigați în Code Blocks la Settings -> Compiler and debugger, apoi la „Linker settings”;
la 'Link libraries' apăsați pe 'Add' și căutați calea către „libconio.a”, apoi apăsați pe 'OK'.
Iată un program demonstrativ pentru utilizarea lui conio2.h:
#include <stdio.h>
#include <conio2.h>
#define getch _getch
#define kbhit _kbhit
#define cprintf _cprintf
using namespace std;
void printAt(unsigned int x, unsigned int y, char textDeAfisat[100], unsigned int culoareText, unsigned int culoareFundal)
{
textcolor(culoareText); textbackground(culoareFundal); gotoxy(x,y);
cprintf(textDeAfisat); gotoxy(1,1);
}
int main()
{
char tasta; unsigned int x; unsigned int y;
x=30; y=20;
printAt(x,y,"O",LIGHTRED, YELLOW);
do {
if (kbhit()) {
printAt(x,y," ",BLACK, BLACK);
tasta=getch();
switch (tasta) {
case 72: // sus
y--; break;
case 80: // jos
y++; break;
case 75: // stanga
x--; break;
case 77: // dreapta
x++; break;
}
printAt(x,y,"O",LIGHTRED, YELLOW);
}
} while (tasta!=27); // escape
textbackground(0); textcolor(7);
return 0;
}
2.1.1. Funcția printf()
Cu ajutorul acestei funcții putem afișa mesaje pe ecran. Când programul folosește printf, datele pe care dorim să le afișăm
reprezintă parametrii sau argumentele funcției printf. Exemplu: printf("Hello!");
Funcția acceptă mai mulți parametri. Primul parametru trebuie întotdeauna să fie un șir de caractere, parametrii care urmează primului șir de
caractere pot fi numere, variabile, expresii (cum ar fi 10*7) sau chiar alte șiruri de caractere.
Atunci când dorim ca să afișăm o valoare sau o variabila, trebuie să includem informația despre tipul variabilei în primul parametru.
Pe lângă caractere, în primul parametru putem să includem specificatori de format, care spun funcției cum să-i afișeze pe ceilalți parametri.
De exemplu, pentru a afisa o valoare de tip int, veti folosi %d.
De asemenea, pentru a tipări o valoare în virgulă mobila (float), se poate folosi %f.
Următoarele intrucțiuni ilustrează utilizarea specificatorilor de format în cadrul funcției printf():
int varsta=18, greutate=54, pret=12;
float inaltime=1.69;
printf("Varsta este: %d\n", varsta);
//Va afisa pe ecran - Varsta este: 18
printf("Impozitul pe vanzari este: %f\n",pret*0.07);
//Va afisa pe ecran - Impozitul pe vanzari este: 0.84
printf("Varsta: %d, greutatea: %d, inaltimea: %f\n",
varsta,greutate,inaltime);
Următorul program folosește specificatorul de format %d pentru a afișa valori și variabile de tip int:
#include <stdio.h>
using namespace std;
int main()
{
int varsta = 41;
int greutate = 75;
int inaltime = 180;
printf("Varsta utilizatorului: %d greutate: %d inaltime: %d\n",varsta,greutate,inaltime);
printf("%d plus %d egal %d\n",1,2,1+2);
}
rezultat
Exemple de utilizareclick aiciTipărirea unei valori întregi octale sau hexazecimale
Funcția printf permite utilizarea unor specificatori de format care furnizează informatii despre tipurile parametrilor
(cum ar fi int, float, char etc.).
Dacă ne dorim să afișăm o valoare întreagă octala (în baza 8) sau hexazecimală (în baza 16), vom folosi specificatorul %o, respectiv %x (pentru minuscule) și
%X (majuscule).
#include <stdio.h>
int main()
{
int valoare = 255;
printf("Valoarea zecimala %d este %o in octal\n",
valoare, valoare);
printf("Valoarea zecimala %d este %x in hexazecimal\n",
valoare, valoare);
printf("Valoarea zecimala %d este %X in hexazecimal\n",
valoare, valoare);
}
rezultat
Valoarea zecimala 255 este 377 in octal
Valoarea zecimala 255 este ff in hexazecimal
Valoarea zecimala 255 este FF in hexazecimal
Afișarea valorilor de tip unsigned intprintf permite utilizarea unor specificatori de format care furnizează informații despre tipurile parametrilor.
Pentru a afișa variabile de tip unsigned int trebuie să folosiți specificatorul de format %u.
Daca se folosește %d în loc de %u, atunci funcția printf va trata valoarea respectivă ca
fiind de tip int și probabil va afișa rezultatul greșit.
#include <stdio.h>
int main()
{
unsigned int valoare = 4200000000;
printf("Afiseaza 4200000000 ca unsigned %u\n", valoare);
printf("Afiseaza 4200000000 ca int %d\n", valoare);
}
rezultat posibil
Afiseaza 4200000000 ca unsigned 4200000000
Afiseaza 4200000000 ca int -94967296
Afișarea valorilor de tip long int
Pentru a afișa valorile de tip long int cu funcția printf, trebuie să folosiți specificatorul de format
%ld. Dacă folosiți %d în loc de %ld, atunci funcția printf va trata valoarea respectivă
ca fiind te tip int și probabil va afisa rezutatul greșit.
#include <stdio.h>
int main()
{
long int un_milion = 1000000;
printf("Un milion este %ld \n", un_milion);
printf("Un milion = %d\n", un_milion);
}
rezultat
Un milion este 1000000
Un milion = 16960
Afișarea valorilor de tip float folosind functia printf
Pentru afișarea valorilor de tip float, în virgulă mobilă, trebuie folosit specificatorul de format %f.
#include <stdio.h>
int main()
{
float pret = 525.75;
float rata_impozit = 0.06;
printf("Pretul este %f\n", pret);
printf("Impozitul pe vanzari este %f\n", pret*rata_impozit);
}
rezultat
Pretul este 525.750000
Impozitul pe vanzari este 31.544999
Afișarea valorilor de tip char folosind funcția printf
Pentru a afișa valorile de tip char trebuie utilizat specificatorul de format %c.
#include <stdio.h>
int main()
{
printf("Litera este %c\n", 'A');
printf("Litera este %c\n", 65);
}
rezultat
Litera este A
Litera este A
Afișarea valorilor în virgulă mobilă în format exponențial
În funcție de cerințele programului este posibil să afișați valori în formatul exponențial.
Pentru a afișa valori în virgulă mobilă într-un format exponențial, folosiți specificatorul de format %e sau %E.
#include <stdio.h>
int main()
{
float pi = 3.14159;
float raza = 2.0031;
printf("Aria cercului este %e\n", 2*pi*raza);
printf("Aria cercului este %E\n", 2*pi*raza);
}
rezultat
Aria cercului este 1.258584e+01 Aria cercului este 1.258584E+01
Afișarea valorilor în virgulă mobilă
Cu specificatorul %f putem indica lui printf să afișeze valori în virgulă mobilă în format zecimal.
De asemenea, putem folosi specificatorii %e, %E pentru a afișa valori în virgulă mobilă in format exponențial.
În mod similar, funcția printf() acceptă specificatorii de format %g, %G.
Atunci când folosim acești specificatori, printf alege formatul %f sau %e, astfel încât
să ofere utilizatorului o afișare cât mai convenabilă. Următorul program ilustrează utilizarea specificatorului de format %g:
#include <stdio.h>
int main()
{
printf("Numarul 0.1234 este afisat in formatul %g\n", 0.1234);
printf("Numarul 0.00001234 este afisat in formatul %g\n", 0.00001234);
}
rezultat
Numarul 0.1234 este afisat in formatul 0.1234 Numarul 0.00001234 este afisat in formatul 1.234e-05
Afișarea unui șir de caractere folosind funcția printf
Un sir de caractere este o secventa care contine zero sau mai multe caractere. Una dintre cele mai obisnuite operatii executate in programe este afisarea sirurilor de caractere. Asa cum ati invatat pe parcursul acestui articol, functia printf permite utilizarea unor specificatori de format care furnizeaza informatii despre tipurile parametrilor (cum ar fi int, float, char etc). Pt a afisa un sir de caractere cu functia printf trebuie sa folositi specificatorul de format %s. Urmatorul program utilizeaza acest specificator pt a afisa un sir de caractere:
#include <stdio.h>
int main()
{
char titlu[255] = "Functiile printf() si scanf()";
printf("Numele acestui articol este: %s\n", titlu);
}
rezultat
Numele acestui articol este: Functiile printf() si scanf()
Utilizarea semnului plus sau minus inaintea unei valori
Atunci cand folositi functia printf pentru a afisa o valoare negativa, valoarea va fi intotdeauna precedata de semnul minus. In functie de programul dumneavoastra, v-ati dori uneori ca printf sa afiseze si semnul pentru valorile pozitive. Pentru a indica functiei printf sa afiseze semnul valorii, pur si simplu veti include un semn plus imediat dupa % in specificatorul de format. Urmatorul program, ilustreaza utilizarea semnului plus pentru specificatorii de format:
#include <stdio.h>
int main()
{
int neg_int = -5;
int poz_int = 5;
float neg_float = -100.23;
float poz_float = 100.23;
printf("Valoarea intreaga este %+d si %+d\n", neg_int, poz_int);
printf("Valoarea in virgula mobila este %+f si %+f\n", neg_float, poz_float);
}
rezultat
Valoarea intreaga este -5 si +5
Valoarea in virgula mobila este -100.230003 si +100.230003
Formatarea unei valori intregi folosind functia printf
Daca folositi specificatorul de format %d, puteti sa indicati functiei printf sa afiseze un numar minim de caractere. Urmatorul program ilustreaza modul in care puteti formata valorile intregi folosind specificatorul %d:
#include <stdio.h>
int main()
{
int valoare1=332, valoare2=12000, valoare3 = 3311;
printf("%7d\n", valoare1);
printf("%7d\n", valoare2);
printf("%7d\n", valoare3);
}
rezultat
332
12000
3311
Cifra pe care o plasati dupa % precizeaza numarul minim de caractere pe care printf il foloseste pentru a afisa o valoare intreaga. Daca, de exemplu specificati %5d si valoarea pe care vreti sa o afisati este 10, printf va introduce trei spatii libere inainte de valoare. Retineti ca valoarea precizeaza numarul minim de caractere pe care il va avea iesirea. Daca valoarea pe care doriti sa o afisati are mai multe caractere decat ati precizat, printf va folosi numarul de caractere necesar pentru afisarea corecta a valorii.
Afisarea numerelor intregi precedate de zero
În funcție de scopul programului, poate dorm ca să afișăm zerouri înaintea valorii, în loc de spații.
Pentru a indica funcției printf să adauge zerouri înaintea valorii, se plasează un 0 (zero nu litera "O")
imediat dupa % în specificatorul de format, înainte de numărul de cifre dorit.
Următorul program ilustrează acest procedeu:
#include <stdio.h>
int main()
{
int valoare = 5;
printf("%01d\n", valoare);
printf("%02d\n", valoare);
printf("%03d\n", valoare);
printf("%04d\n", valoare);
}
rezultat
5
05
005
0005
Afișarea unui prefix înaintea valorilor octale și hexazecimale
Pentru a indica funcției să adauge prefixul potrivit unei valori octale sau hexazecimale, se plasează caracterul #
imediat dupa % în specificatorul de format.
#include <stdio.h>
int main()
{
int valoare = 255;
printf("Valoarea zecimala %d este %#o in octal\n", valoare, valoare);
printf("Valoarea zecimala %d este %#x in hexazecimal\n",valoare, valoare);
printf("Valoarea zecimala %d este %#X in hexazecimal\n", valoare, valoare);
}
rezultat
Valoarea zecimala 255 este 0377 in octal
Valoarea zecimala 255 este 0xff in hexazecimal
Valoarea zecimala 255 este 0xFF in hexazecimal
Formatarea valorilor cu virgulă mobilă
Atunci când formatăm o valoare cu virgulă mobilă, trebuie să specificăm două valori.
Prima precizează numărul de caractere pe care vrem să-l afișăm, iar a doua valoare reprezintă numărul de cifre
pe care dorim să le afișăm la dreapta punctului zecimal.
#include <stdio.h>
int main()
{
float valoare = 1.23456;
printf("%8.1f\n", valoare);
printf("%8.3f\n", valoare);
printf("%8.5f\n", valoare);
}
În mod similar putem cere funcției să formateze o valoare în virgulă mobilă, în format exponențial.
Alinierea la stânga a ieșirii
Atunci când se afișează un text, utilizând formatarea cu printf, alinierea prestabilită este la dreapta.
Dacă dorim ca să facem alinierea textului la stânga, trebuie să plasăm un semn minus (-) imediat dupa %
în specificatorul de format.
#include <stdio.h>
int main()
{
int val_int = 5; float val_flt = 3.33;
printf ("Aliniere dreapta %5d a valorii \n", val_int);
printf("Aliniere stanga %-5d a valorii\n", val_int);
printf("Aliniere dreapta %7.2f a valorii\n", val_flt);
printf("Aliniere stanga %-7.2f a valorii\n", val_flt);
}
rezultat
Aliniere dreapta 5 a valorii
Aliniere stanga 5 a valorii
Aliniere dreapta 3.33 a valorii
Aliniere stanga 3.33 a valorii
Utilizarea combinată a specificatorilor de format
Cu ajutorul funcției printf putem utiliza specificatori de format combinați, de exemplu afișarea la stânga
a unui număr întreg cu semn:
#include <stdio.h>
int main()
{
int val_int = 5;
printf("Afisarea la stanga cu semn %-+3d\n",val_int);
}
rezultat
Afisarea la stanga cu semn +5
2.1.2. Funcția scanf()
Funcția scanf este o funcție cu ajutorul căreia putem citi date de la tastatură.
Sintaxa funcției scanf este următoarea:
scanf("lista de formate",adresa_var1, adresa_var2, ...);
Această funcție realizează următoarele operații:
citește din fișierul standard de intrare stdio o secvență de câmpuri de intrare, caracter cu caracter,
pâna la terminarea introducerii câmpurilor și apăsarea tastei <enter>;
formatează fiecare câmp conform formatului specificat în lista de formate;
Din caracterele citite se calculează valori numerice sau literale, conform tipului fiecărei variabile,
dimensiunile de format specificate și a separatorilor de câmpuri predefiniți (spațiu, <tab> și <enter>)
sau impuși explicit
valorile astfel construite sunt stocate la adresele variabilelor specificate ca argumente.
Indiferent de formatul folosit, la întâlnirea unui spațiu în introducerea datelor, este terminată citirea variabilei.
Pentru funcția de citire scanf trebuie folosit operatorul de adresă &.
Pentru variabilele citite cu această funcție trebuie precizate adresele la care se stochează în memoria calculatorului
valorile variabilelor.
Functia va introduce valorile citite direct la acele adrese.
Singurul caz în care nu este obligatorie folosirea operatorului adresă pentru citirea valorii unei variabile cu funcția
scanf este citirea unui șir de caractere.
Observație: Citirea cu ajutorul funcției scanf() a șirurilor de caractere care conțin spații este imposibilă.
În cazul în care formatul specificat este necorespunzător, rezultatul obținut poate fi neprevăzut.
Valoare intoarsă de scanf în caz de succes, este numărul de variabile care au fost citit corect.
Dacă nu a fost citită nicio variabilă (de exemplu s-a introdus un șir în loc de un număr) funcția întoarce valoarea 0.
Dacă apare o eroare înaintea oricărei citiri și asignări, funcția returneaza EOF (constantă de sistem având valoarea întreagă -1).
Specificatorii de format ai funcției scanf
Specificatorii de format ai funcției scanf sunt prezenți în lista următoare:
%c – citește un caracter
%d – citește un întreg zecimal
%i – citește un întreg zecimal
%e – citește un număr float
%f – citește un număr float
%g – citește un număr float
%o – citește un număr octal fără semn
%s – citește un sir de caractere
%x – citește un nr hexazecimal fara semn
%p – citește un pointer
%n – argumentul asociat primeste o valoare intreaga egala cu numarul de caractere deja citite
%u – citeste un numar intreg fara semn
%[] – scanare pentru set de caractere
Observație: Multe compilatoare tratează specificatorul de format %i ca fiind identic cu %d.
Totusi nu este recomandat sa il folositi deoarece %i este un specificator mostenit si este posibil ca viitoarele
compilatoare sa nu il accepte.
În specificatorul de format pot să apară și modificatori de tip:
modificatorulh, care poate precede caracterele de conversie d,i,o,u,x,X, precizeaza că valoarea
convertită trebuie memorată ca un short int sau unsigned short int;
modificatorull, care poate precede caracterele de conversie d,i,o,u,x,X, caz în care valoarea trebuie
memorată ca un long int sau unsigned long int, sau poate precede caracterele e,E,f,g,G, caz în care
valoarea trebuie memorată ca un double;
modificatorul L, care poate precede numai caracterele e,E,f,g,G și precizează că valoarea convertită
trebuie memorată ca un long double.
Un număr între % și caracterul de format limitează caracterele citite: de exemplu, %4d reprezintă un întreg
din cel mult 4 caractere (spaţiile iniţiale nu contează).
Se folosesc pentru operații de citire și scriere a caracterelor.
int getchar(void) - citește un caracter de la tastatură. Așteaptă până este apasată o tastă și
returnează valoarea sa; tasta apăsată are imediat ecou pe ecran.
int putchar(int c) - scrie un caracter pe ecran în poziția curentă a cursorului
fișierul antet pentru aceste funcții este stdio.h.
2.1.4. Funcțiile gets și puts
Se folosesc pentru operații de citire și scriere a șirurilor de caractere.
char *gets(char *s) – citește caractere din stdin și le depune în zona de date de la adresa s,
până la apăsarea tastei <Enter>. În șir, tastei <Enter> îi va corespunde caracterul '\0'.
dacă operația de citire reușește, funcția întoarce adresa șirului, altfel valoarea NULL ( = 0 ).
int puts(const char *s) – scrie pe ecran șirul de la adresa s sau o constantă șir de caractere și apoi trece la linie nouă.
dacă operația de scriere reușește, funcția întoarce ultimul caracter, altfel valoarea EOF (-1).
fișierul antet pentru aceste funcții este stdio.h
Nu recomandăm folosirea funcției gets, deoarece:
char *gets(char *s) - primește ca intrare numai un buffer (s), nu știm dimensiunea lui
poate apărea problema de buffer overflow: citim în s mai mult decat dimensiunea lui,
deoarece gets nu ne împiedică, așa că va scrie datele în altă parte
În schimb, se poate folosi funcția fgets cu fișierul stdin ca fișier de intrare:
char *fgets(char *s, int size, FILE *stream): fgets(s, sizeof(s), stdin).
De altfel, în standardul C11 funcția gets este eliminată
2.1.5. Intrări / ieșiri folosind stream-uri (cu cin/cout) în C++
Stream-urile au in principal rolul de a abstractiza operațiile de intrare-ieșire. Ele oferă metode de scriere și citire a datelor
independente de dispozitivul I/O și chiar independente de platformă. Stream-urile ascund problemele specifice dispozitivului
cu care se lucrează, folosind biblioteca standard iostream. Această bibliotecă utilizează un sistem de zone tampon (buffere).
Operațiile de intrare și ieșire cu dispozitivele periferice sunt consumatoare de timp, de aceea aplicațiile sunt uneori nevoite să
aștepte terminarea acestor operații. Datele trimise unui stream nu sunt scrise imediat pe dispozitivul respectiv, ci sunt transferate
într-o zonă de memorie tampon, din care sunt descărcate către dispozitiv abia în momentul umplerii acestei zone.
În C++ stream-urile au fost implementate utilizand clase, dupa cum urmeaza:
clasa streambuf gestioneaza buffer-ele.
clasa ios este clasa de baza pentru clasele de stream-uri de intrare si de iesire. Clasa ios are ca variabila membru un obiect de tip streambuf.
clasele istream si ostream sunt derivate din ios.
clasa iostream este derivata din istream si ostream si ofera metode pentru lucrul cu terminalul.
clasa fstream ofera metode pentru operatii cu fisiere.
Cand un program C++ care include iostream.h este lansat in executie, sunt create si initializate automat patru obiecte:
cin gestionează citirile de la intrarea standard (tastatură);
cout gestionează scrierile către ieșirea standard (ecranul);
cerr gestionează ieșirea către dispozitivul standard de eroare (ecranul), neutilizând zone tampon;
clog gestionează ieșirea către dispozitivul standard de eroare (ecranul), utilizand buffere.
Dispozitivele standard de intrare, ieșire și eroare pot fi redirectate către alte dispozitive. Erorile sunt de obicei redirectate către
fișiere, iar intrarea și ieșirea pot fi trimise către fișiere utilizând comenzi ale sistemului de operare
(utilizarea ieșirii unui program ca intrare pentru altul).
Forma generală de utilizare a lui cin și cout este:
cin >> var; /* citeşte var de la cin */
Se pot prelua tipurile aritmetice, șiruri de caractere
cout << expr; /* scrie expr la cout */
Se pot transfera tipurile aritmetice, șiruri de caractere, pointeri de orice tip în afară de char.
Sunt posibile operaţii multiple, de tipul:
cin >> var1 >> var2 ... >> varN; și
cout << var1 << var2 ... << varN; Exemplu - citirea și afișarea unui intExemplu - citirea și afișarea unui charExemplu - afișarea codurilor ASCIIExplicații
Așa cum veți învăța la disciplina Programarea orientată pe obiecte, de fapt, cin și cout sunt niște obiecte
definite global, care au supraîncărcat operatorii >>, << de mai multe ori, pentru fiecare tip de
parametru în parte (int, char * etc.):
Aici am citit de la intrarea standard o valoare întreagă, ce s-a trimis apoi ieșirii standard. Simbolurile '\n', '\t', ș.a.m.d. se pot utiliza
ca la funcțiile printf, scanf etc. Utilizarea simbolului endl va forța golirea zonei tampon, adică trimiterea datelor
imediat către ieșire. Atât operatorul >>, cât și << returnează o referință către un obiect al clasei istream.
Deoarece cin, respectiv cout este și el un obiect istream, valoarea returnată de o operație de citire/scriere
din/în stream poate fi utilizată ca intrare/ieșire pentru următoarea operație de același fel.
Obiectul cin are o funcție membru get, ce poate fi utilizată pentru a obține un singur caracter din intrare,
apelând-o fără niciun parametru, caz în care returnează valoarea utilizată, sau ca referință la un caracter.
În forma get() fără parametri, funcția întoarce valoarea caracterului găsit. Spre deosebire de operatorul >>,
nu poate fi utilizată pentru a citi mai multe intrări, deoarece valoarea returnată este de tip întreg, nu un obiect istream.
Exemplu
Operatorul >> nu poate fi utilizat pentru a citi corect șiruri de caractere de la intrare (cu spații),
deoarece spațiile sunt interpretate ca separator între diverse valori de intrare. În astfel de cazuri trebuie folosită functia get().
În acest caz, funcția get se folosește astfel:
cin.get(char *PointerLaSirulDeCaractere, int LungimeMaxima, char Sfarsit);
Primul parametru este un pointer la zona de memorie în care va fi depus șirul de caractere. Al doilea parametru reprezintă numărul
maxim de caractere ce poate fi citit plus unu. Cel de-al treilea parametru este caracterul de încheiere a citirii, care este opțional
(implicit considerat ca fiind '\n'). În cazul în care caracterul de încheiere este întâlnit înainte de a fi citit
numărul maxim de caractere, acest caracter nu va fi extras din stream.
Există o functie similara funcției get(), cu aceeași sintaxă, numită getline().
Funcționarea sa este identică cu cea a funcției get(), cu excepția faptului că acel ultim caracter
menționat mai sus este și el extras din stream.
Alte funcții ale lui cin
Funcția cin.ignore() se utilizează pentru a trece peste un număr de caractere, până la întâlnirea unui anume caracter:
cin.ignore(int NumarMaximDeCaractereIgonorate, char Sfarsit);.
Funcția cin.peek() returnează următorul caracter din stream, fără însă a-l extrage.
Funcția cin.putback() inserează în stream un caracter.
Obiectul cout are o funcție cout.flush() ce determină trimiterea către ieșire a tuturor informațiilor
aflate în zona de memorie tampon. Această funcție poate fi apelată și sub forma cout << flush.
Funcția cout.put() scrie un caracter către ieșire: cout.put(char Caracter);.
Deoarece această funcție returnează o referință de tip ostream, pot fi utilizate apeluri succesive ale acesteia, de exemplu:
cout.put('H').put('i').put('!').put('\n');.
Funcția cout.write() are același rol ca și operatorul <<, cu excepția faptului că se poate specifica
numărul maxim de caractere ce se doresc scrise. Sintaxa funcției este: cout.write(char *SirDeCaractere, int CaractereDeScris);.
Funcția cout.width() permite modificarea dimensiunii valorii trimise spre ieșire (pentru următoarea operație), care implicit este considerată
exact mărimea câmpului în cauză: cout.width(int Dimensiune);.
Funcția cout.fill() permite modificarea caracterului utilizat pentru umplerea eventualului spațiu liber creat prin utilizarea
unei dimensiuni mai mari decât cea necesară ieșirii, cu funcția cout.width(): cout.fill(char Caracter);.
Opțiuni de formatare a ieșirii
Pentru formatarea ieșirii sunt definite două funcții membre ale cout, și anume:
Funcția cout.setf() activează o opțiune de formatare a ieșirii, primită ca parametru:
cout.setf(ios::Optiune);, unde Optiune poate fi:
showpos - determină adăugarea semnului plus (+) în fața valorilor numerice pozitive;
dec, oct, hex - schimbă baza de numerație pentru valori numerice;
showbase - determină adăugarea identificatorului bazei de numerație în fața valorilor numerice.
Funcția cout.setw() modifică dimensiunea ieșirii, fiind similară funcției cout.width():
cout.setw(int Dimensiune);
Exemplu
#include <iostream.h>
#include <iomanip.h>
void main()
{
int number = 783;
cout << "number = " << number;
cout.setf(ios::showbase);
cout << "number in hexa = " << hex << number;
cout.setf(ios::left);
cout << "number in octal, aligned to the left = " << oct << number;
}
2.2. Instrucțiuni
În limbajul C avem următoarele tipuri de instrucțiuni:
Expresii
Instrucțiuni compuse (bloc)
Instrucțiuni condiționale
Instrucțiuni iterative
Instrucțiuni pentru oprirea secvenței
Instrucţiunea de salt necondiționat
Detalii
2.2.1. Instrucțiunea expresie
Sintaxa
instr_expresie ::= { expresie }opt ;
Semantica
Se evaluează expresia.
Dacă este o expresie de forma unei instrucțiuni de atribuire, variabila=expresie, atunci variabila primește valoarea expresiei din dreapta, vechea valoare a expresiei pierzându-se.
Dacă este o expresie de forma variabila op = expresie, aceasta este echivalentă cu variabila=variabila op expresie, unde op este un operator din mulțimea {+, -, *, /, % }
Dacă este o expresie de forma variabila++ sau ++variabila, aceasta este echivalentă cu variabila=variabila+1.
Dacă este o expresie de forma variabila-- sau --variabila, aceasta este echivalentă cu variabila=variabila-1.
Exemple
a = b;
a + b + c;
;
cout << a;
sizeof(int);
2.2.2. Instrucţiunea compusă (bloc)
Sintaxa
Grupează instrucţiuni/declarații într-o unitate executabilă.
O instrucţiune compusă este ea însăşi o instrucţiune: oriunde poate să apară o instrucţiune, este corect să apară şi o instrucţiune compusă.
Se execută o singură dată fiecare dintre instrucțiuni/declarații, de sus în jos și de la stânga la dreapta.
Nu se revine în vreun fel la una dintre instrucțiunile/declarațiile anterioare.
Exemple
{
int a=3, b=10, c=7;
a += b += c;
cout << a << ", " << b << ", " << c; // ?, ?, ?
}
if (x > y){
int temp;
temp = x; x = y; y = temp;
cout << x << y;
}
{
int a, b, c;
{
b = 2; c = 3; a = b += c;
}
cout << "a= " << a <
2.2.3. Instrucţiunile condiţionale if şi if-else
Sintaxa
instr_if ::= if (<expresie_booleană>)
{<instructiunea1>;}
instr_if-else ::= if (<expresie_booleană>)
{<instructiunea1>;}
else
{<instructiunea2>;}
expresie_booleană este construită cu:
Expresii aritmetice
Comparatori: ==, !=, <, <=, >, >=
Conectori logici: &&, ||, !
Semantica
Se evaluează (o singură dată) expresie_booleană.
Dacă aceasta este adevărată, atunci se execută instrucțiunea1.
Dacă nu este adevărată, atunci, dacă este prezentă ramura cu else, se execută instrucțiunea2.
Exemple
if(lungime == latime)
ariaPatrat = lungime*lungime;
if (a % 2) if (b % 2) p = 1; else p = 2; // cu cine este grupat acest „else”?
if(a%2) { if(b%2) p = 1;} else p = 2;
if (primulNumar < alDoileaNumar)
minimul = primulNumar;
else
minimul = alDoileaNumar;
int primul, alDoilea, alTreilea, alPatrulea, maximul;
if(primul>alDoilea)
if(alTreilea>alPatrulea)
if(primul>alTreilea) maximul = primul;
else maximul = alTreilea;
else
if(primul>alPatrulea) maximul = primul;
else maximul = alPatrulea;
else
if(alTreilea>alPatrulea)
if(alDoilea>alTreilea) maximul = alDoilea;
else maximul = alTreilea;
else
if(alDoilea>alPatrulea) maximul = alDoilea;
else maximul = alPatrulea;
Problema "dangling else"
Regula este: else este ataşat celui mai apropiat if.
if (a == 1)
if (b == 2) // b=2
cout << "*****\n";
else
cout << "ooooo\n";
Nu lăsaţi forma codului să vă ducă în eroare!
Atenție la diferența dintre operatorii de egalitate și cel de asignare
if ( conditie-1 ) {
instructiuni-1;
}
else if ( conditie-2 ) {
instructiuni-2;
...
}
else if ( conditie-n ) {
instructiuni-n;
}
else {
instructiuni-pt-restul-posibilitatilor;
}
Exemplu cu un calculator simplu
int main(void){
float operand1, operand2, rezultat;
char op;
cout << "Expresia:(numar operator numar – FARA SPATII)\n";
cin >> operand1 >> operator >> operand2;
if(op == '+')
rezultat = operand1+operand2;
else if(op == '-')
rezultat = operand1-operand2;
else if(op == '*')
rezultat = operand1*operand2;
else if(op == '/')
rezultat = operand1/operand2;
else{
cout << "Eroare in scrierea expresiei!";
return 1;
}
cout << "Rezultatul este: " << rezultat << "\n";
return 0;
}
2.2.4. Instrucţiunea switch
Sintaxă
switch (expresia)
{
case constanta1:
grupul_de_instrucțiuni_1; [break;] (break este opțional)
case constanta2:
grupul_de_instrucțiuni_2; [break;]
...
[default:
grup_implicit_de_instrucțiuni] (default este opțional)
}
Valorile constantelor trebuie sa fie diferite; ordinea lor nu are importanţă.
Acoladele ce grupeaza mulţimea case>-urilor sunt obligatorii.
După fiecare case pot apare mai multe instrucţiuni fără a fi grupate în acolade.
Semantica:
Se evaluează expresia.
Dacă ea are valoarea constanta1, atunci se execută grupul_de_instrucțiuni_1,
eventual grupul_de_instrucțiuni_2 etc., până la întâlnirea primului break.
Dacă ea are valoarea constanta2, atunci se execută grupul_de_instrucțiuni_2 etc.,
până la întâlnirea primului break.
...
În cazul în care expresia nu este egală cu niciuna din variantele constanta1, constanta2 etc, iar
grupul_implicit_de_instrucțiuni este prezent, se execută acesta.
(acesta trebuie să apară o singură dată, nu neaparat la sfârşit)
Exemple:
1) Echivalență între switch și if:
cin >> i;
switch(i){
case 1: cout << " 1";
case 2: cout << " 2";
case 3: cout << " 3"; // break;// ???
case 4: cout << " 4";
default: cout << " blabla! ";
//3
2) Un alt exemplu
3
3 4 blabla !
3) Încă un exemplu
char eval;
cin >> eval;
switch (eval) {
case 'A':
case 'a':
cout << "Excellent: you got an \"A\"!\n";
break;
case 'B':
case 'b':
cout << "Good: you got a \"B\"!\n";
break;
}
b
Good: you got a "B"!
2.2.5. Instrucțiunea while
Sintaxa:Semantica:
Se evaluează expresia (condiția).
Dacă ea este nulă / nu este adevărată, se trece la instrucțiunea_următoare.
Dacă este adevărată, se execută instrucțiunea, apoi se reia ciclul, testându-se din nou valoarea de adevăr (!=0) a expresiei ș.a.m.d.
Așadar, cât timp expresia este adevărată, se execută instrucțiunea.
Exemplu:
int n, i=1, factorial=1;
cin>>n;
while (i++ < n)
factorial *= i;
cout<<factorial;
2.2.6. Instrucțiunea do-while
SintaxaSemantica:
Se execută instructiune.
Se evaluează conditie, apoi:
dacă valoarea sa este nenulă controlul este transferat înapoi, la începutul instrucţiunii do..while;
dacă valoarea este nulă se execută instructiunea_urmatoare.
Aşadar instructiune se execută o dată sau de mai multe ori.
Exemplu
unsigned long n;
do {
cout << "Enter number (0 to end): ";
cin >> n;
cout << "You entered: " << n << "\n";
} while (n != 0);
return 0;
Enter number (0 to end): 25
You entered: 25
Enter number (0 to end): 36
You entered: 36
Enter number (0 to end): 0
You entered: 0
Exemplu cu un calculator simplu
int main(void){
float operand1, operand2, rezultat;
char op, raspuns;
int ERROR;
cout << "Calculator pentru expresii de forma \n operand1 operator operand2\n";
cout << "Folositi operatorii + - * / \n";
do{
ERROR = 0;
cout << "Dati expresia: ";
cin >> operand1 >> operator >> operand2;
switch(op){
case '+': rezultat = operand1+operand2; break;
case '-': rezultat = operand1-operand2; break;
case '*': rezultat = operand1*operand2; break;
case '/': if(operand2 != 0) rezultat = operand1/operand2;
else {cout << "Impartire prin zero!\n"; ERROR = 1;}
break;
default : {cout << "Operator necunoscut!\n"; ERROR = 1;}
}
if(!ERROR)
cout << operand1 << " " << operator << " " << operand2 << " = " << rezultat;
cin.sync();
do{cout << "\n Continuati (d/n)?"; raspuns = getchar();
} while (raspuns != 'd' && raspuns != 'n');
} while (raspuns != 'n');
cout << "La revedere!\n";
return 0;
}
2.2.7. Instrucţiunea for
Sintaxa Una, două sau chiar toate cele trei expresii pot lipsi, dar cei doi separatori (;) sunt obligatorii.
Semantica
Dacă instructiune nu conţine continue şi expr-cond este prezentă, atunci for este echivalent cu:
Dacă există continue atunci această instrucțiune transferă controlul la expr-in/decrementare.
Se evaluează expr-init - în general aceasta se utilizează pentru iniţializarea iteraţiei.
Se evaluează expr-cond - în general aceasta este o expresie logică ce se utilizează pentru controlul iteraţiei.
Dacă valoarea sa este nenulă (true), se execută corpul buclei (instrucţiune),
se evalueaza expr-in/decrementare și controlul este trecut la începutul buclei, fără a se mai evalua expr-init.
În general expr-in/decrementare face trecerea la iteraţia următoare: modifică o variabilă ce intră în
componenţa lui expr-cond.
Procesul continuă până când valoarea expr-cond este nulă (false).
Controlul este transferat următoarei instrucţiuni (cea de după for).
Argumentele sunt expresii ce substituie parametrii la un apel: parametrii funcţiei sunt iniţializaţi cu valorile argumentelor.
Exemplul 1
Definim o funcție care să calculeze (returneze) pentru un număr natural n dat suma primelor n numere naturale.
Matematic, funcția este definită pe mulțimea numerelor întregi cu valori în mulțimea numerelor întregi.
suma: Z -> Z, suma(n)=1+2+3+...+n
Cea mai simplă și eficientă variantă:
int suma(int n)
{
return n*(n+1)/2
}
Varianta iterativă (repetitivă)
int suma(int n)
{
int s = 0;
int i;
for(i=1; i<=n; ++i)
s += i;
return s;
}
Varianta recursivă
int suma(int n)
{
if (n==0)
return 0;
else
return n+suma(n-1);
}
Exemplul 2 - Ce se întâmplă?
void swap(int x, int y){
int temp = x; x = y; y = temp;
cout << "x=" << x<< ",y=" << y<< "\n";
}
int main(void){
int a = 2, b = 3;
swap(a, b); // x = 3, y = 2
cout << "a=" << a<< ",b=" <<b <<"\n";
// a = 2, b = 3
}
Exemplul 3 - Ce se întâmplă?
void swap(int& x, int& y){
int temp = x; x = y; y = temp;
cout << "x=" << x<< ",y=" << y<< "\n";
}
int main(void){
int a = 2, b = 3;
swap(a, b); // x = 3, y = 2
cout << "a=" << a<< ",b=" <<b <<"\n";
// a = 3, b = 2
}
2.3.3. Transmiterea parametrilor
Variabile locale/globale/parametri
Parametri transmiși prin valoare
Parametri transmiși prin referință
Returnarea unei valori prin parametrul transmis prin referință - „proceduri”
Returnarea unei valori cu return „prin tipul funcției”
2.3.4. Parametri impliciți
#include<iostream>
using namespace std;
// O functie cu parametri impliciti, poate fi apelata cu
// 2 argumente, 3 argumente sau 4 argumente.
int sum(int x, int y, int z=0, int w=0)
{
return (x + y + z + w);
}
int main()
{
cout << sum(10, 15) << endl;
cout << sum(10, 15, 25) << endl;
cout << sum(10, 15, 25, 30) << endl;
return 0;
}
2.3.5. Funcții cu număr variabil de parametri
În C putem avea funcții cu număr variabil de parametrii. Astfel de funcții vor avea mereu ultimul argument 3 puncte (...),
iar argumentul din fața sa va fi un int, care reprezintă numărul de argumente variabile setate la apelul funcției.
Folosirea funcțiilor cu număr variabil de parametrii:
Pentru a folosi funcții cu număr variabil de parametrii, trebuie să includem fișierul header
stdarg.h, care definește anumite macro-uri și funcții necesare.
Pașii pentru a folosi o funcție cu număr variabil de parametrii:
definește o funcție care are penultimul argument un int (numărul de argumente primite la apel)
și ultimul parametru "3 puncte" (...);
creează o variabilă de tipul va_list;
folosește macro-ul va_start și parametrul de int pentru a inițializa va_list;
folosește macro-ul va_arg și variabila de tipul va_list pentru a accesa fiecare parametru din listă;
folosește macro-ul va_end ca să cureți memoria alocată variabilei de tipul va_list.
Exemplul 1 - sumă de numere
#include <stdio.h>
#include <stdarg.h>
int suma(int numar_parametri,...) {
va_list lista_parametri;
int suma_numere = 0;
int i;
va_start(lista_parametri, numar_parametri);
for (i = 0; i < numar_parametri; i++) {
suma_numere = suma_numere + va_arg(lista_parametri, int);
}
va_end(lista_parametri);
return suma_numere;
}
int main() {
printf("Suma numerelor 2, 3, 4, 5 = %d\n", suma(4, 2,3,4,5));
printf("Suma numerelor 5, 10, 15 = %d\n", suma(3, 5,10,15));
}
Exemplul 2 - concatenare de șiruri
Iată, în continuare, o funcție ce concatenează un număr arbitrar de șiruri de caractere.
char *sir = vstrcat("Ghici, cine ","vine ","la cina!",(char *)NULL);
Se observa cast-ul de la ultimul argument.
Declarația va_list argp; definește lista de argumente ce va fi utilizată de macrourile va_arg, va_end.
Înainte de a descărca argumentele din stivă este necesară inițializarea listei de argumente:
va_start(argp,fmt); inițializează lista de argumente argp la primul argument fixat din lista variabilă (fmt).
Rutina va_arg descarcă stiva de argumente.
Ea primește doi parametri: numele listei de argumente și tipul datei care se descarcă.
2.3.6. Parametrii de tip pointer
Prezintă același comportament ca și parametrii de tip referință (se pasează adresa si nu valoarea)
Exemplu de program cu parametrii trimiși prin valoare și parametrii trimiși prin referință: