Documente Academic
Documente Profesional
Documente Cultură
Fundamentele Limbajului C PDF
Fundamentele Limbajului C PDF
Din mulimea identificatorilor posibili, se remarc cuvintele cheie (reserved keywords) ale
limbajului, identificatori a cror semnificaie nu poate fi modificat de programator (Tabelul 6.1.).
Cuvintele cheie din tabel care ncep cu semnul underscor reprezint variabile interne.
6.2.1. Tipul fundamental void indic absena oricrei valori i se utilizeaz n urmtoarele situaii:
declaraia unei funcii fr parametri sau care nu returneaz un rezultat, tipul pointer generic i conversii de
tip cu operatorul cast pentru pointeri.
Iat cteva exemple de expresii care returneaz ca valoare spaiul de memorie ocupat de date de diferite
tipuri:
sizeof (long int);
sizeof (unsigned char)
sizeof (long double)
Observaie: C++ admite delimitatorii /* */ pentru inserarea de comentarii care se pot ntinde pe mai multe
rnduri i, n plus, introduce delimitatorul // pentru includerea de comentarii de sfrit de linie.
Tot textul care urmeaz dup delimitatorul // pn la sfritul liniei este considerat comentariu.
2
6.2.2. Constante
Constantele sunt valori fixe (numerice, caractere sau iruri de caractere), care nu pot fi modificate n
timpul execuiei programului. Tipul constantei este determinat de compilator pe baza valorii i sintaxei
utilizate. Ele rmn n memorie pe toat durata execuiei programului.
6.2.2.1. Constante ntregi
Tipul constantei este determinat pe baza valorii, sau prin utilizarea unui sufix (U sau u pentru unsigned,
respectiv L sau l pentru long). Constantele ntregi pot fi zecimale, octale sau hexazecimale.
Constante zecimale (baza 10)
Constantele zecimale se disting prin faptul c prima cifr este diferit de 0, cum ar fi:
23
// tip int
23u
// tip unsigned int
32768
// tip long int
77UL
// tip unsigned long int
Constante octale (baza 8)
Constantele octale sunt valori avnd prima cifr 0. Cifrele 8 i 9 sunt ilegale.
-067
// tip int
067u
// tip unsigned int
020000000 // tip long int
055ul
// tip unsigned long
089
// eroare, prima cifr indic reprezentarea n octal i numrul include cifrele 8 i 9
Constante hexazecimale (baza 16)
Constantele hexazecimale se disting prin prefixul 0x sau 0X. Pot conine cifre mai mari de 9 (af, sau
AF).
0x7FFF
// tip int
0X8000
// tip unsigned int
0xffu
// tip unsigned int
0x10000
// tip long int
0xFFul
// tip unsigned long int
6.2.2.2. Constante n virgul mobil
Constantele n virgul mobil sunt valori raionale a cror reprezentare conine n general urmtoarele
cmpuri:
parte ntreag
punct zecimal
parte fracionar
e sau E i un exponent cu semn (opional)
sufix de specificare a tipului: f sau F (foreaz tipul float) sau l sau L (foreaz tipul long double).
Se pot omite partea ntreag sau partea fracionar (dar nu amndou), punctul zecimal sau litera e (E) i
exponentul (dar nu amndou).
Tipul implicit pentru constantele n virgul mobil este tipul double.
2.1
11.22E5
-.33e-2
.5
1.
1.f
0.L
// se afieaz caracterul ?
// se afieaz caracterul ?, 63 fiind valoarea corespunztoare n codul ASCII
// se afieaz caracterul ?
// se afieaz caracterul ?
Observaie: n C, toate constantele de un singur caracter au tipul int i sunt reprezentate intern pe 16 bii cu
octetul mai semnificativ 0 pentru valoarea caracterului mai mic dect 128, sau 1 (0xFF) pentru valori n
intervalul 128255.
- legtura precizeaz modul de asociere a unui identificator cu un anumit obiect sau funcie, n procesul de
editare a legturilor.
Atributele se pot asocia identificatorilor n mod implicit, n funcie de poziia i sintaxa declaraiei sau
explicit prin utilizarea unor specificatori.
Sintaxa unei declaraii de variabil impune specificarea tipului, avnd forma general:
tip_var nume_var;
tip_var este un specificator de tip de date oarecare, standard, pointer sau definit de utilizator.
// declararea variabilei r de tip pointer la float,
// declararea variabilei n de tip unsigned int
float * r;
unsigned int n;
}
int functie (int n, float q)
}
6
Observaii:
1. ntr-un bloc inclus n domeniul unei declaraii este permis o declaraie local a aceluiai identificator,
asocierea fiind ns fcut unui alt obiect cu alocarea altei zone de memorie.
2. Spre deosebire de C, care impune gruparea declaraiilor locale la nceputul unui bloc, C++ permite
plasarea declaraiilor n interiorul blocului, bineneles nainte de utilizarea obiectului.
void main (void)
{
}
Clasa de memorare se poate preciza prin specificatorii auto, static, extern, register. Aceti specificatori
precizeaz modul de alocare a memoriei i timpul de via pentru variabile i legtur pentru funcii i
variabile.
auto
Declaraia auto specific o variabil automatic i se poate utiliza pentru variabile cu domeniul local (cu
spaiu alocat pe stiv). Variabilele ce se declar n interiorul unui bloc sunt implicit automatice, astfel c
declaraia auto este rar folosit.
void fct()
{
auto float r;
double s;
...
}
static
Declaraia static a unei variabile locale foreaz durata static fr a modifica domeniul de existen.
Variabilele statice i pstreaz valoarea ntre dou apeluri succesive ale blocurilor care le conin,
asigurndu-se n acelai timp o protecie, dar ele nu pot s fie accesate din blocuri care nu constituie
domeniul lor de existen. Variabilele statice pot fi declarate cu iniializare, n caz contrar, implicit se
iniializeaz cu valoarea 0, similar variabilelor globale.
#include <stdio.h>
int fct()
{
// se declar o variabil local funciei, cu durat static
static int a=2;
return (a++); }
void main(void)
{
int n;
n=fct();
printf (\n Prima atribuire : n= %d, n);
n=fct();
printf (\n A doua atribuire : n= %d, n);
}
Programul afieaz:
Prima atribuire : n= 3 (la primul apel al funciei, variabila a are valoarea iniial 2, ea fiind apoi
incrementat ).
A doua atribuire : n= 4 (la al doilea apel al funciei, variabila a are la nceput valoarea 3, valoare datorat
apelului anterior al funciei, valoarea fiind apoi incrementat.
register
Declaraia register are ca efect memorarea variabilei ntr-un registru al procesorului i nu n memorie,
avnd ca rezultat creterea vitezei de execuie a programului. Aceste variabilele pot fi variabile locale,
nestatice, de tip int sau char. Numai dou variabile pot fi memorate simultan n registre, n cazul existenei
mai multor declaraii register, cele care nu pot fi onorate vor fi tratate
de compilator ca variabile obinuite.
register char c;
extern
Specificatorul extern indic legtura extern i asigur durata static pentru variabile locale i globale sau
pentru funcii (acestea au implicit legtur extern i durat static).
Pentru identificatorii cu legtur extern sunt permise mai multe declaraii de referin, dar o singur
definiie. De exemplu, n cazul unui proiect n care o variabil se folosete n mai multe fiiere, ea se va
defini global ntr-un fiier, n celelalte fiind declarat extern fr definire. Compilatorul i va aloca o
singur dat memorie.
// Fiier Ex_prj.cpp
#include <stdio.h>
scanf(%d, &m);
printf(\nm= %#x, m);
}
// Fiier Ex_prj1.cpp
...
int m ;
// declaraia variabilei m
n exemplul anterior, cele dou fiiere, Ex_prj.cpp i Ex_prj1.cpp, se includ ntr-un proiect utiliznd
opiunea project a meniului principal din mediul de programare C/C++. Variabila m este declarat global
ntr-unul dintre fiiere, ea putnd fi referit din cellalt fiier datorit specificrii legturii extern .
O variabil pointer constant nu se poate modifica, n schimb se poate modifica obiectul indicat.
n cazul unui pointer ctre un obiect constant, valoarea pointerului este modificabil, dar nu i valoarea
obiectului.
void main()
{
int var1=25, var2=44;
const int var3=7;
int * p1=&var1;
int * p2=&var3;
const int * p3=&var3;
var3++;
*p3=15;
int * const p4=&var1;
p4=&var2;
*p4++;
// declaraie cu iniializare
// eroare, nu se poate converti const int * la int *
// corect, tipul de date corespund
// eroare, se ncearc modificarea unui obiect constant
// eroare, se ncearc modificarea unui obiect constant
// corect, se declar un pointer constant
// eroare, se ncearc modificarea unui pointer constant
// corect, se modific valoarea obiectului var2 care nu
// este declarat constant
}
n mod uzual se folosesc funcii cu parametri pointeri ctre obiecte constante atunci cnd se dorete
protejarea la modificare a acestora.
Un exemplu este o funcie care realizeaz criptarea unui ir de caractere:
#include <stdio.h>
#include <string.h>
void criptare(const char *sir_i, char *sir_c);
void main()
{
char sir_initial[80], sir_criptat[80];
sir_initial=Exemplu criptare;
criptare(sir_initial, sir_criptat);
printf(\nSirul criptat este: %s, sir_criptat);
}
void criptare( const char *sir_i, char *sir_c)
{
while (*sir_i)
{
// criptarea se face prin modificarea codului ASCII
*sir_c = * sir_i+1 ;
sir_i ++ ;
sir_c ++ ;
}
*sir_c=\0;
}
volatile
Variabilele volatile pot fi modificate din exteriorul programului (de exemplu servirea unei ntreruperi).
6.2.4. Declaraia typedef
Specificatorul typedef nu declar un obiect, ci asociaz un nume unui tip de date. Sintaxa este:
typedef tip_data identificator_tip
typedef unsigned char octet;
octet var;
// pointer la ntreg
// tablou de pointeri ctre ntregi
// dubl indirectare; pointer la pointer
Este important c orice variabil pointer trebuie iniializat cu o valoare valid, 0 (NULL) sau adresa unui
obiect nainte de a fi utilizat. In caz contrar, efectele pot fi grave deoarece la compilare sau n timpul
execuiei nu se fac verificri ale validitii valorilor pointerilor.
Operatori specifici.
Exist doi operatori unari care permit folosirea variabilelor pointer:
operatorul & se folosete pentru aflarea adresei unei variabile oarecare i
operatorul * pentru accesul la variabila adresat de un pointer.
#include <stdio.h>
void main(void)
{
int var=20, *pvar;
printf("\nVariabila var se afla la adresa %p, &var);
printf("si are valoarea var= %d", var);
pvar=&var;
printf("\nVariabila pvar are valoarea %p, pvar);
printf("si adreseaza obiectul: %d", *iptr);
10
*iptr=50;
printf("\nNoua valoare a lui var este %d, var);
}
Programul afieaz:
Variabila var se afl la adresa: FFF4 si are valoarea iv= 20
Variabila pvar are valoarea: FFF4 si adreseaza obiectul: 20
Noua valoare a lui var este 50
Situaia:
tipl * id_pl;
tip2 * id_p2;
id_pl=&id_p2;
nu genereaz erori dac tip1 i tip2 sunt identice, sau, n caz contrar dac tip1 este void.
Dac se folosete un pointer void, pentru orice referire a obiectului adresat este necesar precizarea
explicit a tipului utiliznd operatorul cast.
void main()
{ void *p1;
float *p2, var=1.5;
p2=&var;
p1=p2;
printf(\nValoarea referita de p1: %f , * (float *) p1);
}
n exemplul anterior, att p, ct i r, acioneaz asupra variabilei n. Atunci cnd se acceseaz o variabil
prin referina sa, nu este necesar s se foloseasc adresa, acest lucru realizndu-se automat.
Spre deosebire de pointeri, care la un moment dat pot primi ca valoare adresa unei alte variabile, referinele
nu pot fi modificate, ele fiind practic o redenumire a variabilei a cror adres o conin (se creeaz un alias
al respectivei variabile).
n utilizarea referinelor, trebuie avute n vedere urmtoarele restricii:
referinele trebuie iniializate n momentul declarrii;
referinelor nu li se pot modifica locaiile la care se refer;
11
nu sunt permise referine la cmpuri de bii, referine la referine i pointeri la referine, deci nici
tablouri de referine.
int &r ;
// eroare, se declar o referin fr iniializare
int &r=20 ;
// corect, se declar o referin la o constant
const int i = 20;
// eroare, se declar o referin ntreag la o constant ntreag
int &r = i ;
const int i = 20;
const int &r = i ; // corect, se declar o referin constant ntreag la o constant ntreag
Observaie: Referinele de sine stttoare sunt rar folosite. n schimb, utilizarea parametrilor formali
referin permite transferul prin referin simplu i eficient, fr recurgerea la parametri formali pointeri.
6.2.4.3. Tablouri de date
Tabloul de date (sau masiv de date) este o colecie de date de acelai tip, plasate ntr-o zon
contigu de memorie.
Sintaxa declaraiei unui tablou cu N dimensiuni este:
tip_element nume_tablou [dimensiune1][dimensiune2][dimensiuneN]
Zona de memorie rezervat conine dimensiune1 x dimensiune2 x...x dimensiuneN elemente de tipul
tip_element.
Referirea unui element de tablou se face cu operatorul de indexare [ ] sub forma:
nume_tablou [indice1][indice2]...[indiceN]
Declaraia unui tablou se poate face cu iniializarea sa folosind sintaxa:
declaratie_tablou={list_valori};
Lista de valori trebuie s conin constante de tip compatibil cu tipul de baz al tabloului, n ordinea plasrii
n memorie.
float vect1[5];
// se declar un tablou cu 5 elemente float, fr iniializare
vect1[0]=1.5;
// elementului de index 0 i se atribuie valoarea 1.5
int vect2[10]={2,7,-1,0,9,15,-5,22,6,11};
// se declar un tablou cu 10 elemente int cu
// iniializare
// se declar un tablou bidimensional cu 2*3
// elemente de tip ntreg, cu iniializare
mat[1][2]= 23;
// elementului de indeci 1, respectiv 2, i se atribuie valoarea 23
Tablourile unidimensionale cu elemente de tip char sunt folosite pentru memorarea irurilor de caractere.
Pentru a marca sfritul unui ir de caractere, dup ultimul caracter se adaug un octet cu valoarea 0 (\0),
numit i terminator de ir.
int mat[2][3]={{3,5,-3},{2,-1,0}};
Numele unui tablou fr index este un pointer constant de tipul elementelor tabloului i are ca valoare
adresa primului element al tabloului.
12
&tab[0] = = tab ;
&tab[2] = = tab+2 ;
tab[0] = = *tab ;
tab[2] = = *(tab+2) ;
tab++ ;
// eroare, tab este un pointer constant, deci nu se poate incrementa
ptr++ ;
Tablourile multidimensionale reprezint tablouri cu elemente tablouri, astfel nct numele tabloului (fr
index) este un pointer de tablouri.
float mat[10][10];
float *p;
p=mat;
p=(float*)mat;
mat = = &mat[0][0];
mat+1 = = &mat[1][0];
*(mat+9) = = mat[9][0];
sau
typedef enum {false, true} boolean; // declaraia este echivalent declaraiei anterioare
# include <stdio.h>
// valoarea identificatorului false este 0, iar a lui true este 1
enum boolean {false, true};
void main()
{
boolean op1=false, op2;
op2=true;
printf(\n op1=%d\nop2=%d, op1, op2);
}
Tipul enumerare faciliteaz operarea cu variabile care pot lua un numr mic de valori ntregi, asociindu-se
nume sugestive pentru fiecare valoare.
Programul devine mai clar i mai uor de urmrit.
6.2.4.4.2. Structuri
Structura este o colecie de date referite cu un nume comun. O declaraie de structur precizeaz
identificatorii i tipurile elementelor componente i constituie o definiie a unui nou tip de date.
Sintaxa declaraiei unui tip structur este:
struct id_tip_struct {
tip_elem1 id_elem1;
tip_elem2 id_elem2;
Referirea unui membru al unei structuri indicate de un pointer se face folosind operatorul de selecie
indirect (->) (sgeat).
persoana * p_pers;
// se declar un obiect pointer la persoana
puts(\nIntroduceti numele:);
scanf(%s, &p_pers->nume);
puts( \nIntroduceti prenumele:)
scanf(%s, &p_pers->prenume);
puts( \nIntroduceti data nasterii:);
scanf(%d.%d.%d, &p_pers->data_n.zi, &p_pers->data_n.luna, &p_pers->data_n.an);
Operatorul de atribuire admite ca operanzi variabile structur de acelai tip, efectund toate atribuirile
membru cu membru.
persoana p1={Popescu, George, 5, 12, 1982}, p2; // p1 se declar cu iniializare
// prin atribuire, p2 preia, membru cu membru datele din p1
p2=p1;
15
printf(\nNumele:%s, p2.nume);
printf(\nPrenume:%s, p2.prenume;
printf(\nData nasterii: %d.%d.%d, p2.data_n.zi, p2.data_n.luna, p2.data_n.an);
#include <stdio.h>
typedef struct complex {int re, im;} ;
complex suma(complex *a, complex *b)
{
complex c;
c.re=a->re+b->re;
c.im=a->im+b->im;
return c;
}
void main()
{
complex c1, c2, c3;
c1.re=12;
c1.im=-7;
c2.re=29;
c2.im=35;
c3=suma(&c1, &c2);
printf("\n%i %i", c3.re, c3.im);
}
Pentru transferul parametrilor de tip structur se pot folosi variabile referin de structur de acelai tip.
16
include <stdio.h>
typedef struct complex {int re, im;} ;
complex suma(complex &a, complex &b)
{
complex c;
c.re=a.re+b.re;
c.im=a.im+b.im;
return c;
}
void main()
{
complex c1, c2, c3;
puts(\nIntroduceti valorile:
scanf(%d, &c1.re);
scanf(%d, &c1.im);
scanf(%d, &c2.re);
scanf(%d, &c2.im);
c3 = suma(c1,c2);
printf(\nc3=%d + i* %d", c3.re, c3.im);
}
Se poate observa c zona de memorie ocupat de un obiect date este de 3 octei, spre deosebire de structura
care nu include cmpuri de bii care ocup 6 octei.
printf(data_n ocupa %d octeti, sizeof(data_n));
6.2.4.4.4. Uniuni
Uniunea permite utilizarea n comun a unei zone de memorie de ctre mai multe obiecte de tipuri
diferite. Sintaxa de declarare a unei uniuni este similar declaraiei unei structuri:
union id_tip_uniune {
tip_elem1 id_elem1;
tip_elem2 id_elem2;
};
18
void main ()
{
intreg i;
i.val=22;
Programul afieaz:
0x16 se reprezinta in binar 00010110
6.3. Operaii de intrare / ieire cu consola
C++ permite utilizarea funciilor de intrare/ieire C, ns dispune de un sistem de intrare/ieire conceput
n spiritul POO, mai flexibil i mai comod.
n C++ sunt predefinite dispozitive logice de intrare/ieire standard similare celor din limbajul C:
cin = console input = dispozitiv de intrare consol, tastatura (echivalent cu stdin din C);
cout = console output = dispozitiv de ieire consol, monitorul (echivalent cu stdout din C).
cerr = dispozitiv de ieire pentru afiarea erorilor, fr memorare (echivalent cu stderr din C).
clog = dispozitiv de ieire pentru afiarea erorilor, cu memorare (nu are echivalent n C).
Transferul informaiei cu formatare este efectuat de operatorul >> pentru intrare (de la cin) i de <<
pentru ieire (ctre cout), deci:
cin >> var;
cout << var;
Pentru citirea/scrierea irurilor de caractere se poate specifica o constant ir sau un pointer de caractere.
Din acest motiv, pentru afiarea adresei unui ir este necesara o conversie explicit la pointer de alt tip, de
exemplu (void *).
Valorile adreselor se afieaz n hexazecimal.
Operaiile de citire de la tastatur efectuate cu operatorul >> sunt similar cu cele efectuate cu scanf().
Delimitatorii cmpurilor introduse sunt spaiu, tab, linie noua, etc. In cazul citirii unui caracter nevalid,
citirea este ntrerupt i caracterul rmne n tamponul de intrare genernd probleme similare cu cele care
apar la utilizarea funciei scanf0.
Utilizarea dispozitivelor i operatorilor de intrare/ieire C++ impune includerea fiierului antet
iostrearm.h. Exemplul urmtor este elocvent pentru elegana i simplitatea dialogului cu consola n C++.
#include <iostream.h>
void main()
{
int i;
char nume[21];
float r;
cout < < "introduceti un numar intreg si apoi un numar real: ;
cin>>i >> r;
cout << "\nAti introdus: "<< i << "si" << r <<'\n';
cout << "Introduceti numele dvs: ;
cin >> nume;
cout<<"Salut, " < < nume << " !\n ;
}
Programul afieaz:
Intruduceti un numar intreg si apoi un numar real:15 3.1416
Ati introdus:15 si 3.1416
Introduceti numele dvs: ANDREI
Salut, ANDREI !
Pentru afiare se pot utiliza expresii:
#include <iostream.h>
int main() {
int num;
cin >> num;
cout << num + 1; }
Pentru citirea/scrierea irurilor de caractere se poate specifica o constant ir sau un pointer de caractere.
Din acest motiv, pentru afiarea adresei unui ir este necesar o conversie explicit la pointer de alt tip, de
exemplu (void *).
Valorile adreselor se afieaz n hexazecimal.
#include <iostream.h>
void main()
{
char sir[20]=Sir de caractere; // se declar un ir de caractere cu iniializare
cout<<sir<<\n;
// se afieaz coninutul sirului de caractere sir
20
cout<<*sir<<\n;
cout<<&sir<<\n;
cout<<(void*)sir<<\n;
cin>>*sir;
cout<<sir<<\n;
cin>>sir;
cout<<sir<<\n;
char * p_sir=abc;
// pointeaz p_sir
// se afieaz primul caracter din irul constant de caractere
// se afieaz adresa la care se afl variabila pointer p_sir
// se afieaz adresa coninut de variabila pointer p_sir,
// deci adresa la care se afl irul constant abc
}
cout<<*p_sir<<\n;
cout<<&p_sir<<\n;
cout<<(void*)p_sir<<\n;
Programul afieaz:
Sir de caractere
S
0xffe0
0xffe0
s
sir de caractere
Alt sir de caractere
Alt sir de caractere
abc
a
0xfff4
0x00be
Programul afieaz:
Acesta este un sir prea lung pentru a fi scris pe un singur rand.
El poate fi continuat pe randul urmator.
Observaie: Trebuie reinut c operatorii >> i << i pstreaz i semnificaia din C - operatori de
deplasare bit cu bit la dreapta, respectiv la stnga.
21
Pentru formatarea intrrilor i ieirilor sunt definii o serie de manipulatori. De exemplu, ntregii pot fi
nsoii de dec, oct, hex, pentru reprezentarea n zecimal, octal, respectiv hexazecimal. Valoarea implicit
este dec. De asemenea, se poate folosi endl care insereaz caracterul \n i golete tamponul de ieire i
ends care insereaz caracterul \0 (terminator de ir de caractere).
22