Partea 1

Plan

  • Alfabetul, vocabularul, sintaxa și semantica unui limbaj de programare
  • Forma unui program simplu în C++, directive de preprocesare
  • Tipuri fundamentale de date
  • Caractere, cuvinte rezervate
  • Variabile, expresii, asignări
  • Operatori
  • Expresii booleene
  • Constante
  • Tipul întreg
  • Tipul flotant
  • Conversii
  • Instrucțiuni
  • Intrări și ieșiri

Alfabetul și vocabularul unui limbaj de programare

Setul de caractere

Orice limbaj de programare are la bază un anumit alfabet. În majoritatea cazurilor setul de caractere este format din:

  • literele alfabetului englez (de la A la Z, de obicei și majusculele, și literele mici, în total 52 de caractere);
  • cifrele arabe (de la 0 la 9, în total 10 caractere);
  • unele caractere speciale (. , ; = < > # $ % + – * / ” ‘ ( )  etc.) , a căror  semnificație poate sa difere de la un limbaj la altul.

Secvențe Escape / Caractere speciale în C++

\b Backspace, \t Tab orizontal, \v Tab vertical, \n Linie nouă, \f Pagina nouă – formfeed
 \r Început de rând, \” Ghilimele, \’ Apostrof, \\ Backslash, \? Semnul întrebării, \a Alarmă

Standarde de codificare a seturilor de caractere

  • EBCDIC (Extended Binary Coded Decimal Interchenge Code), un cod pe 8 biți, introdus de IBM;
  • ASCII (American Standard Code for Information Interchange), introdus de ANSI (American National Standard Institute), este un cod pe 7 biți și permite codificarea a 128 de caractere (95 de caractere afișabile și 33 de caractere neafișabile, numite caractere de control). Ulterior, setul ASCII a fost extins la o codificare pe 8 biți, fiind disponibile astfel 256 de caractere.

Primele 128 sunt din setul ASCII standard, iar următoarele 128 sunt coduri de caractere afișabile pentru caracterele unor alfabete naționale europene (francez, spaniol, român etc.), o parte din literele alfabetului grecesc, unele simboluri matematice, caractere speciale pentru desenat tabele etc.

Ordonarea caracterelor alfabetului se face pe baza codurilor numerice corespunzătoare caracterelor respective.

Cuvinte cheie / cuvinte rezervate

Pe baza caracterelor ce alcătuiesc alfabetul limbajului se alcătuiesc cuvintele care formează vocabularul sau lexicul limbajului și cu ajutorul cărora se construiesc expresiile și instrucțiunile limbajului. Există doua categorii de cuvinte și anume:

  1. cuvinte cheie – acestea au un înțeles explicit într-un context precizat (de ex., în unele limbaje de programare cuvintele ce desemnează instrucțiuni pot fi folosite și ca nume de variabile, neexistând restricții; asemenea situații nu sunt însă indicate deoarece pot ascunde erori în logica programului și îl fac mai greu de înțeles);
  2. cuvinte rezervate – acestea nu pot fi folosite decât în scopul pentru care au fost definite (de ex., în limbajul C++). Avantajele utilizării acestei categorii de cuvinte sunt următoarele:
  • programul devine mai ușor de înțeles;
  • se mărește viteza de compilare (analiza lexicală, sintactică și semantică este mai simplă la căutarea în tabele de simboluri);
  • erorile sunt mai ușor de depistat.
  • Pe de alta parte, în cadrul unui limbaj de programare se vor utiliza cuvinte ale limbajului (rezervate) si cuvinte definite de utilizator pentru a referi diverse elemente (variabile, fisiere, nume de proceduri, nume de functii, etc.).

Sintaxa unui limbaj de programare

Și în cazul limbajelor de programare succesiunile de cuvinte construite după anumite reguli, formează propoziții, numite instrucțiuni. Sintaxa unui limbaj de programare reprezinta ansamblul de reguli prin care se determină dacă o anumită instrucțiune este alcătuită corect sau nu. Sintaxa unui limbaj de programare poate fi descrisă în diverse moduri, unul dintre acestea fiind notația BNF (Backus-Naur Form).

Notatia BNF

Notatia BNF (Backus-Naur Form) a fost utilizata prima data la descrierea sintaxei limbajului ALGOL (în cadrul raportului ALGOL60 aparut în 1963) si este numita dupa doi dintre autorii acestui raport. În cadrul BNF sunt folosite metasimboluri, simboluri terminale si simboluri neterminale.

Metasimboluri sunt simbolurile <, >, ½ si ::= si ele fac parte din mecanismul de descriere a limbajului. Simbolul ½  semnifica o alternativa, simbolul  ::= inseamna „se definește astfel”.

Simbolurile terminale sunt cuvinte care apar acolo unde se specifica în productii (de ex., for, while, do, +, ; etc.).

Simbolurile neterminale sunt încadrate în < si > si sunt definite prin productii ale limbajului (de ex., <variabila>, <identificator>, <instructiune if> etc.).

Exemplu: în limbajul C++ sintaxa unui identificator se descrie în BNF astfel:

<identificator>::=<litera>|<identificator><cifra>|<identificator><literă>|

unde

<litera>::=a|b|...|z|A|B|...|Z|_

<cifra>::=0|1|2|...|9
Simbolul _ este considerat <litera> în acest context.

Conform acestei reguli, identificatorul are 3 definiții alternative: un identificator este fie o <litera>, fie un <identificator> urmat de o <cifra> sau o <litera> (definitie recursiva). Semnificatia acestei definitii este urmatoarea: un identificator poate sa contina o singura litera, sau o litera urmata de oricâte litere si/sau cifre. Conform acestei definitii, sunt corecte sintactic urmatorii identificatori: a, t1, sec12a1.

Descrierea sintaxei instructiunii conditionale if-else din limbajul C++ în notatie BNF este:

<instructiune if>::= if (<conditie>)
                        <instructiune1>
                     else
                        <instructiune2>

Semantica unui limbaj de programare

Semantica unei instrucțiuni reprezintă înțelesul pe care îl are acea instrucțiune, adică ce va executa calculatorul când o întâlnește.

Astfel, pentru instrucțiunea if-else de mai sus, se evalua condiția <conditie>, iar dacă aceasta este adevărată (în momentul evaluării), atunci se va executa o singură dată instrucțiunea <instructiune1>, respectiv, dacă este falsă, se va executa o singură dată instrucțiunea <instructiune2>.

Primul program în C++, folosind Code::Blocks

Instalare Code::Blocks și scrierea primului program

Exemplu de program simplu în C++

/*
 * primul program in C++
 */
#include <iostream>
int main ()
{
  std::cout << "Primul test 1, 2, 3. ";
  std::cout << "functioneaza.. \n";
  return 0;
}

SAU

/*
* primul program in C++
*/
#include <iostream>
using namespace std;
int main ()
{
  cout << "Primul test 1, 2, 3. ";
  cout << "functioneaza.. \n";
  char c;
  cout << "Pentru a iesi, apasati orice tasta!!\n";
  cin >> c;
  return 0;
}

Rezultatul va fi:

Primul test 1, 2, 3. functioneaza..

Forma unui program simplu în C++

/*comentariu; el nu influențează programul */
//directive preprocesare
#include <biblioteci> (Input/output, math, strings, …)
#define 
//declarații ale variabilelor
tipuri utilizator;
Variabile;
Funcții;
....
// definirea funcțiilor utilizator ..........

//funcția  principală
int main()
{
..........
return 0;
}  //aici se încheie programul

Directive preprocesare

Directiva preprocesare #include

Sintaxa:

#include <biblioteci> (Input/output, math, strings, …)

Exemple:

#include <iostream>
#include <math.h>
#include <stdlib.h>
#include “biblioteca_mea.h”
#include “t1.h”

Directiva preprocesare #define

Sintaxa:

#define simbol

#define simbol valoare

Exemple:

#define infinit 1000
#define pi 3.1415926
#define then
#define si &&
#define daca if
#define altfel else
#define max(x,y) x > y ? x : y #define min(x,y) x < y ? x : y
#include <stdio.h>
void main()
{
   float a,b,c;
   printf("Dati lungimile laturilor:\n");
   scanf("%f %f %f",&a,&b,&c);
   daca ((a>=0) si (b>=0) si (c>=0) si  (a<b+c) si (b<a+c) si (c<a+b))
        printf("%4.2f, %4.2f  si %4.2f formeaza triunghi.", a,b,c);
   altfel
        printf("Nu formeaza triunghi.");
}

Date

Variabile și constante. Expresii

În cadrul programului, datele pot fi declarate ca fiind constante sau variabile.

O constantă este o dată a cărei valoare nu se poate modifica pe parcursul execuţiei programului, deci rămâne constantă.

O variabilă este o dată a cărei valoare se poate modifica pe parcursul execuţiei programului, deci ea poate varia, dar acest lucru nu este obligatoriu. Astfel, se poate declara o dată ca fiind variabilă în cadrul unui program, apoi ea să primească o anumită valoare, iar această valoare să rămână asociată respectivei variabile până la terminarea programului.

Evident, atunci când se va declara o dată constantă, se va preciza şi valoarea ei, iar când se va declara o dată variabilă, se subînţelege că ulterior, pentru a putea fi folosită, această variabilă va primi o anumită valoare.

Majoritatea limbajelor de programare asignează o valoare iniţială variabilelor, o dată cu declararea lor. Astfel, şirurile de caractere sunt iniţializate la şirul vid, iar numerele sunt considerate cu valoarea zero.

Fireşte, atât constantele cât şi variabilele au o anumită structură, mai simplă sau mai complicată, şi o anumită natură, dată de mulţimea valorilor posibile pentru o dată. Cu ele se pot face anumite operaţii, în funcţie de natura şi structura lor. Astfel, vom spune că o dată are un anumit tip.

Există anumite convenții lexicale pentru scrierea constantelor și variabilelor:

      • ALL_CAPS pentru constante
      • lowerToUpper pentru variabile, cu nume cât mai sugestive

Expresii

Majoritatea limbajelor de programare definesc expresiile după un sistem de reguli sintactice, care, în general sunt următoarele:

  1. orice constantă este expresie;
  2. orice variabilă este expresie;
  3. dacă E este expresie, atunci şi (E), -E, +E, F(E) sunt expresii, unde F este numele unei funcţii aplicabile expresiei E;
  4. dacă E1 şi E2 sunt expresii, atunci şi E1+E2, E1-E2, E1*E2, E1/E2 sunt expresii.

Acum, pe baza regulilor de mai sus putem construi expresii foarte complexe, pornind de la constante şi variabile. Astfel, să considerăm entitatea (3+A)*(5/(-B+C)) şi să verificăm dacă ea este expresie sau nu. Să presupunem că A, B şi C sunt variabile numerice întregi. Cum 3 este constantă, conform regulii 1, ea este şi expresie. A, fiind variabilă este, conform regulii 2 expresie. Acum, conform regulii 4, 3+A este expresie, iar (3+A) este tot expresie, conform regulii 3. După simbolul înmulţirii (reprezentat adesea prin *), avem: 5 este expresie, fiind constantă, B, C, apoi -B şi -B+C sunt expresii. În fine, conform regulii 3, (-B+C) este tot expresie, apoi şi (5/(-B+C)) este expresie, în conformitate cu regula 4, şi, tot după această regulă, şi (3+A)*(5/(-B+C)) este expresie.

Datele sunt caracterizate de

  • Tip
  • Nume
  • Valoare
  • Domeniu de vizibilitate
  • Timp de viaţă
  • Operatori
  • Apeluri de funcții

Variabile în C++

Declararea variabilelor

    tip variabila;

    tip var1, var2,, varn;

    tip variabila = expresie_constanta;

Variabile globale și variabile locale

Variabile globale: declararea lor se face la începutul programului, în afara oricărei funcţii.

Variabile locale: declararea se face în corpul funcţiei, la început.

Exemplificare

char c;
signed char sc;

int a, b;
a = b = 5;

int i;
int suma = 0;
long j;

float x1,,x2, x3;
float pi = 3.14;
double y;

int patrat(int y)
{  
      int x;  x=y*y; 
      return x; 
}

Variabila x este caracterizata de
  • Tip = int
  • Nume = x
  • Valoare = 4
  • Domeniu de vizibilitate: funcția patrat
  • Timp de viaţă = pe durata unui apel al funcției

Atribuirea (Asignarea) variabilelor

variabila = expresie;

SAU

Lvalues (left-side) = Rvalues (right-side)

  • Lvalues sunt variabile
  • Rvalues sunt expresii

Exemplu

În atribuirea

distance = rate * time;

avem: Lvalue: „distance” și Rvalue: „rate * time”

Contraexemple pt Lvalue: 5+5, “str”, const int i

În atribuiri apar alte două probleme, despre care vom vorbi mai târziu:

  • Compatibilitate
  • Conversii

Tipuri de variabile și vizibilitatea lor

Tip de date

Prin tip de date vom înţelege o mulţime de valori, împreună cu operaţiile ce se pot executa cu ele. Fiecărei variabile, la declarare, i se va asocia un anumit tip. Tipul unei constante poate fi determinat implicit din valoarea constantei, sau poate fi precizat explicit ca în cazul variabilelor. Astfel, dacă constanta K are valoarea numerică 7, putem trage concluzia că ea este de tip întreg, sau de tip real, nu şi logic sau şir de caractere.

Totuşi, există şi limbaje în care se fac anumite convenţii, de pildă că orice număr diferit de zero este considerat ca fiind cu valoarea de adevăr adevărat, iar numărul zero are valoarea de adevăr fals.

Unele limbaje de programare permit declararea unor variabile fără a se preciza tipul lor, considerându-se astfel ca având un anumit tip general. Astfel, atunci când va fi folosită, variabila respectivă va fi considerată ca având cel mai adecvat tip cu putinţă, în situaţia concretă respectivă. De pildă, dacă este declarată o variabilă X, iar la un moment dat i se atribuie valoarea 3,. atunci ea poate fi considerată ca având un tip numeric. Dacă ulterior, variabila X va primi valoarea „abc”, adică un şir de caractere, se poate considera că X este de tip şir de caractere.

Pe baza constantelor şi variabilelor se formează expresii. Bineînţeles, în formarea expresiilor se vor folosi acei operatori, precum şi acele funcţii, permise de tipurile valorilor asupra cărora se operează. Expresiile mici pot conduce la elaborarea de expresii mai mari, din ce în ce mai complexe

Domeniul tipului (colecţia de obiecte) – mulțime de valori pentru care s-a adoptat un anumit mod de reprezentare în memorie

Operaţiile tipului = operațiile ce se pot executa cu valorile de acel tip de date

Categorii de tipuri de date:

  • Tipuri de date standard
  • Tipuri de date structurate de nivel jos – operaţiile se desfășoară la nivel de componentă
  • Tipuri de date de nivel înalt – operaţiile sunt implementate de algoritmi utilizator

Tipuri de date standard în C++

  • Tipuri caracter: tipurile char, signed char, unsigned char
  • Tipuri întregi: tipurile caracter, întregi cu semn, întregi fără semn, tipurile enumerare
  • Tipuri reale: tipurile întregi şi tipurile flotante reale
  • Tipuri aritmetice: tipurile întregi şi cele flotante
  • Tipuri de bază: caracter, întregi cu şi fără semn, flotante
  • Tipul void: desemnează o mulţime vidă

(32 biți)

Echivalențe între tipurile de date

signed short int ≡ short
unsigned short int ≡ unsigned short
signed int ≡ int
unsigned int ≡ unsigned
signed long int ≡ long
unsigned long int ≡ unsigned long

Tipuri de date derivate

Acestea se construiesc din obiecte, funcţii şi tipuri incomplete:

  • tipul tablou de T (elementele de tip T)
  • tipul structură
  • tipul uniune
  • tipul funcţie, derivat din tipul returnat T şi numărul şi tipurile parametrilor (funcţie ce returnează T)
  • Tipul pointer, derivat dintr-un tip referenţiat (tip funcţie, tip obiect, tip incomplet). Valorile tipului pointer sunt referinţe la o entitate de tipul referenţiat (pointer la T)
  • Tipuri scalare: tipurile aritmetice şi tipul pointer
  • Tipuri agregat: tablouri şi structuri
  • Un tablou de dimensiune necunoscută, o structură sau uniune cu conţinut necunoscut sunt tipuri incomplete

Tipuri întregi

Constante întregi

  • Octale: au prefixul 0 (zero), de exemplu: 032 = 26   și    077 = 63
  • Hexazecimale: au prefixul 0x sau 0X, de exemplu: 0x32 = 50 și 0x3F = 63
  • Întregi „long”: au sufixul l sau L, de exemplu: 2147483647L și 0xaf9Fl = 44959
  • Întregi „unsigned” au sufixul u sau U, de exemplu: 345u și 0xffffu = 65535
  • Caractere între apostrof: ‘A’, ‘+’, ‘n’
  • Caractere în zecimal: 65, 42
  • Caractere în octal: ’\101’, ‘\52’
  • Caractere în hexazecimal: ‘\x41’, ‘\x2A’
  • Caractere speciale – secvențe escape

Operații și funcții pentru tipurile întregi

Operaţii pentru tipurile întregi: + – * / % == != < <= > >= ++ —

Funcţii:

  • cele de la tipul flotant
  • cele din bibliotecă: tolower, toupper, isalpha, isalnum, iscntrl, isdigit, isxdigit, islower, isupper, isgraph, isprint, ispunct, isspace

Operatori

Operatorii ++ și —

Se aplică doar unei expresii ce desemnează un obiect din memorie (L-value):

Alte exemple:

++5 –(k+1) ++i++ nu au sens
(++i)++ are sens

Tipul flotant (real)

float

  • Numere reale în simplă precizie
  • sizeof(float) = 4
  • 10^-37<=abs(f)<=10^38
  • 6 cifre semnificative

double

  • Numere reale în dublă precizie
  • sizeof(double) = 8
  • 10^-307<=abs(f)<=10^308
  • 15 cifre semnificative

long double

  • Numere reale în „extra” dublă precizie
  • sizeof(long double) = 12
  • 10^-4931<=abs(f)<=10^4932
  • 18 cifre semnificative

Limitele se găsesc în <float.h>

Operaţii: + – * / == != < <= > >=

Constante reale

  • Constantele reale sunt implicit double:
     125.435 1.12E2 123E-2 .45e+6 13. .56
     1.12E2 = 1.12 x 102 = 112
     123E-2 = 1.12 x 10-2 = 1.23
     .45e+6 = 0.45 x 106 =450000
     13. = 13.00 şi .56 = 0.56
  • Pentru a fi float trebuie sa aiba sufixul f sau F
     .56f 23e4f 45.54E-1F
     23e4f = 23 x 104 = 230000.00
  • Pentru long double trebuie sa aibă sufixul l sau L
     123.456e78L

Funcţii (în biblioteca math.h):

sin, cos, tan, asin, acos, atan, sinh, cosh, tanh, exp, log, log10, pow, sqrt, ceil, floor, fabs, ldexp, frexp, modf, fmod.

Date booleene (logice)

Tipul bool

  • Domeniul de valori: {false, true}
  • false = 0
  • true = 1, dar şi orice întreg nenul
  • Operaţii: ! && || == !=
  • Declaraţii posibile:
     bool x = 7; // x devine “true”
     int y = true; // y devine 1

Expresii logice

expresie_relationala ::= expr < expr | expr > expr | expr <= expr | expr >= expr | expr == expr | expr != expr expresie_logica ::= ! expr | expr || expr | expr && expr

Valoarea expresiilor relaţionale

Negația logică

! 0 = 1, ! orice_nr_diferit_de_0 = 0

Disjuncția logică. Valoarea expresiilor logice ||

Conjuncția logică. Valoarea expresiilor logice &&

Exemple

O condiţie de forma a ≤ x ≤ b se scrie în limbajul C++ astfel:

(x >= a) && (x <= b) (a <= x) && (x <= b)

O condiţie de forma a > x sau x > b se scrie în limbajul C++ astfel:

(x < a) || (x > b) !(x >= a && x <= b)

Legile lui De Morgan

  • ! (A && B) este echivalent cu !A || ! B
  • ! (A || B) este echivalentă cu ! A && ! B

Tipul void

  • Conversia în tip void a unei expresii semnifică faptul că valoarea sa este ignorată
  • Utilizat pentru tipul pointer; nu se face controlul tipului la un pointer de tip void
  • Utilizat pentru funcţii fără valoare returnată sau pentru funcţii fără parametri
  • Este un tip incomplet ce nu poate fi completat
  • Conversia în tip void a unei expresii semnifică faptul că valoarea sa este ignorată
  • Utilizat pentru tipul pointer; nu se face controlul tipului la un pointer de tip void
  • Utilizat pentru funcţii fără valoare returnată sau pentru funcţii fără parametri
  • Este un tip incomplet ce nu poate fi completat

Structuri. Utilizare typedef 

Typedef este un mecanism prin care se asociază un tip unui identificator:

typedef char litera_mare;
typedef short varsta;
typedef int vector[20];
typedef char string[30];
typedef float matrice[10][10];
typedef struct { double re, im; } complex;

Identificatorul respectiv se poate utiliza pentru a declara variabile:

litera_mare u, v=‘a’;
varsta v1, v2;
vector x; string s;
matrice a;
complex z;

sau funcții

complex suma(complex z1, complex z2) { 
  complex z; 
  z.re=z1.re+z2.re; z.im=z1.im+z2.im; 
  return z;
}

Operatorul condiţional ? :

Sintaxa

exp1 ? exp2 : exp3

Semantica 

  • Se evaluează exp1
  • Dacă exp1 are valoare true (nenulă), atunci valoarea expresiei este valoarea lui exp2; exp3 nu se evaluează
  • Dacă exp1 are valoare false (nulă), atunci valoarea expresiei este valoarea lui exp3; exp2 nu se evaluează

Operatorul ?: este drept asociativ

Exemple

x >= 0 ? x : y
x > y ? x : y
x > y ? x > z ? x : z : y > z ? y : z
joc=(raspuns==’1’)?JocSimplu();JocDublu();
#include <iostream>
using namespace std;
void main(){
   int a=1, b=2, c=3;
   int x, y, z;
   x = a?b:c?a:b;
   y = (a?b:c)?a:b; /* asociere stanga */
   z = a?b:(c?a:b); /* asociere dreapta */
   cout<< "x=" << x << "\ny=" << y << "/nz="<< z;
}
/* x=2 y=1 z=2 */

Operatorul virgulă ,

Sintaxa

expresia_virgula ::= expresie, expresie

Semantica

  • Se evaluează prima expresie apoi cea de-a doua.
  • Valoarea şi tipul întregii expresii este valoarea şi tipul operandului drept.
  • Operatorul virgulă are cea mai mică precedenţă.

Exemplu

a = 1, b = 2;
i = 1, j = 2, ++k + 1;
k != 1, ++x * 2.0 + 1;
for(suma = 0, i = 1; i <= n; suma += i, ++i);

Operatorul sizeof()

sizeof() este un operator unar ce permite determinarea numărului de octeţi pe care se reprezintă un obiect (un tip sau o expresie)

Exemple:

sizeof(int), sizeof(double);
sizeof(b*b-4*a*c), sizeof(i);
sizeof(char)<=sizeof(short)<=sizeof(int)<=sizeof(long)
sizeof(signed)=sizeof(unsigned) = sizeof(int)
sizeof(float)<=sizeof(double)<=sizeof(long double)

Utilizare

#include <iostream>
using namespace std;
void main(){
  int x = 1; double y = 9; long z = 0;
  cout << "Operatorul sizeof()\n\n\n";
  cout << "sizeof(char) = " << sizeof(char) << endl;
  cout << "sizeof(int) = " << sizeof(int) << endl;
  cout << "sizeof(short) = " << sizeof(short) << endl;
  cout << "sizeof(long) = " << sizeof(long) << endl;
  cout << "sizeof(float) = " <<sizeof(float) << endl;
  cout << "sizeof(double) = " << sizeof(double) << endl;
  cout << "sizeof(long double) = " << sizeof(long double) << endl;
  cout << "sizeof(x +y + z) = " << sizeof(x+y+z) << endl;
}

Rezultatul executiei Visual C++:

Operatorul sizeof()

sizeof(char) = 1
sizeof(int) = 4
sizeof(short) = 2
sizeof(long) = 4
sizeof(float) = 4
sizeof(double) = 8
sizeof(long double) = 8
sizeof(x + y + z) = 8

Tabel cu prioritatea și asociativitatea operatorilor

Reguli pentru conversia implicită

În absenţa unui unsigned , obiectele se convertesc la tipul cel mai “înalt” în ordinea (descrescătoare):

long double, double, float, long int, int

Regulile pentru operanzii unsigned depind de implementare.

Conversia la unsigned se face doar în caz de necesitate (de ex. valoarea din unsigned nu “încape” în celălalt operand).

Regula “integer promotion” : operaţiile se fac cel puţin în int, deci char şi short sunt “promovaţi” la int.

La o asignare (v = exp) tipul membrului drept se converteşte la tipul membrului stâng (care este şi tipul rezultatului).

ATENŢIE! Se pot produce:

  • Pierderea preciziei (double ->float ->long int)
  • Pierderea unor biţi semnificativi (long ->int)
  • Nedeterminări

Exemplu conversii implicite

#include <iostream>
using namespace std;
int main(void){
   char c1 = -126, c2;          /* c1 = 10000010    */
   unsigned char c3, c4 = 255;  /* c4 = 111111111   */
   short s1, s2 = -32767; /* s2=10000000 00000001   */
   short s3 = -1, s4;     /* s3 = 11111111 11111111 */
   s1 = c1;
   cout << "c1=" << (int)c1 << " s1=" << s1 << endl;
   c2 = s2;
   cout << "c2=" << (int)c2 << " s2=" << s2 << endl;
   c3 = s3;
   cout << "c3=" << (int)c3 << " s3=" << s3 << endl;
   s4 = c4;
   cout << "c4=" << (int)c4 << " s4=" << s4 << endl;
   return 0;
}

Exemplu (rezultatul execuţiei)

Forţarea tipului – cast

  • Conversia explicită la tipul numetip se face prin:

(numetip) expresie

Exemple:

(long)(‘A’ + 1.0)
(int)(b*b-4*a*c)
(double)(x+y)/z
(float)x*y/z
x / (float)2

Exemplu cast

#include <iostream>
using namespace std;
int main(void){
   int i, j; double x, y, z, t;
   i = 5/2; x = 5/2;
   y = (double)(5/2);  j = (double)5/2;
   z = (double)5/2;   t = 5./2;
   cout << i << ", " << x << ", ";
   cout << y << ", " << j << ", ";
   cout << z << ", " << t << ", " << endl;
   return 0;
}
/* 2, 2, 2, 2, 2.5, 2.5 */

Fişiere în bibliotecă relative la tipuri

<limits.h>

  • pentru tipurile întregi
  • Întregul min/max: INT_MIN, INT_MAX
  • Numărul de biţi pe caracter CHAR_BIT
  • Etc.

<float.h>

  • pentru tipurile flotante:
  • Exponentul maxim
  • Precizia zecimală, etc.

<stdlib.h>

  • conţine funcţii de conversie:
  • Şir de caractere în int: atoi(const char*)
  • Şir de caractere în float: atof(const char*)
  • Test de evaluare a cunoștințelor

Rezumat

Discuție cu studenții în clasă

Test de verificare a cunoștințelor

Formular Google Forms

Partea 2

  • Intrări – ieșiri
  • Instrucţiuni

Intrări / ieșiri

Forma generală
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; 

cout << var1 << var2 ... << varN; 

Intrări / ieșiri: exemplu – caractere

Intrări / ieșiri: exemplu – coduri ASCII

Pe tablă explicații despre codurile ASCII și sortarea șirurilor de caractere în diferite programe, în funcție de 

Coduri speciale: 7 (BELL), 10 LF (Line Feed), 13 CR (Carriage Return), 27 ESC (Escape), 32 Space, 33 !, …., 48 ‘0’, …, 65 ‘A’, 66 ‘B’,… , 97 ‘a’, 98 ‘b’,… .

Instrucțiuni

Instrucţiunea expresie

Sintaxa:

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

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ă.

Semantica:

  • 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 <<endl;
} // ?

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:

