Sunteți pe pagina 1din 18

PCLP.

Laborator 10: Pointeri și tablouri (Cursul 8)

Pentru a atribui variabilei p de tip pointer valoarea adresei variabilei x se foloseşte operatorul de adresă &:
p = &x;

În urma acestei operaţii pointerul p indică spre variabila x.


Pentru a obţine valoarea obiectului indicat de un pointer se utilizează operatorul de dereferenţiere sau de
indirectare: *. Dacă p este o variabilă de tip pointer care are ca valoare adresa locaţiei de memorie a variabilei
întregi x, p indică spre x atunci expresia *p reprezintă o valoare întreagă: valoarea variabilei x.
Orice operaţie care poate fi realizată cu ajutorul indicilor tablourilor poate fi efectuată cu ajutorul pointerilor.
Declaraţia
int a[10];

defineşte un tablou de dimensiune 10, adică un bloc de 10 elemente consecutive notate


a[0], a[1], ..., a[9].
Dacă pa este un pointer spre un întreg, declarat:
int *pa;
atunci atribuirea
pa = &a[0];
îl setează pe pa să indice spre elementul zero al lui a. pa conţine adresa lui a[0] sau adresa tabloului a.
Instrucţiunea x = *pa; va copia conţinutul lui a[0] în x.
Dacă pa indică spre un anumit element de tablou pa + 1 indică spre
următorul element, pa + i indică spre o locaţie aflată la i elemente
după pa, pa – i indică spre o locaţie aflată cu i elemente înainte.
pa = &a[0]; poate fi scrisă astfel: pa = a;
O referinţă la a[i] poate fi scrisă şi ca *(a + i), cele două forme sunt echivalente. Aplicând operatorul &
ambelor părţi ale echivalenţei, rezultă că &a[i] şi a + i sunt forme identice. Dacă pa este un pointer:
pa[i] este identic cu *(pa + i).

Aplicaţie propusă 1. Funcția f de mai jos returnează lungimea unui șir de caractere, furnizat funcției prin
argumentul de tip pointer către char: s. Scrieți un program complet în care să integrați funcția.
/* f: returneaza lungimea sirului s */
int f(char *s) {
int n;
for (n = 0; *s !=‘\0’; s++)
n++;
return n;
}

Aplicaţie propusă 2. Funcția f de mai jos returnează lungimea unui șir de caractere, furnizat funcției prin
argumentul de tip pointer către char: s. Scrieți un program complet în care să integrați funcția.
/* f: returneaza lungimea sirului s */
int f(char *s)
{
char *p = s;/* initializare cu adresa sirului*/

while (*p != '\0')


p++;

return p - s; /* returneaza nr de caractere parcurse */


}
Aplicaţie propusă 3. Scrieţi un program care conţine codul de mai jos:
int x, *p;
x = 3;
p = &x;
printf("%d\n", *p); /* valoarea obiectului indicat de p: valoarea lui x. Afişeaza 3 */
*p = 5; /* modifică valoarea obiectului indicat de p, adică valoarea lui x. */
1
printf("%d", x); /* afișează 5 */

Aplicaţie rezolvată 1. Se citesc N numere întregi şi se memorează în şirul t1. Se construiește apoi şirul t2 cu
elementele lui t1 în ordine inversă.
#include <stdio.h>

#define N 5

int main (void)


{
int t1[N], t2[N]; int i;
/* citeste elementele sirului t1 */
printf(“Introdu %d elemente sir \n”, N);
for (i = 0; i < N; i++)
scanf(“%d”, &t1[i]);

/* construieste t2 */
for (i = 0; i < N; i++)
t2[i] = t1[N – 1 - i];

/* afiseaza elementele sirului t2 */


printf(“Sirul in ordine inversa este: \n”);
for(i = 0; i < N; i++)
printf(“%d ”, t2[i]);
printf(“\n”);

return 0;
}

Aplicaţie rezolvată 2. Folosind patru variante - pe bază de pointeri - pentru o funcției de afișare a elementelor
unui tablou unidimensional de numere reale, să se afișeze un tablou ale cărui elemente se citesc.
#include <stdio.h>

void afisare1(float v[],int n);


void afisare2(float *v, int n);
void afisare3(float *v, int n);
void afisare4(float *v, int n);

main()
{
float a[10];
int i, n;

printf("nr elemente din sir: "); scanf("%d", &n);


for ( i = 0; i < n; i++){
printf("element[%d] = ", i);
scanf("%f", &a[i]);
}
printf("\ncu prima functie sirul este:\n"); afisare1(a, n);
printf("\ncu a 2-a functie sirul este:\n"); afisare2(a, n);
printf("\ncu a 3-a functie sirul este:\n"); afisare3(a, n);
printf("\ncu a 4-a functie sirul este:\n"); afisare4(a, n);
}

