agenda

13
1 Programare in limbajul C – Cursul 12 Echivalenţa dintre pointeri şi tablouri Prof. univ. dr. Constantin Popescu

Upload: melyssa-mosley

Post on 01-Jan-2016

45 views

Category:

Documents


0 download

DESCRIPTION

Programare in limbajul C – Cursul 12 Echivalenţa dintre pointeri şi tablouri Prof. univ. dr. Constantin Popescu. Agenda. S imilarităţi între tablouri şi pointeri Pointeri şi tablouri Alocarea memoriei Alocarea si e liberarea memoriei Re-alocarea blocurilor de memorie. - PowerPoint PPT Presentation

TRANSCRIPT

Page 1: Agenda

1

Programare in limbajul C – Cursul 12Echivalenţa dintre pointeri şi tablouri

Prof. univ. dr. Constantin Popescu

Page 2: Agenda

Agenda Similarităţi între tablouri şi pointeri Pointeri şi tablouri Alocarea memoriei Alocarea si eliberarea memoriei Re-alocarea blocurilor de memorie

Page 3: Agenda

Similarităţi între tablouri şi pointeri Există o serie de similarităţi în C între tablouri şi pointeri. Dacă

avem un tablouint a[10];

ne putem referi la a[i], a[1], a[2] etc. unde i este o variabilă de tip int. Dacă declarăm o variabilă pointer ip şi o facem să pointeze la începutul tabloului:

int *ip = &a[0]; ne putem referi la *ip, *(ip+1), *(ip+2) etc. sau la *(ip+i) unde i

este de tip int. Nu se poate atribui un tablou altuia; urmatoarea secvenţa de

cod nu este permisă:int a[10], b[10];a = b; /* GREŞIT */

În schimb asignarea unui pointer altuia este permisă:int *ip1, *ip2;ip1 = &a[0];ip2 = ip1;

Page 4: Agenda

Similarităţi între tablouri şi pointeri Dacă scriem:

ip[3] este ca şi cum am fi scris:

*(ip + 3) De exemplu, dacă tabloul de caractere

char string[100]; conţine un şir de caractere, pentru a afla lungimea acestui şir putem

folosi funcţia:int mystrlen(char *string){ int len; char *p; for(p = string; *p != '\0'; p++) ; /* După terminarea instrucţiunii for, p pointează la caracterul '\0' */ len = p - string; /* Expresia p-string este echiv. cu p-&string[0] */ return len;}

Page 5: Agenda

Tablouri şi pointeri ca argumente ale funcţiilor#include <stddef.h>#include <ctype.h>int getwords(char *line, char *words[],

int maxwords) {char *p = line;int nwords = 0;while(1) { while(isspace(*p))

p++; if(*p == '\0') return nwords;

words[nwords++] = p; while(!isspace(*p) && *p != '\0')

p++; if(*p == '\0') return nwords; *p++ = '\0'; if(nwords >= maxwords)

return nwords;}

}

Mai jos dăm o secvenţă completă de apel a funcţiei getwords:

...

char line[]="acesta este un test";

int i;

nwords=getwords(line,words,10);

for(i = 0; i < nwords; i++)

printf("%s\n", words[i]);

...

Page 6: Agenda

Alocarea memoriei Când alocăm memorie dinamic folosind malloc trebuie să

manifestăm multă precauţie întrucât aceasta este o funcţie de "nivel jos".

Problema este că dacă atribuim o valoare unei locaţii pointate de un pointer, de ex.:

*p = 0; şi dacă pointerul p nu pointează "nicăieri" (de fapt el va pointa

ceva dar nu ceea ce vrem noi), zeroul este scris în locul acelui "ceva".

Dacă acel "ceva" este o zonă de memorie utilizată de program sau, mai rău, dacă sistemul de operare utilizează acel "ceva" şi sistemul de operare nu are protecţie împotriva unor astfel de instrucţiuni, atunci putem asista la un comportament "ciudat" din partea sistemului pe care îl folosim, putând ajunge până la imposibilitatea de a-l utiliza şi necesitatea repornirii acestuia.

Page 7: Agenda

Alocarea memoriei cu malloc (1) Iată un prim exemplu:

#include <stdlib.h>. . .

char *line;

int linelen = 100;

line = malloc(linelen);

/* incomplet -- valoare de return a functiei malloc nu este testata*/

getline(line, linelen); Funcţia malloc este declarată în fişierul stdlib.h, aşa că acest

fişier header trebuie inclus în orice program care apelează funcţia malloc.

Un "octet" este în C, prin definiţie, o cantitate de memorie necesară pentru stocarea unui caracter

Apelul funcţiei malloc de mai sus ne va da exact atâtea caractere câte am cerut.

Page 8: Agenda

