Documente Academic
Documente Profesional
Documente Cultură
M2
8. Tablouri şi pointeri
• In cadrul limbajului C/C++ există o strânsă legătură între
tablouri şi pointeri
2
Tablouri şi pointeri
3
Tablouri şi pointeri
• Exemplu:
float ftab[20], *fptr, ftemp;
int l;
...
fptr = ftab; // fptr contine adresa primului element din ftab
ftemp = ftab[0]; // este echivalent cu ftemp = *fptr
4
Tablouri şi pointeri
• Un pointer se poate indexa ca şi când ar fi un tablou
doar daca refera un tablou:
void main(void)
{
char *p;
int i;
p = str; // atribuire pointeri
for(i=0; p[i]; i++)
printf("%c",p[i]);
}
6
Tablouri şi pointeri
char str[ ];
...
*(str+1)='A';
printf("%c ", *(str+1)); // dar nu e permis str++
7
Tablouri şi pointeri
• Tablouri de pointeri
– Tablourile de pointeri se definesc astfel:
tip *nume_ptr[DIM];
– Exemplu:
int *pa[20];
int adrpoint;
...
pa[7] = &adrpoint;
*pa[7] = 127;
8
Tablouri şi pointeri
– Tablourile de pointeri se folosesc mai ales la crearea de
tabele de şiruri care pot fi selectate funcţie de anumite
valori
– Exemplu:
9
Tablouri şi pointeri
10
• Exemplu:
Fie 10 siruri de caractere ale caror adrese
se afla intr-un tablou de pointeri, char
*sir[10] si construim o functie care afiseaza
aceste siruri de caractere la un apel. Acest
lucru il putem realiza in doua moduri:
• -primul mod clasic:
- al doilea, cu pointeri dubli
11
a) clasic
• #include <iostream>
• using namespace std;
• #include <conio.h>
• void afis1_sir(char *tp[], int n);
• char *sir[10]={"a","b","c","d","e","f","g","h","i","j"};
• void main(){
• afis1_sir(sir,10);
• getch();
• }
12
• void afis1_sir(char *tp[], int n)
• {
• int l;
• for(l=0;l < n; l++)
• //if (tp[l] != NULL) //if (tp[l])
• printf("%s\n", tp[l]);
• }//afis1_sir
13
b) Pointeri dubli
• void afis2_sir(char **tp, int n)
• {char *p;
• while (n--)
• {p=*tp;
• while (*p) putchar( *p++);
• putchar(„\n‟);
• tp++;
• }//while
• }//afis2_sir
14
Tablouri şi pointeri
• Pointeri către şiruri constante
void main(void)
{
char *p;
p = "unu doi trei";
printf(“%s”, p);
}
void main(void)
{
char *p = "unu doi trei";
printf(“%s”, p);
}
void main(void)
{
char str[ ] = "unu doi trei", *p;
p = str;
printf(“%s”, p);
}
15
Tablouri şi pointeri
#include <stdio.h>
#define DIM 20
void main(void)
{
int i, dim, min;
int x[DIM];
printf("\nIntroduceti dimensiunea vectorului: ");
scanf("%d", &dim);
if(dim > DIM) {
printf("\n Dimensiune prea mare !\n");
return;
}
17
• Pointerii catre tablouri de tip T au o aritmetica in
care unitatea este:
• dim_tab * sizeof(T),
• in timp ce pointerii spre tipul T au o aritmetica in
care unitatea este sizeof (T).
• Exemplu:
• int (*p)[10];//p este un pointer spre un tablou de
10 intregi cu unitatea 10*sizeof(int) ce rezulta
usor tinind cont de faptul ca (*p) poate aparea in
ori ce context unde apre x, => int x[10].
• int *p[10];//p este un tablou de 10 pointeri spre
intregi 18
• In cazul in care avem tablouri cu mai multe
dimensiuni care se declara prin:
• T nume_tab [d1][d2]…[dn]; //unde T este tipul
elementelor si d1, d2, …, dn sunt constante
intregi si pozitive, atunci elementele tabloului
nume_tab vor ocupa o zona contigua de
memorie de dimensiunea:
• d1*d2*…*dn * sizeof(T), deci tabloul va fi
alocat la adrese succesive de memorie.
19
• Fie un tablou a de tip T si dimensiuni: d1, d2, …,
d n:
• T a[d1][d2]…[dn]; si presupunem indicii:
• i1, i2, …, in astfel incit 0 <= ik <= dk-1, unde k ia
valori intre 1 si n.
• functia f care realizeaza corespondenta intre
indicii (i1, i2, …, in) si adresa lui a[i1][i2]…[in] se
numeste functie de alocare a memoriei pentru
tabloul a, functia de alocare fiind identica pentru
toate tablourile cu aceiasi dimensiune si acelas
tip T.
20
• Notind cu d si i multiindicii:
• d = (d1, d2, …, dn)
• i = (i1, i2, …, in), si cu
• T tipul de baza al tabloului atunci functia
de alocare a memoriei pentru un tablou
oarecare a se noteaza cu:
• fd, T (i,a) , adica adresa elementului i al
tabloului a de tipul T si multiindici d este
data in limbajul C prin:
21
• fd, T (i,a) = baza (a) + sizeof(T) *[ i1d2d3…dn
+
• i2d3d4…dn +
• i3d4d5…dn +
• in-1dn +
• in
• ], deci tabloul este
alocat la adrese succesive de memorie,
ultimul indice variind cel mai repede.
baza(a) este &a[0][0]…[0].
22
• Observatii:
• -Functia de alocare nu depinde de prima
dimensiune, d1, de aceea uneori putem sa o
ignoram
• -La tablourile unidimensionale functia de
alocare devine:
• a[i] = baza(a) + sizeof (T) * i
• -Un tablou cu mai multe dimensiuni este
tratat de catre compilator ca un tablou cu o
dimensiune (si anume prima) care are ca si
elemente un tablou cu restul de dimensiuni, deci
nu exista limitari sintactice ale numarului de
dimensiuni in C 23
• In cazul transmiterii unui tablou cu mai
multe dimensiuni la o functie, este de
preferat a folosi ca si parametru formal un
pointer catre tablou, adica adresa de
inceput a acelui tablou. De asemenea se
prefera folosirea pointerului de tip void, in
cadrul functiei folosindu-se un pointer
specific catre tipul T si cu conversia
explicita catre acel tip.
24
Afisare matrice linie cu linie
• #include <stdio.h>
• #include <stddef.h>
• #define FORMAT “%6d”
•
• void afis_mat_int(void *a, int m, int n)
• {
• int *v = (int *)a;
• int mn = m*n;
• ptrdiff_t d;//definire din stddef d ca si pointer
diferenta
• while ((d=v-(int*)a) < mn) printf ((d%n == n-1) ?
FORMAT “\n” : FORMAT, *v++); 25
Declaratori complecsi
• Un declarator complex este un identificator
insotit de mai mult de un modificator de tipurile:
• -de date, []
• -pointer, *
• -functie, ()
• Aceste combinatii variate pot fi aplicate uneia si
aceleiasi variabile (identificator) cu unele
exceptii:
• -un tablou nu poate fi compus din functii
• -o functie nu poate returna o functie sau un
tablou 26
Interpretarea declaratorilor
complecsi:
• -parantezele () si [] din dreapta (functii si
tablouri) identificatorului au prioritatea mai mare
decat * din stanga identificatorului
• -parantezele () si [] au aceiasi prioritate
asocierea facandu-se de la S ->D
• -specificatorul de tip este aplicat in ultimul pas
cand declaratorul a fost complet evaluat
• -parantezele () ca si operator, se pot folosi
pentru a schimba asocierea implicita, fortand
una explicita
27
Regula interpretarii (citire din
interior spre exterior)
• 1. Se citeste identificatorul si se cauta
paranteze [] si () spre dreapta care se
interpreteaza, respectiv * spre stanga
• 2. daca se intalneste operatorul () la ori ce
nivel se revine si se aplica aceleasi reguli
pentru elementele din interiorul
parantezelor rotunde
• 3. In final se aplica specificatorul de tip
28
Exemple:
a)char * (* (*var)( ))[10];
• -var este: un pointer la
• -o functie, care returneaza
• -un pointer la
• -un tablou de 10 elemente
• -fiecare element fiind un pointer de tip char
b) int * var[5];
-var este un tablou
-de 5 pointeri de tip intreg 29
c) int (*var)[5];
-var este un pointer
-la un tablou de 5 elemente de tip int
d) long * var(int, int);
-var este o functie cu doi parametrii int
-care returneaza un pointer de tip long
30
9. Funcţii pentru lucrul cu şiruri de
caractere
31
Funcţii pentru lucrul cu şiruri de caractere
32
Funcţii pentru lucrul cu şiruri de caractere
33
Funcţii pentru lucrul cu şiruri de caractere
34
Funcţii pentru lucrul cu şiruri de caractere
35
Funcţii pentru lucrul cu şiruri de caractere
36
Funcţii pentru lucrul cu şiruri de caractere
37
Funcţii pentru lucrul cu şiruri de caractere
– Funcţiile returneaza:
• 0 dacă şirurile sunt egale
• -1 dacă s1 < s2
• 1 dacă s1 > s2
39
10. Pointeri spre funcţii
• O funcţie, ca şi un tablou, are asociată o adresă fixă de
memorie
40
Pointeri spre funcţii
• Exemplu:
char * (*pf) (char *, const char *);
41
Pointeri spre funcţii
42
Pointeri spre funcţii
• Observaţii:
– Standardul ANSI permite a scrie apelul fără a folosi
operatorul de indirectare * adică:
pf (lista_param_actuali);
sau
var = pf (lista_param_actuali);
void main(void)
{
char s1[30], s2[30];
int (*pf)(char *, char *);
pf = comp1;
...
if(test(s1, s2, pf) == 0)
printf("sirul s1 este diferit de sirul s2");
else
printf("sirul s1 este egal cu sirul s2");
} 44
Pointeri spre funcţii
#define DIM 10
void main(void)
{
int i, n, tab[DIM];
char grp;
float (*pf)(int*, int);
46
Pointeri spre funcţii
printf("\nIntroduceti %d valori de rezistente :\n", n);
for(i=0; i<n; i++) {
printf("Rezistenta %d :", i+1);
scanf("%d", &tab[i]);
}
switch(grp)
{
case 'S':
case 's': pf = serie;
break;
case 'P':
case 'p': pf = paralel;
break;
default: printf("\n Operatie invalida !");
return;
}//end switch
47
Pointeri spre funcţii
printf("\n\tRezistenta echivalenta este: %f\n", calcul (tab, n, pf));
}//end main
• Exemplu:
arj e chess.arj
49
Transferarea de argumente către funcţia main
51
Transferarea de argumente către funcţia main
52
Transferarea de argumente către funcţia main
#include <stdio.h>
#include <stdlib.h>
void main (int argc, char *argv[ ])
{
int i, suma=0, n;
if (argc == 1) {
printf("\n\n Nu aţi introdus numerele de adunat !");
exit(1);
}
else {
for(i=1; i<argc; i++) {
n = atoi(argv[i]);
suma += n;
}
printf("\nSuma argumentelor din linia de comandă este: %d", suma);
}
}
53
Transferarea de argumente către funcţia main
int main(void)
{
...
return(1);
}
54
Transferarea de argumente către funcţia main
55
12. Alocarea dinamică a memoriei
• Alocarea dinamică permite crearea, exploatarea şi
distrugerea unor obiecte în timpul execuţiei programului,
la iniţiativa programatorului
56
Alocarea dinamică
57
Alocarea dinamică
58
Alocarea dinamică C
59
Alocarea dinamică C
• Descriere:
• alocă o zonă de "nr_oct" octeţi în memoria heap, în cadrul
segmentului de date curent
• returnează un pointer generic pe 16 biţi în caz de succes sau
valoarea NULL în caz de eşec
• dimensiunea maximă a blocului alocat este de 64Ko
60
Alocarea dinamică C
• Descriere:
– alocă o zonă de "nr_elem*dim_elem" octeţi în memoria
heap, în cadrul segmentului de date curent
– iniţializează zona de memorie cu 0
– returnează un pointer generic în caz de succes sau
valoarea NULL în caz de eşec;
– dimensiunea maximă a blocului alocat este de 64Ko
– exemplu:
int *p, n=20;
...
p = (int *)calloc(n, sizeof(int));
62
Alocarea dinamică C
63
Alocarea dinamică C
64
Alocarea dinamică C
• Regulă practică:
– numărul de apeluri către funcţii de alocare (malloc( ), calloc( );
farmalloc( ), farcalloc( )) trebuie să fie egal cu numărul de apeluri
către funcţii de dealocare (free( ); farfree( )) 65
Alocarea dinamică C
void main(void)
{
int i,n, *tab=NULL;
printf("\nIntroduceti dimensiunea tabloului : ");
scanf("%d", &n);
tab = (int *)malloc(n * sizeof(int));
if(tab != NULL)
{
printf("\nIntroduceti elementele tablolului : ");
for(i=0; i<n; i++)
{
printf("\n\t elementul %d : ", i+1);
scanf("%d", tab+i);
// scanf("%d", &tab[i]);
} 67
Alocarea dinamică C
68
Alocarea dinamică C
2. Alocare tablou dinamic unidimensional exploatat ca un tablou
bidimensional
void main(void)
{
int *p, m, n, i, j;
printf("\n Dimensiuni matrice : ");
scanf("%d %d", &m, &n);
if((m <= 0) || (n <= 0)) {
printf("\nNumere invalide ! Mai incearca !");
return;
}
// dealocare
if(p)
free(p);
}
70
Alocarea dinamică C
• Concluzii la alocarea dinamică în limbajul C:
– limbajul C nu are mecanisme încorporate (operatori)
pentru alocarea dinamică
• se utilizează funcţii din biblioteca standard
– alocarea dinamică implică folosirea pointerilor
– este necesară folosirea conversiilor de tip şi a
operatorului sizeof
– pointerii obtinuţi cu funcţiile malloc( ) şi calloc( ) se vor
dealoca numai cu funcţia free( )
– se recomandă testarea pointerilor obţinuţi înainte de
folosire şi înainte de dealocare
71
Alocarea dinamică C++
• Operatorul new
– Este un operator unar şi permite alocarea dinamică în
heap
– Are ca şi valoare adresa de început a zonei de memorie
alocate (un pointer) în caz de succes sau valoarea 0 în
caz de eşec
– Obiectul alocat are durata de viaţă până la dealocare cu
operatorul delete sau până la sfârşitul programului
72
Alocarea dinamică C++
• Forme:
tip *nume_ptr = new tip;
tip *nume_ptr = new tip(expresie);
– unde:
• "tip" este un tip predefinit sau definit de utilizator
• "expresie" permite iniţializarea zonei alocate
74
Alocarea dinamică C++
• Se recomandă testarea variabilei dinamice înainte de
utilizare în raport cu valoarea 0:
int *ip;
long dim;
cout << "Dimensiune bloc : "
cin >> dim;
if((ip = new int[dim]))
{
cout << "Alocare reusita !";
exit(0);
}
else cout << "Alocare nereusita !";
...
75
Alocarea dinamică C++
• Operatorul delete
– Permite eliberarea (dealocarea) memoriei atunci când
alocarea s-a făcut cu operatorul new:
int *p;
p = new int;
...
delete p;
– In cazul tablourilor:
float *p = new double[200];
...
delete [ ]p;
void main(void)
{
int i, n, *tab;
cout << "\n Introduceti dimensiunea tabloului : ";
cin >> n;
tab = new int[n];
if(tab != 0) {
cout << "\n Introduceti elementele tabloului : ";
for(i=0;i<n;i++) {
cout << "\n\t Elementul " << i+1 << " : ";
cin >> tab[i];
}
cout << "\n\n Elementele tabloului sunt : ";
for(i=0;i<n;i++)
cout << tab[i] << "\t";
}
else
cout << "Alocare nereusita !";
if(tab)
delete [ ]tab;
}
77
Alocarea dinamică C++
// Alocarea unui tablou bidimensional (matrice)
#include <iostream.h>
void main(void)
{
int i, j, m,n, **tab;
78
Alocarea dinamică C++
for(i=0; i<m; i++)
for(j=0; j<n; j++) {
cout << "\n\t Elementul tab[" << i+1 << "][ "<<j+1<<”]:”;
cin >> tab[i][j];
}
80
13. Funcţii pentru manipularea zonelor
de memorie
Iniţializări zone de memorie
#include <mem.h>
void *memset(void *dst, int c, size_t n);
81
Funcţii pentru manipularea zonelor de memorie
82
Funcţii pentru manipularea zonelor de memorie
#include <mem.h>
void *memccpy(void *dest, const void *src, int c, size_t n);
83
Funcţii pentru manipularea zonelor de memorie
84
Funcţii pentru manipularea zonelor de memorie
85
Funcţii pentru manipularea zonelor de memorie
86
Funcţii pentru manipularea zonelor de memorie
Interschimbarea octeţilor
#include <stdlib.h>
void swab( char *src, char *dest, int n );
87
Funcţii pentru manipularea zonelor de memorie
#include <stdio.h>
#include <memory.h>
void main(void)
{
char alphabet[27] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
char target[27];
char *result;
result =(char *) memccpy(target, alphabet, 'K', sizeof(alphabet));
if (result)
*result = NULL;
printf(target);
printf("\n");
}//end main
88
Funcţii pentru manipularea zonelor de memorie
#include <stdio.h>
#include <memory.h>
void main(void)
{
char *a = "AAA";
char *b = "BBB";
char *c = "aaa";
89
Funcţii pentru manipularea zonelor de memorie
#include <stdio.h>
#include <memory.h>
#include <string.h>
void main(void)
{
float values[ ] = { 1.1, 2.2, 3.3, 4.4, 5.5 };
float empty[5];
int i;
memmove(empty, values, sizeof(values));
for (i = 0; i < 5; i++)
printf("%3.1f\t", empty[i]);
printf("\n");
}
90
Funcţii pentru manipularea zonelor de memorie
#include <stdio.h>
#include <stdlib.h>
#include <memory.h>
#include <string.h>
void main(void)
{
char *source = "Sir de initializare...";
char target[64];
memset(target, NULL, sizeof(target));
swab(source, target, strlen(source));
printf("Sursa: %s \n", source);
printf("Destinatie: %s\n", target); // iS redi initlazira.e..
}
91