Sunteți pe pagina 1din 9

Programarea Calculatoarelor - Limbaje

Lucrarea 10. Pointeri şi tablouri. Transferul de argumente către main().


Pointeri spre funcţii.

O1. Utilizarea pointerilor la tablouri.


Obiective O2. Indexarea tablourilor folosind operații specifice pointerilor
O3. Utilizarea argumentelor din linia de comandă

INTRODUCERE

Tablouri și pointeri
Identificatorul unui tablou este un pointer constant la primul element din tablou. Această valoare
poate fi atribuită unui alt pointer. Poate fi folosit pentru accesul la elementele tabloului folosind ar-
itmetica pointerilor
Spre deosebire de pointeri (ce pot fi modificați pe parcursul unui program), identificatorul unui
tablou este un pointer constant!!

Indexare pointeri
Indexarea unui pointer asemenea unui tablou are sens doar dacă referă un tablou:
int *p = tab;
printf("%d", p[i]);//echivalent cu *(p+i)

Dacă p pointează pe un tablou, compilatorul C/C++ generează cod mai scurt pentru *(p+i) decât
pentru p[i]
OBS: dacă un pointer referă un tablou și se folosește operatorul de indexare [ ], operatorul de
indirectare * nu mai e folosit.
Dacă un pointer nu pointează pe un tablou, el poate fi indexat, dar rezultatul este imprevizibil.

Acces la elementele unui tablou prin adresă


Un tablou este definit in memorie prin:
• numele tabloului, ca și un pointer constant ce are ca valoare adresa primului element din
tablou
• elementele tabloului sunt memorate în mod contiguu
• tablourile multidimensionale sunt tratate ca tablouri unidimensionale în care fiecare element
este N-1 dimensional

Elementele unui tablou pot fi accesate și prin operații aritmetice specifice pointerilor
*(tab+i)

© Adriana Stan, Ligia Chiorean, Mircea Vaida 1 Programarea Calculatoarelor - Limbaje


Tablouri de pointeri
Tablourile de pointeri se definesc astfel:
tip *nume_ptr[DIM];

reprezintă un tablou de adrese. Se folosesc mai ales la crearea de tablouri de şiruri de carac-
tere
Tablourile de pointeri pot fi accesate cu pointeri dubli
char *a[5];
char **p; // pointer dublu catre caractere
p = a;
p va conține adresa primului element al tabloului a, unde vom avea un pointer spre un caracter,
astfel încât (p+1) va indica elementul a[1], etc.

Indirectarea multiplă

Când un pointer pointează alt pointer avem un proces de indirectare multiplă:


Pointer --> Pointer --> Variabilă
Primul pointer conține adresa celui de-al doilea pointer, pointer care pointează locația variabilei,
obiectului sau a funcției.
Declararea se face utilizând un * suplimentar în fața numelui pointerului:
char **pm, *p, ch;
p = &ch;
pm = &p;
**pm = 'A'; // ch = ‘A’
Indirectarea multiplă e utilizată la returnarea valorilor din funcții și alocarea dinamică a
tablourilor.

Declaratori complecși
Un declarator complex este un identificator însoțit de mai mult de un modificator de tipurile:
• de date, [ ]
• pointer, *
• funcție, ( )
Aceste combinații variate pot fi aplicate 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

Evaluarea declaratorilor:
• parantezele ( ) și [ ] din dreapta (funcții și tablouri) identificatorului au prioritate mai mare
decât * din stânga identificatorului
• parantezele ( ) și [ ] au aceeași prioritate, asocierea făcându-se de la S ->D
• specificatorul de tip este aplicat în ultimul pas, când declaratorul a fost complet evaluat
• parantezele ( ) ca și operator, se pot folosi pentru a schimba asocierea implicită, forțând
una explicită

© Adriana Stan, Ligia Chiorean, Mircea Vaida 2 Programarea Calculatoarelor - Limbaje


Pointeri la funcții
O funcție, ca şi un tablou, are asociată o adresă fixă de memorie. Un pointer către o funcție va
conține această adresă. Declararea unui pointer spre o funcție trebuie să precizeze tipul returnat
de funcție şi numărul, respectiv tipul parametrilor
tip_rezultat (*pf) (lista_param_formali);

Parantezele (*pf) sunt obligatorii!!


Utilizați pentru transferul adresei unei funcții ca parametru sau construirea unor tablouri de
adrese de funcții ce pot fi apelate indirect.
Exemplu:
char* (*pf) (char *, const char *);

pf este un pointer la o funcție care:


• are doi parametri, unul char * , altul const char *
• returnează un pointer la șir de caractere, char *
Numele unei funcții e sinonim cu adresa de început a acesteia, putem avea declarații:
pf = strcpy; pf = &strcpy;
Apelul unei funcții prin intermediul unui pointer se face cu construcția:
(*pf) (lista_param_actuali);

Dacă funcția returnează o valoare, aceasta se poate atribui unei variabile:


var = (*pf) (lista_param_actuali);