/* 4 functii de afisare tablou v folosind pointeri */


void afisare1(float v[],int n) {
float *p;
for (p = v; p < v + n; p++)
printf("%7.2f", *p);
}

void afisare2(float *v, int n) {


float *p;
for (p = v; p < v + n; p++)
printf("%7.2f", *p);
}
2
void afisare3(float *v, int n) {
int i;
for (i = 0; i < n; i++, v++)
printf("%7.2f", *v);
}

void afisare4(float *v, int n){


for (; n--; v++)
printf("%7.2f", *v);
}

Aplicaţie rezolvată 3. Folosind o funcție pentru afișarea elementelor unui tablou unidimensional (vector, șir)
de numere reale, se afișeze:
- toate elementele șirului,
- elementele șirului începând cu o anumită poziție din șir până la final și
- un număr precizat din elementele șirului începând de la o poziție precizată.

#include <stdio.h>

void afisare(float *a, int n);

main()
{
float a[10];
int i, n, l;

printf("nr elemente din sir: "); scanf("%d", &n);


for ( i = 0; i < n; i++){
printf("element[%d] = ", i);
scanf("%f", &a[i]);
}
printf("\nsirul citit este:\n");
afisare(a, n);

printf("\n\npozitia din care se doreste afisat sirul: "); scanf("%d", &i);


afisare(a + i, n - i); /* n - i: cate elemente trebuie afisate */
/* a + i: pozitia din care incepe afisarea */

printf("\n\npozitia din care incepe afisarea: "); scanf("%d", &i);


printf("cate pozitii se afiseaza: "); scanf("%d", &l);
afisare(a + i, l);
}

/* f: afiseaza n elemente ale sirului a */


void afisare(float *a, int n)
{
for(; n; n--)
printf("%8.2f ", *(a++) );
3
}

