Documente Academic
Documente Profesional
Documente Cultură
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
De asemenea:
&ftab[0] este identic cu ftab
ftab[0] *ftab
&ftab[i] ftab+i
ftab[i] *(ftab+i)
iar expresia: (&ftab[i] - ftab) are întotdeauna valoarea i
4
TABLOURI ŞI POINTERI
Indexarea unui pointer asemenea unui tablou are sens
doar dacă referă un tablou:
int main(void){
const char *p; //pointer aritmetic catre un sir const
int i;
p = str; // atribuire pointeri
for(i=0; p[i]; i++)
printf("%c",p[i]);
}
pentru p[i]
TABLOURI ŞI POINTERI
6
TABLOURI ŞI POINTERI
7
ORGANIZAREA IN MEMORIE A UNUI TABLOU
Un tablou este definit in memorie prin:
- numele tabloului, ce are ca valoare adresa primului
element din tablou
- elementele tabloului memorate în mod contiguu
- se rezervă o zonă de dimensiunea unui element după
ultimul element efectiv din tablou
Exemplu:
int varsta[ ] = {18,19,20,5,10};
varsta[0] = *varsta = 18
varsta[1] = *(varsta+1) = (varsta +1)[0] = 19
8
varsta[2] = *(varsta+2) = (varsta +1)[1] =
(varsta +2)[0] =20
varsta[3] = *(varsta+3) = (varsta +1)[2] = (varsta+2)[1]
= (varsta+3)[0] = 5
varsta[4] = *(varsta+4) = (varsta +1)[3] = (varsta+2)[2]
= (varsta+3)[1] = (varsta+4)[0] = 10
9
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;
10
TABLOURI ŞI POINTERI
Tablourile de pointeri se folosesc mai ales la crearea de
tabele de şiruri de caractere care pot fi selectate in
funcţie de anumite valori
Exemplu:
11
TABLOURI ŞI POINTERI
char *a[5];
char **p; // pointer (dublu) catre caractere
p = a;
12
Exemplu:
Fie 10 șiruri de caractere ale căror adrese se află într-un
tablou de pointeri char *sir[10] și construim o funcție care
afișează aceste șiruri de caractere la un apel. Acest lucru îl
putem realiza în două moduri:
-primul mod, cu tablouri de pointeri;
-al doilea, cu pointeri dubli
13
A) TABLOURI DE POINTERI
#include <iostream>
using namespace std;
void afis1_sir(char *tp[ ], int n);
const char *sir[10]={"a", "b", "c", "d", "e",
"f", "g", "h", "i", "j" };
int main(){
afis1_sir(sir,10);
return 0;
}
14
void afis1_sir(const char *tp[], int n)
{
int i;
for(i=0; i < n; i++)
if (tp[i] != NULL) //if (tp[i])
printf("%s\n", tp[i]);
}//afis1_sir
15
B) POINTERI DUBLI
void afis2_sir(const char **tp, int n)
{
char *p;
while (n--){
p=*tp;
while (*p)
putchar( *p++); //caracterul urmator
putchar(‘\n’);
tp++; // trecerea la un nou sir de caract.
}//while
}//afis2_sir
16
TABLOURI ŞI POINTERI
Pointeri către şiruri de caractere:
int main(void){
const char *p1;
p1 = "unu doi trei";
printf("%s", p1);
return 0;
}
17
TABLOURI ŞI POINTERI
/* valoarea minima dintr-un tablou de numere intregi*/
#include <stdio.h>
#define DIM 20
int DetMin(int *x, int dim);
int main(void){
int i, dim, min;
int x[DIM];
printf("\nIntroduceti dimensiunea tabloului (<=20): ");
scanf("%d", &dim);
if(dim<0 || dim > DIM)
printf("\n Dimensiune prea mare sau negativa !\n");
return 1;
}
printf("\n Introduceti elementele tabloului:\n");
18
TABLOURI ŞI POINTERI
for(i=0; i<dim; i++) {
printf("\tx[%d] = ", i);
scanf("%d", (x+i));
}
min = DetMin(x, dim);
printf("\n Cel mai mic element din tablou este:
%d\n", min);
return 0;
}//main
Exemplu:
int (*p)[10]; //p este un pointer spre un tablou de 10
întregi cu unitatea 10*sizeof(int)
int(*p)[3];
int tab[3][3] = { { 1,2,3 }, { 4, 5,6 }, {7,8,9} };
p = &tab[0]; // *p[0]=1, *p[1]=4, *p[2]=7
21
Fie un tablou a de tip T și dimensiuni: d1, d2, …, dn:
T a[d1][d2]…[dn];
și presupunem indicii: i1, i2, …, in astfel încât
0 <= ik <= dk-1, unde k ia valori între 1 și n.
22
Notând cu d și i multiindicii:
d = (d1, d2, …, dn)
i = (i1, i2, …, in), și cu
T tipul de bază al tabloului,
atunci funcția de alocare a memoriei pentru un tablou
oarecare a se notează cu:
fd, T (i, a)
adică adresa elementului i al tabloului a de tipul T și
multiindici d este dată în limbajul C prin:
23
fd, T (i,a) = baza (a) + sizeof(T) *[ i1d2d3…dn +
i2d3d4…dn +
i3d4d5…dn +…+
in-1dn +
in
]
24
Observații:
Funcția de alocare nu depinde de prima dimensiune, d1,
de aceea uneori putem să o ignorăm
La tablourile unidimensionale (T a[M]) funcția de alocare
nu depinde de M:
&a[i] este egala cu: baza(a) + sizeof (T) * i
Un tablou cu mai multe dimensiuni este tratat de către
compilator ca un tablou cu o dimensiune (și anume prima),
care are ca elemente un tablou cu restul de dimensiuni, deci
nu există limitări sintactice ale numărului de dimensiuni în C.
La un tablou bidimensional, T a[M][N], funcţia de alocare nu
depinde de M:
&a[i][j] este egala cu: baza(a) + sizeof (T) * [ i * N + j ]
25
În cazul transmiterii către o funcție a unui tablou cu mai
multe dimensiuni, este de preferat să folosim ca
parametru formal un pointer către tablou, adică adresa
de început a acelui tablou.
26
AFIŞARE MATRICE LINIE CU LINIE
#include <stdio.h>
#include <stddef.h>
#define FORMAT "%6d"
27
DECLARATORI COMPLECȘI
Un declarator complex este un identificator însoțit de mai
mult de un modificator de genul:
-de date, [ ]
-pointer, *
-functie, ( )
Aceste combinații variate pot fi aplicate uneia și aceleiași
variabile (identificator) cu unele excepții:
-un tablou nu poate fi compus din funcții
-o funcție nu poate returna o funcție sau un tablou
28
INTERPRETAREA DECLARATORILOR COMPLECSI
29
REGULA INTERPRETĂRII (CITIRE DIN INTERIOR SPRE
EXTERIOR)
30
EXEMPLE:
a) int * var[5];
-var este un tablou
-de 5 pointeri de tip intreg
b) int (*var)[5];
-var este un pointer
-la un tablou de 5 elemente de tip int
31
c) long * var(int, int);
-var este o funcție cu doi parametri int
-care returnează un pointer de tip long
33
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
34
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
#include <iostream>
using namespace std;
#include <regex>
int main() {
//versiunea C
printf("\nGets: ");
char buf[20];
char *adr = gets_s(buf, _countof(buf));
printf(buf);
printf("\nAdr. init %p Adr. ret: %p", buf, adr);
double d_var;
printf("\nIntoduceti o valoare reala: ");
scanf_s("%lf", &d_var);
printf("\nValoarea reala este: %lf \n", d_var);
/* printf("\nIntroduceti sir nou: ");
char *aadr = gets_s(buf, _countof(buf));
printf(buf); 36
printf("\nAdr. init %p Adr. ret: %p", buf, aadr);*/
// versiunea C++
cout << "\n C++ - Introduceti numele si prenumele
studentului: ";
cin.ignore();
cin.getline(buf, 30);
regex pattern(" ");
//verifica separare nume prenume cu spatiu
while (!regex_search(buf, pattern)){
cout << "\nNu ati introdus corect!!";
cin.getline(buf, 30);
}
cout<<"\nIntroduceti o valoare double: ";
cin>>d_var;
cout<<"\n Studentul este: " << buf<< "\t Valoarea
double e: " << d_var<<endl; 37
cout << "\n\nIntroduceti inca o data numele si
prenumele studentului (nu se valideaza
spatiu intre nume si prenume): ";
cin.ignore();
cin.getline(buf, 30);
38
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
39
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
40
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
41
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
42
FUNCŢII PENTRU LUCRUL CU ŞIRURI DE CARACTERE
44
10. POINTERI SPRE FUNCŢII
45
POINTERI SPRE FUNCŢII
Exemplu:
char * (*pf) (char *, const char *);
46
POINTERI SPRE FUNCŢII
47
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);
48
POINTERI SPRE FUNCŢII
49
POINTERI SPRE FUNCŢII
int test(char*, char*, int (*)(char*, char*));
int comp1(char *, char *);
int comp2(char *, char *);
int main(void){
char s1[30], s2[30];
int (*pf)(char *, char *);
pf = comp1;
...
if ( test(s1, s2, pf) == 0 )
printf("sirul s1 este egal cu sirul s2");
else
printf("sirul s1 este diferit de sirul s2");
return 0;
50
}
int test(char *a, char *b, int (*cmp)(char *, char*)){
if(!(*cmp)(a,b))
return(0);
else
return(1);
}
#include <stdio.h>
#include <conio.h>
#define DIM 10
int main(void){
int i, n, tab[DIM];
char grp;
float (*pf)(int*, int);
54
float serie(int *tab, int n) {
float suma = 0;
while(n)
suma += tab[--n];
return(suma);
}//end serie
55
11. TRANSFERUL DE ARGUMENTE CĂTRE
FUNCŢIA MAIN
Exemplu:
arj e chess.arj
56
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
Introducerea de argumente în linia de comandă, se face
prin definirea unor parametri pentru funcţia main( ):
int main(<int argc, char *argv[ ]> <,char *env[ ]>)
{ ... }
argc, conţine numărul argumentelor ( >= 1)
argv, este un tablou de pointeri către şiruri de
caractere, unde:
argv[0] pointează pe un şir de caractere cu numele şi
calea programului care se lansează în execuţie
argv[1] pointează pe un şir de caractere cu primul
argument, ş.a.m.d.
env, este un tablou de pointeri către şiruri de
caractere care reprezintă o listă de parametri ai SO
57
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
58
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
int main(void)
{
...
return (0);
}
59
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
60
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
#include <stdio.h>
#include <stdlib.h>
int 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;
} // for
printf("\nSuma argumentelor din linia de comandă este: %d", suma);
} // else
return 0; } /main
61
TRANSFERUL DE ARGUMENTE CĂTRE FUNCŢIA MAIN
62
12. ALOCAREA DINAMICĂ A MEMORIEI
64
HEAP – ce este?
• zona de memorie e controlată de programator
• structură arborescentă
• nu are restricții la dimensiunea memoriei
• accesul la variabile se face mai lent și neapărat prin pointeri
• variabilele stocate pe heap pot fi accesate din orice regiune
a programului
Stiva
• stochează variabile temporare create de fiecare funcție
(inclusiv main())
• structură LIFO (last in first out)
• la ieșirea din funcție, toate variabilele sunt șterse din stivă
• memoria este controlată automat de compilator
• are dimensiuni reduse
65
• acces rapid la variabile
ALOCAREA DINAMICĂ
66
ALOCAREA DINAMICĂ C
67
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 în caz de succes sau
valoarea NULL în caz de eşec
dimensiunea maximă a blocului alocat este de 64Ko
68
ALOCAREA DINAMICĂ C
69
Se recomandă testarea pointerului obţinut înainte
de folosire:
70
ALOCAREA DINAMICĂ C
void * calloc(unsigned nr_elem, unsigned dim_elem);
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;
exemplu:
int *p, n=20;
...
p = (int *)calloc(n, sizeof(int));
71
ALOCAREA DINAMICĂ C
72
ALOCAREA DINAMICĂ C
int main(void){
int i,n, *tab=NULL;
printf("\nIntroduceti dimensiunea tabloului : ");
scanf_s("%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_s("%d", tab+i);
// scanf_s("%d", &tab[i]);
} 75
ALOCAREA DINAMICĂ C
79
ALOCAREA DINAMICĂ C++
Operatorul new
Este un operator unar şi permite alocarea dinamică în
heap
Are ca 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
80
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
82
ALOCAREA DINAMICĂ C++
int *ip;
long dim;
cout << "Dimensiune bloc : "
cin >> dim;
if((ip = new int[dim]))
{
cout << "Alocare reusita !";
exit(0);
}
else cout << "Alocare nereusita !"; 83
...
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:
double *p = new double[200];
...
delete [ ]p;
#include <iostream>
using namespace std;
int 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]; 85
}
ALOCAREA DINAMICĂ C++
86
ALOCAREA DINAMICĂ C++
// Alocarea unui tablou bidimensional (matrice)
#include <iostream>
using namespace std;
int main(void)
{
int i, j, m,n, **tab;
88
ALOCAREA DINAMICĂ C++
for(i=0; i<m; i++) {
for(j=0; j<n; j++)
cout << tab[i][j]<<"\t";
cout << “\n”;
}
}
else
cout << "Alocare nereusita !";
if(tab) {
for(i=0; i<m; i++)
delete [ ] tab[i];
delete [ ] tab;
}
return 0;
}
89
ALOCAREA DINAMICĂ C++
90
13. FUNCŢII PENTRU MANIPULAREA ZONELOR DE
MEMORIE
91
TIPUL DE DATE SIZE_T – ce este?
• size_t • tip de date alias pentru unsigned integer •
returnat de operatorul sizeof
• utilizat de obicei în expresii ce se referă la
dimensiunea unui obiect
• disponibil în C: <stddef.h> <stdio.h> <stdlib.h>
<string.h> <time.h> <uchar.h> <wchar.h>
• disponibil în C++: <cstddef> <cstdio> <cstdlib>
<cstring> <ctime> <cwchar>
92
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
93
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
95
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
97
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
Interschimbarea octeţilor
#include <stdlib.h>
void _swab( char *src, char *dest, int n );
98
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
#include <stdio.h>
#include <string.h>
int 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");
return 0;
}//end main
99
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
#include <stdio.h>
#include <memory.h>
int main(void){
const char *a = "AAA";
const char *b = "BBB";
const char *c = "aaa";
#include <stdio.h>
#include <string.h>
int 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");
return 0;
}
101
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[] = "ABCDEFG";
char *ps = (char *) memchr(str,'D',strlen(str));
if (ps != NULL)
printf ("Caracterul cautat a fost gasit: %s\n", ps);
else
printf ("Caracterul cautat nu a fost gasit\n");
return 0;
}
102
FUNCŢII PENTRU MANIPULAREA ZONELOR DE MEMORIE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int 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..
return 0;
}
103
Ce știm după acest curs…
Tablouri și pointeri. Legături, accesul la elementele tabloului prin
intermediul pointerilor (indexare, operatori +, -, ++, --), respectiv
prin numele tabloului și operatorii ‘+’, ‘-’.
Tablouri de pointeri. Utilizare.
Alocarea în memorie a tablourilor. Funcția de alocare a memoriei
pentru un tablou (independența de prima dimensiune).
Declaratori complecși. Reguli de interpretare.
Funcții pentru lucrul cu șiruri de caractere.
Pointeri către funcții. Declarare, utilizare.
Argumentele funcției main()
Alocarea dinamică a memoriei în C
Alocarea dinamică a memoriei în C++
Funcții pentru manipularea zonelor de memorie
104
105