Observații:
Standardul ANSI permite scrierea apelului fără a folosi operatorul de indirectare *:
pf (lista_param_actuali);
sau
var = pf (lista_param_actuali);

Parantezele permit distingerea între declarația unui pointer de funcție şi prototipul unei funcții
care returneaza un pointer:
tip_rez *nume_f(...); //functie ce returneaza un pointer
tip_rez (*nume_pf)(…); //pointer de functie

Funcția main cu argumente


void 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
• argv[1] - pointează pe un şir de caractere cu primul argument, ş.a.m.d.
© Adriana Stan, Ligia Chiorean, Mircea Vaida 3 Programarea Calculatoarelor - Limbaje
• env - este un tablou de pointeri către şiruri de caractere care reprezintă o listă de parametri ai
sistemului de operare
Între argumente se acceptă ca separator spațiu şi tab, iar dacă un argument va conține
spațiu(tab), acel argument va fi încadrat între ghilimele
Numele argc, argv, env nu sunt impuse, sunt doar identificatori
Pentru că aceste argumente se primesc sub forma de şiruri de caractere, aceste şiruri pot fi
convertite spre un format intern de reprezentare în memorie cu funcțiile atoi(), atof(), atol()
Indiferent de modul de utilizare a funcției main() de către utilizator, cei trei parametri sunt alocați
pe stivă

Funcția main - valoare returnată


Funcția main( ) poate returna un rezultat către programul apelant. În general, un rezultat 0 in-
dică terminarea normală a programului, iar orice altă valoare indică terminare anormală. Return-
area rezultatului se face cu ajutorul instrucțiunii return, ca în orice altă funcție C/C++:

EXEMPLE
1. Program pentru determinarea celui mai mic element dintr-un tablou unidimensional.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#define DIM 20

int DetMin(int *, int);//prototip ce ret min din tablou

int main(void){
int i, dim, min;
int x[DIM];
printf("\nIntroduceti dimensiunea tabloului unidimensional: ");
scanf("%d", &dim);
if(dim > DIM)
{
printf("\n Dimensiune prea mare !\n");
return 0;
}

printf("\n Introduceti elementele tabloului unidimensional:\n");


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 tabloul unidimensional este:
%d\n", min);
}

int DetMin(int *x, int n){


© Adriana Stan, Ligia Chiorean, Mircea Vaida 4 Programarea Calculatoarelor - Limbaje
int i, min;
min = *x++;
for(i=1; i<n; i++){
if(*x < min)
min = *x;
x++;
}
return min;
}

2. Program ce utilizează pointeri spre funcţii

#include <stdio.h>

int get_result(int, int, int (*)(int, int));

int max(int, int);


int min(int, int);