Aplicaţie propusă 4. Folosind codul de mai jos citiţi şi afişaţi elemente unei matrici de numere reale cu N linii
şi M coloane.
/* citire matrice */
printf("Introduceti elementele matricii: \n");
for(i = 0; i < N; i++)
for(j = 0; j < M; j++){
printf("element[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
/* afisare matrice */
for(i = 0; i < N; i++) {
for(j = 0; j < M; j++)
printf("%8.2f", a[i][j]);
printf("\n");
}

Aplicaţie rezolvată 4. Folosind codul de mai jos să se calculeze suma elementelor de sub diagonala
principală a unei matrici pătrate cu n (n ≤ 20) linii şi coloane.
/* suma elementelor de sub diagonala principală a unei matrici pătrate */
#include <stdio.h>

main(void)
{
int a[20][20];
int suma, i, j, n;

printf("Dimensiunea matricii (<=20):");


scanf("%d", &n);

/* citirea elementelor matricii */


for ( i = 0; i < n; i++ )
for ( j = 0; j < n; j++ ) {
printf("a[%d][%d] = ", i + 1, j + 1);
scanf("%d", &a[i][j]);
}

/* afisare matrice */
for ( i = 0; i < n; i++ ) {
for ( j = 0; j < n; j++ )
printf("%5d", a[i][j]);
printf("\n");
}

/* calculul si afisarea sumei */


for ( i = 0, suma = 0; i < n; i++ )
for( j = 0; j< i; j++ )
suma += a[i][j ];

printf("Suma: %d\n", suma);


}

Aplicaţie rezolvată 5. Scrieți un program care calculează suma și diferența a două matrici de numere reale.
#include <stdio.h>

int n, m;

void citire(float x[10][10]);


void sum(float x[10][10], float y[10][10], float s[10][10]);
void dif(float x[10][10], float y[10][10], float d[10][10]);
void tiparire(float x[10][10]);

int main()
{
4
float a[10][10], b[10][10], suma[10][10], diferenta[10][10];

printf("dimensiuni matrici:\n");
printf("numar linii = "); scanf("%d", &n);
printf("numar coloane = "); scanf("%d", &m);

/* Citirea matricilor */
printf("\nelemente matrice a \n\n");
citire(a);
printf("\nelementele matrice b \n\n");
citire(b);

/* Tiparirea matricilor */
printf("\nMatricea a este :\n");
tiparire(a);
printf("\nMatricea b este :\n");
tiparire(b);

/* Calcul si afisare matrici suma si diferenta */


sum(a, b, suma);
printf("\nMatricea suma :\n");
tiparire(suma);
dif(a, b, diferenta);
printf("\nMatricea diferenta :\n");
tiparire(diferenta);

return 0;
}

void citire (float x[10][10])


{
int i, j;

printf("Introduceti elementele matricii:\n");


for(i = 0; i < n; i++)
for(j = 0; j < m; j++){
printf("element[%d][%d] = ", i + 1, j + 1);
scanf("%f", &x[i][j]);
}
}

void sum(float x[10][10], float y[10][10], float


s[10][10])
{
int i, j;

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


for ( j = 0; j < m; j++ )
s[i][j] = x[i][j] + y[i][j];
}

void dif(float x[10][10], float y[10][10], float d[10][10])


{
int i, j;

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


for ( j = 0; j < m; j++ )
d[i][j] = x[i][j] - y[i][j];
}

void tiparire(float x[10][10])


{
int i, j;

for ( i = 0; i < n; i++ ) {


for ( j = 0; j < m; j++ )
printf("%10.2f", x[i][j]);
printf("\n");

5
}
}

TABLOURI DE POINTERI

Putem organiza pointerii în tablouri de pointeri.


int *b[10]; /* declara un tablou de pointeri de tip int de 10 elemente */
int x = 12;
b[3] = &x; /* atribuie adresa variabilei x de tip int celui de-al patrulea element din
tablou */
printf(”%d”, *b[3]); /* afiseaza valoarea lui x: 12 */

Putem memora în fiecare element al lui b adresa unui tablou unidimensional, nu doar a unei variabile int ca în
aplicația de mai jos:

Aplicație rezolvată 6. Scrieți un program care memorează adresele a trei vectori într-un vector de pointeri.
Afișarea celor trei vectori se face în trei moduri diferite:
/* tablou de pointeri la tablouri */
#include <stdio.h>

main()
{
int *b[10], i, j;
int x[3] = {1, 2, 3}, y[3] = {4, 5, 6}, z[3] = {7, 8, 9};

b[0] = x;
b[1] = y;
b[2] = z;

printf("afisarea celor trei vectori se face in trei moduri diferite\n");


for(i = 0; i < 3; ++i) {
for(j = 0; j < 3; ++j)
printf("%d ", *(b[i] + j) );
printf("\n");
}
printf("\n");

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


for(j = 0; j < 3; ++j)
printf("%d ", *(*(b + i) + j) );
printf("\n");
}
printf("\n");

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


for(j = 0; j < 3; ++j)
printf("%d ", b[i][j]);
printf("\n");
}

Aplicaţie rezolvată 7. Scrieți un program care folosind funcția zi(z), care returnează un pointer la un şir de
caractere ce conține numele celei de a z-a zi din săptămână, citește un număr natural între 1 și 7 și afișează ziua
corespunzătoare din săptămână. Programul să aibă prevăzută posibilitatea ca în cazul furnizării unui număr în
afara intervalului 1..7, să afișeze un mesaj: “eroare zi!”.
#include <stdio.h>

char *zi(int z);

main()
{
int nr;

6
printf("introduceti numarul unei zile din saptamana(1..7): "); scanf("%d", &nr);
printf("\nziua %d din saptamana este : %s\n", nr, zi(nr) );
}

char *zi(int z)
{
static char *s[] = {"eroare zi din saptamana!", "luni", "marti", "miercuri", "joi",
"vineri", "sambata", "duminica"};

return (z < 1 || z > 7) ? s[0] : s[z];


}

Aplicație propusă 5. Funcția luna(l) furnizată mai jos folosește un tablou de pointeri la char (char *p[])
pentru a memora lunile anului. Folosind funcția luna(l), care returnează un pointer la un şir de caractere ce
conține numele celei de a n-a luni, construiți un program care citind un număr natural între 1 și 12 afișează luna
corespunzătoare din an. Programul are prevăzută și posibilitatea ca în cazul furnizării unui număr în afara
intervalului 1..12 să afișeze un mesaj: “eroare luna!”.
char *luna(int l)
{
static char *p[] = {“eroare luna!”, “ian”, “feb”, “mar”, “apr”,
“mai”, “iun”, “iul”, “aug”, “sep”, “oct”, “nov”, “dec” };

return (l < 1 || l > 12) ? p[0] : p[l];


}

Aplicație propusă 6. Funcția luna(l) furnizată mai jos folosește o matrice care pe fiecare linie memorează un
șir de caractere corespunzând unei luni a anului. Folosind funcția luna(l) de mai jos, care returnează un
pointer la un şir de caractere ce conține numele celei de a n-a luni, construiți un program care citind un număr
natural între 1 și 12 afișează luna corespunzătoare din an. Programul are prevăzută și posibilitatea ca în cazul
furnizării unui număr în afara intervalului 1..12 să afișeze un mesaj: “eroare luna!”.
Observație: Dacă în aplicația anterioară am folosit un vector de pointeri pentru a memora mesajul de eroare și
numele celor 12 luni (vezi figura de mai sus), de data aceasta folosim un tablou bidimensional (matrice).
Dezavantajul acestei variante în raport cu cea
anterioară care în loc de matrice folosea un vector de
pointeri este dat de pierderea spațiului de memorie,
care este același (17 octeți) chiar dacă numele oricărei
luni este redus la 3 caractere (3 octeți) (vezi figura din
dreapta).
char *luna(int l)
{
static char a[][17] = {"eroare luna!", "ian", "feb", "mar", "apr", "mai", "iun", "iul",
"aug", "sep", "oct", "nov", "dec" };

return (l < 1 || l > 12) ? a[0] : a[l];


}

Aplicație rezolvată 8. Folosind pe rând câte una din variantele de funcție strcpy de mai jos scrieți un program
care citește un șir de caractere, îl atribuie altui șir pe care apoi îl afișează.

VARIANTA 1
#include <stdio.h>

void strcpy(char *s, char *t);

main()
{
char s1[10], s2[10], c;
int i;

printf("introduceti un sir: ");

7
i = 0;
while ((c = getchar()) != '\n')
s1[i++] = c;
s1[i]='\0';

printf("sirul citit = %s\n",s1);


strcpy(s2,s1);

printf("sirul copiat = %s\n", s2);


}

/* strcpy: copiaza t in s; versiunea cu indici de tablou */


void strcpy(char *s, char *t)
{
int i = 0;

while ((s[i] = t[i]) != '\0')


i++;
}

VARIANTA 2
/* strcpy: copiaza t in s; versiunea cu pointeri 1 */
void strcpy(char *s, char *t)
{
while ((*s = *t) != '\0'){
s++;
t++;
}
}

VARIANTA 3
/* strcpy: copiaza t in s; versiunea cu pointeri 2 */
void strcpy(char *s, char *t)
{
while ((*s++ = *t++) != '\0')
;
}

VARIANTA 4
/* strcpy: copiaza t in s; versiunea cu pointeri 3 */
void strcpy(char *s, char *t)
{
while (*s++ = *t++)
;
}

Aplicație rezolvată 9. Folosind pe rând câte una din variantele de funcție strcmp de mai jos scrieți un program
care citește două șiruri de caractere pe are le compară.

Observație: Funcţia strcmp compară lexicografic două şiruri de


caractere (s şi t) şi returnează o valoare: negativă, dacă s < t;
zero, dacă s == t; pozitivă, dacă s > t. Valoarea se obţine prin
scăderea caracterelor aflate în prima poziţie în care t şi s diferă.

VARIANTA 1
#include <stdio.h>

int strcmp (char *s, char *t);

int main()
{
char s1[10], s2[10], c;
int i;

8
printf("introduceti primul sir: ");
i = 0;
while ((c = getchar()) != '\n')
s1[i++] = c;
s1[i]='\0';

printf("primul sir = %s\n",s1);

printf("\nintroduceti al 2-lea sir: ");


i = 0;
while ((c = getchar()) != '\n')
s2[i++] = c;
s2[i]='\0';

printf("al 2-lea sir = %s\n",s2);

i = strcmp(s1,s2);
if ( i == 0 )
printf("\nsirurile sunt egale\n");
else if ( i < 0 )
printf("\nprimul sir \"%s\" < al 2-lea sir \"%s\"\n", s1, s2);
else
printf("\nprimul sir \"%s\" > al 2-lea sir \"%s\"\n", s1, s2);

return 0;
}

/* strcmp: compara sirurile de caractere s si t; versiunea cu indici de tablou */


int strcmp (char *s, char *t)
{
int i;

for (i = 0; s[i] == t[i]; i++)


if (s[i] == '\0')
return 0;

return s[i] - t[i];


}

VARIANTA 2
/* strcmp: compara sirurile de caractere s si t; versiunea cu pointeri */
int strcmp (char *s, char *t)
{
for ( ; *s == *t; s++, t++)
if (*s == ‘\0’)
return 0;

return *s – *t;
}

POINTERI LA POINTERI

Un pointer la pointer este tot un pointer ce conține adresa unei alte variabile de tip pointer care, la rândul ei,
conține adresa unei variabile obișnuite.

int a = 7, *p = &a, **pp = &p;

printf("adresa p(&p) = %p, pp = %p \n", &p, pp);


printf("a = %d, *p = %d, **p = %d\n", a, *p, **pp);
printf("adresa a(&a) = %p, p = %p, *pp = %p \n", &a, p, *pp);

9
Aplicație rezolvată 10. Scrieți un program care afișează - folosind pointeri la pointeri - elementele unui tablou
de șiruri de caractere memorat pe baza unui tablou de pointeri la char (char *p[]).
Observație: Pointerul p este constant, el nu poate fi incrementat (p++) pentru afișarea celor opt șiruri de
caractere, dar putem defini un pointer la pointerul p, prin char **pp = p; care poate fi incrementat.
#include <stdio.h>

int main()
{
char *p[] = {"eroare zi", "duminica", "luni", "marti", "miercuri", "joi", "vineri",
"sambata"};
char **pp = p;
int i;

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


printf("%s ", p[i]);

printf("\n");

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


printf("%s ", *(pp++) );

return 0;
}

ALOCAREA DINAMICĂ

Multe aplicaţii pot fi optimizate dacă memoria necesară stocării datelor lor este alocată dinamic în timpul
execuţiei programului. Alocarea dinamică de memorie înseamnă alocarea de zone de memorie şi eliberarea lor
în timpul execuţiei programelor. Funcţiile de gestionare a memoriei au prototipurile în fişierele alloc.h şi
stdlib.h.

Funcţia de alocare dinamică a memoriei: Funcţia de eliberare dinamică a memoriei:


void * malloc(size_t size); void free(void *p);

Funcţia alocă în heap un bloc de dimensiune size; Funcţia eliberează un bloc alocat anterior cu malloc;
dacă operaţia reuşeşte returnează un pointer la adresa de început a blocului este transmisă ca
blocul alocat, altfel returnează NULL. argument, la apelul funcţiei.

void* calloc(size_t nmemb, size_t size); void* realloc(void *ptr, size_t size);

nmemb: numărul de elemente care trebuie alocate ptr: adresa veche a blocului
size: dimensiunea elementelor care trebuie alocate size: noua dimensiune a blocului, dacă este 0, iar
ptr indică spre un bloc de memorie existent, blocul
Funcţia alocă în heap un bloc de dimensiune
de memorie spre care indica ptr este eliberat și
nmemb*size; dacă operaţia reuşeşte returnează un
funcția întoarce pointerul NULL.
pointer la blocul alocat, altfel returnează NULL.
Blocul alocat este inițializat cu zero. Funcția redimensionează și realocă blocul de
memorie heap de la adresa indicată de ptr, bloc care
a fost alocat anterior în heap cu un apel de malloc ,
calloc sau realloc. Funcția întoarce noua adresă
de realocare a blocului în heap sau NULL.

Aplicație rezolvată 11. Scrieți un program care creează o copie alocată dinamic în heap a unui șir de caractere
alocat static. Către copia șirului va indica un pointer alocat static.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

10
int main()
{
char s1[20] = "Un sir de caractere", *s2;

printf("Sirul dat alocat static = \"%s\"\n", s1);

if ( (s2 = (char*)malloc(strlen(s1))) == NULL ){


printf("Eroare alocare dinamica\n");
exit(1);
}

strcpy(s2, s1);
printf("Copia lui alocata dinamic in HEAP = \"%s\" \n", s2);

return 0;
}

Aplicație rezolvată 12. Scrieți un program pentru alocarea dinamică în heap a unui tablou unidimensional (șir,
vector) v de n numere reale simplă precizie folosind funcția malloc.
/* alocarea dinamică a unui tablou (șir sau vector) de n numere reale */
#include <stdio.h>
#include <stdlib.h>

main(void)
{
int n, i;
float *v;

printf("numarul de elemente : "); scanf("%d", &n);

if ( ( v = (float *)malloc( n*sizeof(float) ) ) == NULL ){


printf("Eroare alocare dinamica!\n");
exit(1);
}

/* citire tablou */
printf("\ncitire tablou\n");
for (i = 0; i < n; i++){
printf("element[%d] = ", i + 1);
scanf("%f", &v[i]);
}

/* afisare tablou */
printf("\nafisare tablou\n");
for (i = 0; i < n; i++)
printf("%5.2f ", v[i]);

free(v); /* eliberare memorie */


}

Aplicație rezolvată 13. Scrieți un program pentru alocarea dinamică


în heap a unui tablou unimensional v de n numere întregi folosind
funcția calloc.
#include <stdio.h>
#include <stdlib.h>

int main(){
int n, i, *a;

printf ("numar de elemente din tablou = "); scanf ("%d", &n);


a = (int *) calloc (n, sizeof(int)); /* a = (int*) malloc (n * sizeof(int)); */

printf ("citire elemente tablou \n");

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


scanf ("%d", &a[i]); /* scanf ("%d", a + i); */
11
printf("\nafisare elemente tablou\n");
for (i = 0; i < n; i++)
printf ("%d ",a[i]); /* printf ("%d ", *(a + i)); */

return 0;
}

Aplicație rezolvată 14. Scrieți un program pentru alocarea dinamică în heap a unui tablou bidimensional
(matrici).

Observație: Dacă programul poate afla


numărul efectiv de linii şi de coloane al
unei matrici cu dimensiuni diferite de la
o execuţie la alta, atunci se va aloca
memorie pentru un vector de pointeri
funcţie de numărul liniilor şi apoi se va
aloca memorie pentru fiecare linie
funcţie de numărul coloanelor cu
memorarea adreselor liniilor în vectorul
de pointeri.
#include <stdio.h>
#include <stdlib.h>

int main ()
{
int **a, i, j, nl, nc;

printf ("nr. linii="); scanf ("%d",&nl);


printf ("nr. col. ="); scanf ("%d",&nc);

/* memorie pentru vectorul de pointeri la linii */


a = (int**) malloc (nl * sizeof(int*));

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


/* aloca memorie pentru fiecare linie i si face initializare la zero */
a[i] = (int*) calloc(nc, sizeof(int));

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


a[i][i] = 1; /* a[i][j] = 0 pt. i != j */

printf("afisare matrice cu indici\n");


for ( i = 0; i < nl; i++ ) {
for (j = 0; j < nc; j++)
printf("%3d", a[i][j]);
printf("\n");
}

printf("afisare matrice folosind pointeri\n");


for ( i = 0; i < nl; i++ ) {
for ( j = 0; j < nc; j++ )
printf("%3d", *(*(a + i) + j) );
printf("\n");
}

/* eliberare memorie heap */


for (i = 0; i < nl; i++)
free(a[i]);
free(a);

return 0;
}

12
Aplicație rezolvată 15. Scrieți un program care citește un număr necunoscut de valori întregi într-un vector
extensibil alocat dinamic în heap.
#include <stdio.h>
#include <stdlib.h>

#define INCREMENT 3 /* cu cat creste


vectorul la fiecare realocare */

int main()
{
int n = INCREMENT, i = 0, j;
float x, *v; /* v = adresa vector
*/

/* alocare initiala vector v cu n elemente: */


v = (float *)malloc(n * sizeof(float));

printf("introduceti elementele vectorului (^Z la final)\n");


while (scanf("%f",&x) != EOF) {
if (++i == n) { /* daca este necesar */
n += INCREMENT; /* creste dimensiunea vectorului */
v = (float *)realloc(v, n * sizeof(float));
}
v[i] = x; /* memorare x in elementul v[i] al vectorului */
}

for ( j = 1; j <= i; ++j) /* afisare vector */


printf("%7.2f", v[j]);

return 0;
}

ARGUMENTE DE TIP POINTER LA FUNCȚII

Argumentele de tip pointer permit unei funcții să acceseze și să modifice obiecte din funcția care a apelat-o. De
exemplu, să considerăm funcția getint care realizează conversia datelor de intrare independentă de format,
prin împărțirea unui flux de caractere în valori întregi, câte un întreg la fiecare apel. Funcția getint trebuie să
returneze valoarea pe care a găsit-o și să semnaleze de asemenea sfârșitul de fișier când nu mai există date de
intrare. Aceste valori trebuie trimise înapoi pe căi separate, deoarece indiferent ce valoare este folosită pentru
EOF, aceasta ar putea fi și valoarea unui întreg din fișierul de intrare.
O soluție este ca funcția getint să returneze indicatorul de sfârșit de fișier ca valoarea a sa, folosind în același
timp un argument de tip pointer pentru a trimite întregul rezultat după conversie înapoi în funcția apelantă.
Acesta este procedeul pe care îl folosește și funcția scanf. Următorul ciclu completează un tablou cu întregi
prin apeluri la funcția getint:
int n, array[SIZE], getint(int *);
for (n = 0; n < SIZE && getint(&array[n]) != EOF; n++)
;

Fiecare apel setează variabila array[n] la valoarea următorului întreg întâlnit în fișierul de intrare și îl
incrementează pe n. Observați că este esențială transmiterea adresei variabilei array [n] funcției getint.
Altfel nu există nici o cale ca getint să comunice întregul rezultat după conversie apelantei sale.
Funcția getint returnează EOF pentru sfârșit de fișier, zero dacă următoarea dată de intrare nu este un număr şi
o valoare pozitivă dacă data de intrare conține un număr valid.
#include <ctype.h>
int getch(void);
void ungetch(int);

/* getint: get next integer from input into *pn */


int getint(int *pn){
int c, sign;
while (isspace(c = getch())) /* skip white space */
;

13
if (!isdigit(c) && c != EOF && c != '+' && c != '-') {
ungetch(c); /* it is not a number */
return 0;
}
sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getch();
for (*pn = 0; isdigit(c); c = getch())
*pn = 10 * *pn + (c - '0');
*pn *= sign;
if (c != EOF)
ungetch(c);
return c;
}

În interiorul funcției getint, *pn este folosit ca o variabilă de tip int obișnuită. Am folosit de asemenea
funcțiile getch şi ungetch (prezentate în Cursul 6 la Aplicația cu programul calculator care folosește stiva și
notația poloneză inversă) astfel încât acel caracter suplimentar care trebuie citit să poată fi reintrodus în fișierul
de intrare.

Aplicaţie rezolvată 16*. Scrieţi un program C care foloseşte funcţia getint pentru a citi și a afișa un șir de
valori întregi până la introducerea unor caractere care nu pot fi numere întregi.
#include<stdio.h>
#include <ctype.h>

int getint(int *pn);

int main()
{
#define SIZE 100
int n, array[SIZE], getint(int *), i, k;

for (n = 0; n < SIZE && (k = getint(&array[n])) && k != EOF; n++)


;
printf("nr de valori numerice intregi citite: %d\n", n);
for ( i = 0; i < n; ++i )
printf("%d\n", array[i]);

return 0;
}

int getch(void);
void ungetch(int);

/* getint: get next integer from input into *pn */


int getint(int *pn)
{
int c, sign;

while (isspace(c = getch())) /* skip white space */


;

if (!isdigit(c) && c != EOF && c != '+' && c != '-') {


ungetch(c); /* it is not a number */
return 0;
}

sign = (c == '-') ? -1 : 1;
if (c == '+' || c == '-')
c = getch();

for (*pn = 0; isdigit(c); c = getch())


*pn = 10 * *pn + (c - '0');

*pn *= sign;

14
if (c != EOF)
ungetch(c);

return c;
}

#define BUFSIZE 100


char buf[BUFSIZE]; /* buffer for ungetch */
int bufp = 0; /* next free position in buf */

int getch(void) /* get a (possibly pushed-back) character */


{
return (bufp > 0) ? buf[--bufp] : getchar();
}

void ungetch(int c) /* push character back on input */


{
if (bufp >= BUFSIZE)
printf("ungetch: too many characters\n");
else
buf[bufp++] = c;
}

Aplicaţie propusă 7. Folosind codul de mai jos scrieţi un program complet pentru conversia datei din zi a lunii
în zi a anului şi invers, prin intermediul celor două funcţii:
 zi_a_anului – converteşte ziua şi luna în ziua din an
 luna_zi – converteşte ziua din an în lună şi zi.
static char tabzi[2][13] = {
{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

/* zi_a_anului: calculeaza ziua din an avand an, luna, zi */


int zi_a_anului(int an, int luna, int zi)
{
int i, bisect;
bisect = an%4 == 0 && an%100 != 0 || an%400 == 0;
for (i = 1; i < luna; i++)
zi += tabzi[bisect][i];
return zi;
}

/* luna_zi: calculeaza luna si ziua avand ziua din an */


void luna_zi(int an, int zi_an, int *pluna, int *pzi)
{
int i, bisect;
bisect = an%4 == 0 && an%100 != 0 || an%400 == 0;
for(i = 1; zi_an > tabzi[bisect][i]; i++)
zi_an -= tabzi[bisect][i];
*pluna = i;
*pzi = zi_an;
}

REZOLVĂRI

Aplicaţie propusă 1. Funcția f returnează lungimea unui șir de caractere, furnizat funcției prin argumentul de
tip pointer către char: s. Scrieți un program complet în care să integrați funcția.
/* afiseaza lungimea unui sir dat */
#include <stdio.h>
int f(char *s);

main()
{
char s[10] ="Curs PCLP", *p;

15
printf("lungimea sirului \"%s\" = %d\n", s, f(s));
printf("lungimea sirului \"Curs PCLP\" = %d\n", f("Curs PCLP"));
p = s;
printf("lungimea sirului \"%s\" = %d\n", s, f(p));
}

/* f: returneaza lungimea sirului s */


int f(char *s)
{
int n;
for (n = 0; *s !='\0'; s++)
n++;
return n;
}

Aplicaţie propusă 2. Funcția f returnează lungimea unui șir de caractere, furnizat funcției prin argumentul de
tip pointer către char: s. Scrieți un program complet în care să integrați funcția.
/* afiseaza lungimea unui sir dat */
#include <stdio.h>
int f(char *s);

main()
{
char s[10] ="Curs PCLP", *p;

printf("lungimea sirului \"%s\" = %d\n", s, f(s));


printf("lungimea sirului \"Curs PCLP\" = %d\n", f("Curs PCLP"));
p = s;
printf("lungimea sirului \"%s\" = %d\n", s, f(p));
}

/* f: returneaza lungimea sirului s */


int f(char *s)
{
char *p = s;/* initializare cu adresa sirului*/

while (*p != '\0')


p++;

return p - s; /* returneaza nr de caractere parcurse */


}

Aplicaţie propusă 3. Scrieţi un program care conţine codul dat.


/* lucru cu pointeri */
#include <stdio.h>

main(void)
{
int x, *p;
x = 3;
p = &x;
printf("*p = %d\n", *p);/* valoarea obiectului indicat de p:valoarea lui x.Afişeaza 3 */
*p = 5; /* modifică valoarea obiectului indicat de p, adică valoarea lui x. */
printf(" x = %d", x); /* afișează 5 */
}

Aplicaţie propusă 4. Citiţi şi afişaţi elemente unei matrici cu N linii şi M coloane.


/* citire si afisare matrice de numere reale */
#include <stdio.h>

#define N 3
#define M 2

main(void)
16
{
float a[N][M];
int i, j;

/* citire matrice */
printf("Introduceti elementele matricii: \n");
for(i = 0; i < N; i++)
for(j = 0; j < M; j++){
printf("element[%d][%d] = ", i, j);
scanf("%f", &a[i][j]);
}
/* afisare matrice */
for(i = 0; i < N; i++) {
for(j = 0; j < M; j++)
printf("%8.2f", a[i][j]);
printf("\n");
}
}

Aplicaţie propusă 5. Folosind funcția luna(l), care returnează un pointer la un şir de caractere ce conține
numele celei de a n-a luni, construiți un program care citind un număr natural între 1 și 12 afișează luna
corespunzătoare din an. Programul are prevăzută și posibilitatea ca în cazul furnizării unui număr în afara
intervalului 1..12 să afișeze un mesaj: “eroare luna!”.
#include <stdio.h>

char *luna(int l);

main()
{
int nr;

printf("introduceti numarul unei luni din an: "); scanf("%d", &nr);


printf("\nluna %d din an este : %s\n", nr, luna(nr) );
}

char *luna(int l)
{
static char *p[] = {"eroare luna!", "ian", "feb", "mar", "apr", "mai", "iun", "iul",
"aug", "sep", "oct", "nov", "dec"};

return (l < 1 || l > 12) ? p[0] : p[l];


}

Aplicaţie propusă 6. Folosind funcția luna(l), construiți un program care citind un număr natural între 1 și 12
afișează luna corespunzătoare din an. Programul are prevăzută și posibilitatea ca în cazul furnizării unui număr
în afara intervalului 1..12 să afișeze un mesaj: “eroare luna!”. Dacă în aplicația anterioară am folosit un
vector de pointeri pentru a memora mesajul de eroare și numele celor 12 luni, de data aceasta folosim un tablou
bidimensional (matrice).
#include <stdio.h>

char *luna(int l);

main()
{
int nr;

printf("introduceti numarul unei luni din an: "); scanf("%d", &nr);


printf("\nluna %d din an este : %s\n", nr, luna(nr) );
}

char *luna(int l)
{
static char a[][17] = {"eroare luna!", "ian", "feb", "mar", "apr", "mai", "iun", "iul",
"aug", "sep", "oct", "nov", "dec" };

17
return (l < 1 || l > 12) ? a[0] : a[l];
}

Aplicaţie propusă 7. Folosind codul dat scrieţi un program complet pentru conversia datei din zi a lunii în zi a
anului şi invers, prin intermediul celor două funcţii:
 zi_a_anului – converteşte ziua şi luna în ziua din an
 luna_zi –
converteşte ziua din
an în lună şi zi.
#include <stdio.h>

static char tabzi[2][13] = {


{0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

int zi_a_anului(int an, int luna, int zi);


void luna_zi(int an, int zi_an, int *pluna, int *pzi);

int main()
{
int an, luna, zi, a, b, *l = &a, *z = &b;

printf("dati o data calendaristica (zz/ll/aaaa): ");


scanf("%2d/%2d/%4d", &zi, &luna, &an);
printf("data introdusa este a %d-a zi a anului\n", zi_a_anului(an, luna, zi));

printf("introduceti un an calendaristic cu 4 cifre : ");


scanf("%d", &an);
printf("introduceti un numar (1..366) reprezentand o zi din acest an : ");
scanf("%d", &zi);
luna_zi(an, zi, l, z);
printf("numarul %d corespunde zilei a %d-a din luna a %d-a a anului %d\n", zi, *z, *l,
an);
}

/* zi_a_anului: calculeaza ziua din an avand an, luna, zi */


int zi_a_anului(int an, int luna, int zi)
{
int i, bisect;
bisect = an%4 == 0 && an%100 != 0 || an%400 == 0;
for (i = 1; i < luna; i++)
zi += tabzi[bisect][i];
return zi;
}

/* luna_zi: calculeaza luna si ziua avand ziua din an */


void luna_zi(int an, int zi_an, int *pluna, int *pzi)
{
int i, bisect;

bisect = an%4 == 0 && an%100 != 0 || an%400 == 0;


for(i = 1; zi_an > tabzi[bisect][i]; i++)
zi_an -= tabzi[bisect][i];

*pluna = i;
*pzi = zi_an;
}

18

S-ar putea să vă placă și