Regula este: else este ataşat celui mai apropiat if.

int a=1, b=2; // b=3
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:

int main(void){
    float operand1, operand2, rezultat;
    char operator;
    cout << "Expresia:(numar operator numar – FARA SPATII)\n";
    cin >> operand1 >> operator >> operand2;
    if(operator == '+')
          rezultat = operand1+operand2;
    else if(operator == '-')
          rezultat = operand1-operand2;
    else if(operator == '*')
          rezultat = operand1*operand2;
    else if(operator == '/')
          rezultat = operand1/operand2;
    else{
         cout << "Eroare in scrierea expresiei!";
         return 1;
    }
    cout << "Rezultatul este: " << rezultat << "\n";
    return 0;
}

Instrucţiunea switch

Sintaxa:

switch (expresie)
{
  case constanta1:
     grup de instructiuni 1;
     [break;] (break este opțional)
  case constanta2:
     grup de instructiuni 2;
     [break;]
  .
  .
  .
  [default:
     grup implicit de instructiuni] (default este opțional)
}

Semantica:

  • Se evaluează expresia.
  • Dacă ea are valoarea constanta1, atunci se execută grupul de instrucțiuni 1, eventual grupul de instrucțiuni2 etc., până la întâlnirea primului break.
  • Dacă ea are valoarea constanta2, atunci se execută grupul de instrucțiuni2 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.