int main(void){
int result;

result = get_result(1, 2, max);


printf("Max dintre 1 si 2 este: %d\n", result);

result = get_result(1, 2, min);


printf("Min dintre 1 si 2 este: %d\n", result);

int get_result(int a, int b, int (*compare)(int, int)){


return(compare(a, b)); // apel functie prin pointer
}

int max(int a, int b){


printf("Apel functia max:\n");
return((a > b) ? a: b);
}

int min(int a, int b){


printf("Apel functia min:\n");
return((a < b) ? a: b);
}

3. Program care preia de la consolă mai multe numere întregi ca şi valori de rezistenţe şi cal-
culează rezistenţa echivalentă grupării serie sau paralel.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

© Adriana Stan, Ligia Chiorean, Mircea Vaida 5 Programarea Calculatoarelor - Limbaje


#include <ctype.h>
#define DIM 10

float calcul(int*, int, float (*)(int*, int));


float serie(int *, int);
float paralel(int *, int);

int main(void){
int i, n, tab[DIM];
float rez;
char grp;

printf("\nIntroduceti numarul de rezistente <=10 : ");


scanf("%d", &n);
if(n==0) return 0;

printf("\nIntroduceti %d valori de rezistente :\n", n);


for(i=0; i<n; i++){
printf("Rezistenta %d :", i+1);
scanf("%d", &tab[i]);//(tab+i)
}

printf("\nGrupare serie/paralel (s/p) ? ");


fflush(stdin);
scanf("%c", &grp);//grp=_getch()

switch(toupper(grp))
{
case 'S': rez = calcul(tab, n, serie);
break;
case 'P': rez = calcul(tab, n, paralel);
break;
default: printf("\n Operatie invalida !");
return 0;
}//end switch
printf("\n Rezistenta echivalenta este: %f\n", rez);
return 0;
}//end main

float calcul(int *tab, int n, float (*pf)(int *, int)){


return(pf(tab, n));
}//end calcul

float serie(int *tab, int n){


float suma = 0;
while(n)
suma += tab[--n];
return(suma);
}//end serie

© Adriana Stan, Ligia Chiorean, Mircea Vaida 6 Programarea Calculatoarelor - Limbaje


float paralel(int *tab, int n){
float suma = 0;
while(n)
suma += 1./tab[--n];
return(1./suma);
}//end parelel

4. Program care preia din linia de comandă numere întregi şi afişează suma acestora.
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

void main (int argc, char *argv[]){


int i, suma=0, n;

if (argc == 1) {
printf("\n\n\tNu ati introdus numerele de adunat !");
return 0;
}//end if
else{
for(i=1; i<argc; i++){
n = atoi(argv[i]);
suma += n;
}//end for
printf("\nSuma argumentelor din linia de comanda este :
%d\n", suma);
return 0;
}//end else
}//end main

TEME
1. Rezolvaţi problemele din laboratorul de aplicaţii cu tablouri (laboratorul 8, problemele 1-12)
folosind pointeri.
2. Să se citească doi parametri întregi şi alţi doi flotanţi din linia de comandă. Să se afişeze suma
şi produsul lor.
3. Scrieţi o aplicaţie care citeşte de la tastatură un şir de caractere cu lungimea mai mare decât
7. Folosiţi un pointer pt. a accesa şi afişa caracterele de pe poziţiile 1, 3, 5 şi 7.
4. Citiţi de la tastatură elementele a 2 matrici de valori întregi. Scrieţi o funcţie care primeşte ca
parametri pointerii la cele 2 matrici şi returnează un pointer la matricea sumă. Rezultatul în-
sumării matricelor va fi afişat în funcţia main. Afişaţi elementele de pe diagoanala secundară a
matricii sumă, folosind acelaşi pointer.

© Adriana Stan, Ligia Chiorean, Mircea Vaida 7 Programarea Calculatoarelor - Limbaje


5. Definiţi un tablou de pointeri către şiruri de caractere. Fiecare locaţie a tabloului conţine
adrese către unul din urmatoarele şiruri de caractere:
- "valoare prea mică"
- "valoare prea mare"
- "valoare corectă"
Aplicaţia generează un număr aleator între 1 şi 100 şi apoi citeşte în mod repetat intrarea de la
tastatură până când utilizatorul introduce valoarea corectă. Folosiţi mesajele definite pentru a
informa utilizatorul, la fiecare pas, despre relaţia existentă între numărul generat şi ultima valoare
citită.
6. Scrieţi un program în care să citiți de la tastatură o serie de mesaje ce vor fi stocate într-un
tablou de pointeri spre şiruri de caractere. Afişaţi apoi mesajele.
7. Să se scrie un program care preia din linia de comandă şiruri de caractere şi afişează şirul
rezultat din concatenarea acestora.
8. Să se scrie un program care inversează şirul de caractere citit din linia de comandă.

9. Scrieţi un program care citeşte de la tastatură elementele de tip float ale unui tablou unidimen-
sional, elemente ce reprezintă mediile unei grupe de studenţi. Să se scrie o funcţie care deter-
mină numărul studenţilor cu media >= 8. Afişaţi rezultatul în main(). (lucrati cu pointeri, fără vari-
abile globale).
10. Scrieţi un program C în care se citesc de la tastatură elementele de tip întreg ale unui tablou
unidimensional A prin intermediul unei funcţii. Scrieţi o altă funcţie care completează un tablou
unidimensional B. Fiecare element al lui B este obţinut prin scăderea mediei aritmetice a tuturor
elementelor din A din elementul corespunzător din A. Scrieţi o funcţie care permite afişarea unui
tablou unidimensional şi afişaţi tablourile unidimensionale A şi B. (utilizând pointeri, fără variabile
globale).
Ex:
A=123456789
medie aritmetica = 5

B = -4 -3 -2 -1 0 1 2 3 4
11. Scrieţi un program în care se citesc de la tastatură elementele de tip întreg ale unei matrici
pătratice, utilizând o funcţie. Scrieţi o funcţie care determină numărul de elemente negative de
deasupra diagonalei secundare. Afisaţi rezultatul în main() (fără variabile globale).
Ex:

A = 1 -2 -3
23 0
45 6
Out: 2
12. Scrieţi un program în care se citesc de la tastatură elementele de tip întreg ale unei matrici
pătratice, utilizând o funcţie. Scrieţi o funcţie care interschimbă două linii ale matricii. Afişaţi cu o
funcţie matricea iniţială şi cea obţinută. Dimensiunea matricii şi numerele ce identifică liniile care
vor fi interschimbate se citesc de la tastatură, în funcţia main. (fără variabile globale).

© Adriana Stan, Ligia Chiorean, Mircea Vaida 8 Programarea Calculatoarelor - Limbaje


13. Scrieţi algoritmul care interclasează două tablouri unidimensionale de tip întreg. Folosiţi
pointeri.

Ex:

A=13579
B=2468

out: 1 2 3 4 5 6 7 8 9
14. Ordonaţi crescător un tablou unidimensional de numere întregi folosind funcţia de bibliotecă
qsort() din stdlib.h. Folosiţi acelaşi algoritm pentru numere de tip float şi ordonaţi descrescător.

© Adriana Stan, Ligia Chiorean, Mircea Vaida 9 Programarea Calculatoarelor - Limbaje

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