Alocarea memoriei cu malloc (2) Putem ilustra pointerul care rezultă prin:

Ca un al doilea exemplu, am putea fi puşi în situaţia de a aloca o zonă de memorie şi să copiem un şir de caractere în acea zonă de memorie cu funcţia strcpy:

char *p = malloc(15);

/* incomplet - valoare de return a functiei malloc nu este testata */

strcpy(p, "Hello, world!"); Când copiem şiruri de caractere e important să ţinem cont de

faptul că acestea se termină cu caracterul '\0'.

Page 9: Agenda

Alocarea memoriei cu malloc (3) Dacă folosim funcţia strlen pentru a număra caracterele dintr-un

şir, numărul nu va conţine şi caracterul '\0', aşa că va trebui să-l adăugăm noi înainte de apela funcţia malloc:char *unstring, *copy;...copy = malloc(strlen(unstring) + 1); /* +1 pentru \0 *//* incomplet - valoare de return a functiei malloc nu este testata */strcpy(copy, unstring);

Pentru a aloca spaţiu pentru 100 de întregi, putem scrie:int *ip = malloc(100 * sizeof(int));

Utilizarea operatorului sizeof seamănă cu un apel de funcţie, dar în realitate el este un operator, care îşi face datoria în timpul compilării.

După apelul de mai sus al funcţiei malloc, ip este iniţializat pentru a pointa la o zonă de memorie ce poate stoca 100 de întregi, ce pot fi accesaţi prin ip[0], ip[1], ip[2], … , ip[99].

Page 10: Agenda

Alocarea si eliberarea memoriei Un apel la malloc, cu verificarea erorilor, se scrie de obicei sub

forma:int *ip = malloc(100 * sizeof(int));if(ip == NULL){

printf("memoria insuficienta\n");exit sau return

} După afişarea mesajelor de eroare, codul de mai sus trebuie să

redea controlul funcţiei apelante sau să oprească execuţia programului.

Dacă p conţine un pointer la o zonă de memorie obţinută prin apelul funcţiei malloc, aceasta poate fi eliberată prin apelul:

free(p); După apelul

free(p); Pointerul p pointează la o anumită zonă de memorie.

Page 11: Agenda

Exemplu alocare-dealocare memorie/* Functia care determina toate

numerele prime ce sunt mai mici decit m */

void print_prime( int m ){

int i,j;char * ary = malloc( m );if (ary == NULL)

return -1;for( i = 0; i < m; i++ )

ary[i]=1;ary[0] = ary[1] = 0;ary[2] = 1;

for( i = 3;i < m; i++ ) {

for( j = 2; j < i; j++)

if(ary[ j ] && i%j == 0){

ary[j] = 0;

break;

}

}

for(i = 0; i < m; i++)

if( ary[i] )

printf(“%d “, i);

free( ary );

}

Page 12: Agenda

Re-alocarea blocurilor de memorie (1) Dacă am alocat memorie pentru 100 de elemente şi utilizatorul a

introdus 101 ar fi de dorit să putem reţine cele 100 de elemente şi să alocăm memorie suplimentară pentru încă 100.

Aceasta se poate face cu funcţia realloc. Funcţia realloc primeşte vechiul pointer (cel obţinut pin apelul iniţial al

funcţiei malloc) şi noua dimensiune şi va face tot posibilul pt. a returna o zonă de memorie suficient de mare pentru a satisface noile cerinţe.

De exemplu, dacă vrem ca variabila ip din exemplul precedent să pointeze la 200 de întregi în loc de 100, putem apela funcţia:

ip = realloc(ip, 200 * sizeof(int)); Putem folosi o secvenţă ca cea de mai jos:

int *newp;newp = realloc(ip, 200 * sizeof(int));if(newp != NULL)

ip = newp;else {

printf("memorie insuficienta\n");/* exit sau return *//* ip pointeaza in continuare la 100 de intregi */

}

Page 13: Agenda

Re-alocarea blocurilor de memorie (2) Secvenţa de cod care citeşte

linii de text de la utilizator, fiecare linie va fi interpretată ca un număr prin apelarea funcţiei atoi, şi întregii vor fi stocaţi într-un "tablou" alocat dinamic.

#define MAXLINE 100char line[MAXLINE];int *ip;int nalloc, nitems;nalloc = 100;ip = malloc(nalloc * sizeof(int));

/* alocarea initiala */if(ip == NULL) {

printf("memorie insuficienta\n");exit(1);

}nitems = 0;

while(getline(line, MAXLINE) != EOF) {if(nitems >= nalloc){ /* facem o realocare */ int *newp; nalloc += 100; newp = realloc(ip, nalloc *

sizeof(int)); if(newp == NULL) {

printf("memorie insuf.\n"); exit(1); } ip = newp;}ip[nitems++] = atoi(line);

}