Exemple:

  • Valoarea expresiei expression, care este de tip int, se compară cu constantele constanti.
  • În caz de egalitate se execută instrucţiunea corespunzătoare si toate cele ce urmează. Există posibilitatea de ieşire cu instrucţiunea break.
  • Dacă valoarea determinată diferă de oricare din constantele specificate, se execută instrucţiunea specificată la default, care apare o singură dată, nu neaparat la sfârşit. Dacă default lipseşte se iese din switch.
  • 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.
int i;
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

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

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;

Instrucțiunea do-while

Sintaxa:

Semantica:

  • Se execută instructiune.
  • Se evaluează conditie: 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;

 

Exemplu – calculator

int main(void){
    float operand1, operand2, rezultat;
    char operator, 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(y != 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;
}

Instrucţiunea for

Sintaxa:

Una, doua sau toate trei dintre 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: expr-init;
while(expr-cond){
   instructiune;
   expr-in/decrementare;
}
instructiunea_urmatoare
  • Dacă există continue atunci aceasta 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 do (instrucţiune), se evalueaza expr-in/decrementare si controlul este trecut la începutul buclei do, 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).

Exemple:

i = 1;
suma = 0;
for(;i <= N;++i) suma += i;

i = 1;
suma = 0;
for(;i <= N;) suma += i++;

