This is an old revision of the document!
În acest laborator veţi învăţa să:
Atunci când definiţi o variablilă, compilatorul va fi informat despre 2 lucruri:
De exemplu, în declaraţia:
int n;
compilatorul va rezerva o zonă de memorie pentru această variabilă, de dimensiune sizeof(int) (4 Bytes, pe arhitecturi de 32bit), şi va asocia respectivei zone de memorie numele n.
Atunci când se face o atribuire,
n = 7;
în respectiva zonă de memorie va fi înscrisă noua valoare, 7.
Numele variabilelor în C au sens doar în domeniul în care au fost definite acele variabile. Acest domeniu de definiţie al unei variabile poartă numele de scope. De exemplu, în programul de mai jos, există 4 variabile distincte, toate purtând numele n!
#include <stdio.h> int n; /* Variabila 1 */ int f(int n /* Variabila 2 */) { n = 42; /* Variabila 2 */ } int g() { int n; /* Variabila 3 */ n = 42; /* Variabila 3 */ } int h() { n = 42; /* Variabila 1 */ } int main() { int n; /* Variabila 4 */ n = 42; /* Variabila 4 */ return 0; }
Observăm astfel, că nu putem accesa direct prin nume variabile definite într-o altă funcţie, deoarece numele nu au sens decât în interiorul funcţiei în care au fost declarate. Parametrii formali ai unei funcţii nu sunt altceva decât nişte variabile locale, care în momentul apelului primesc o copie a valorilor cu care a fost apelată funcţia. O funcţie de incrementare scrisă astfel:
void incorrect_increment(int n) { /* Se va incrementa doar o copie a valorii cu care a fost apelată funcţia! */ n++; }
Nu face decât să incrementeze o variaiblă locală funcţiei, efect ce nu poate fi observat din exterior!
Pentru a accesa un obiect definit într-o altă funcţie, îl putem referi, totuşi, folosindu-ne de adresa acestuia în memorie. Adresele în C poartă numele de pointeri.
Pentru a obţine adresa unei variabile, vom folosi operatorul & pus în faţa numelui variabilei, iar pentru a ne referi la valoarea memorată la o anumită adresă, vom folosi operatorul *.
Să ne amintim că pentru a citi valori cu ajutorul funcţiei scanf, trebuia să precedăm numele variabilelor citite cu operatorul &. Acest lucru se întâmplă deoarece din interiorul funcţiei scanf, unde se produce citirea, nu sunt accesibile prin nume variabilele definite în funcţia apelantă.
O funcţie care incrementează în mod corect o valoare se va scrie astfel:
void correct_increment(int* pn) { /* Vom incrementa aici variabila care este memorată la adresa pn */ (*pn)++; }
iar pentru a incrementa o variabilă numită n, va trebui să comunicăm funcţiei de incrementare locaţia acestei variabile astfel:
int main() { int n; n = 0; correct_increment(&n); /* Incrementăm valoarea memorată la adresa variabilei n. */ return 0; }
Putem să ne imaginăm memoria virtuală a calculatorului ca pe un vector foarte lung de Bytes, iar un pointer ca pe un indice în acel vector. Dimensiunea unui pointer (deci a unei adrese de memorie) depinde de tipul sistemului de operare.
Pe sistemele de operare de 32bit, fie ele Windows, Linux, Mac OS, sau altele, dimensiunea oricărui pointer va fi de 32 biţi, adică 4 Bytes, cu valori acceptate între 0 şi 2^32-1, adică un total de 4GB.
Un şir de caractere în limbajul C este o succesiune de octeţi care începe de la o adresă dată şi se termină în mod convenţional cu primul Byte întâlnit care are valoarea numerică 0 (care se poate scrie şi ca '\0', caracterul ce are codul ASCII egal cu 0).
Şirurile de caractere se memorează fie în vectori de tipul char, fie în zone de memorie alocate dinamic (despre care vom discuta la laboratorul de alocare dinamică).
De exemplu, şirul de caractere “abc” va fi reprezentat prin vectorul:
{'a', 'b', 'c', '\0'}
şi deci va ocupa 4 Bytes.