i = 1;
suma = 0;
for(;;) suma += i++; // Bucla infinita

Instrucţiuni de întrerupere a secvenţei

  • break;
    • se referă la bucla sau instrucţiunea switch cea mai apropiată.
    • produce ieşirea din buclă sau din switch şi trece controlul la instrucţiunea următoare
  • continue;
    • se referă la bucla (for, while, do..while) cea mai apropiată.
    • întrerupe execuţia iteraţiei curente şi  trece controlul la iteraţia următoare.
  • goto;
    • Permite saltul la o anumită secțiune din program, identificată prin punctul de începere.
  • return expr;   sau      return;

Exemple:

int n;
  for (n=10; n>0; n--)
  {
    cout << n << ", ";
    if (n==3)
    {
      cout << "countdown aborted!";
      break;
    }
  }
for (int n=10; n>0; n--) {
    if (n==5) continue;
    cout << n << ", ";
  }
  cout << "FIRE!\n";
int n=10;
  loop:
  cout << n << ", ";
  n--;
  if (n>0) goto loop;
  cout << "FIRE!\n";
  return 0;

int i, suma=0;
for(i = 1; i<=N; i++){
   if(i%3 != 0) continue;
   suma+=i;
   }
cout << “suma = ” << suma; /* suma multiplilor de 3 până la N */

Instrucţiuni de iteraţie – recomandare

  • Pentru expresia de control a iteraţiei se recomandă operatorii relaţionali în locul celor de (ne)egalitate:
int main(){
   int contor = 0;
   double suma = 0.0, x;
   for(x = 0.0; x != 9.9; x += 0.1){
       suma += x; 
       ++contor;
   }
   cout << "suma = " << suma << ", contor= " << contor << "\n";
   return 0;
}

  • Folositi x < 9.9 in loc de x != 9.9