Linguaggio C: Funzioni e Puntatori Laboratorio di Programmazione Gruppo 1
Problema: scrivere una funzione che calcoli la potenza n-ma di un numero intero m e una funzione main che la utilizzi
#include #include /* dichiarazione della funzione power */ int power(int base, int n); main(){ int i, potenza; for(i=0 ; i < 10 ; i++){ potenza = power(2,i); printf("%d %d \n", i, potenza); } } /* funzione potenza */ int power(int base, int n) { int i, p=1; for (i=1 ; i <=n ; i++) p=p*base; return p; }
STRUTTURA DI UNA FUNZIONE La prima linea della funzione power è la definizione della funzione: int power (int base, int n) tipo del valore che nome della tipo e nome la funzione ritorna funzione dei parametri Con l'istruzione return p il valore di p è mandato di ritorno alla funzione chiamante main() attraverso il nome della funzione
L'istruzione, prima di main(), int power(int m, int n); è la dichiarazione della funzione (o prototipo) specifica il tipo del valore di ritorno, il tipo ed il nome degli argomenti La dichiarazione di una funzione deve concordare con la sua definizione. CHIAMATA DELLA FUNZIONE: potenza = power(2,i);
Problema: scambia i valori di due variabili #include #include int scambio(float x, float y); int scambio(float x, float y); /* funzione main */ main() { float a, b; float a, b; a=3; b=5; a=3; b=5; scambio(a,b); scambio(a,b); printf("a=%f b=%f \n", a, b); printf("a=%f b=%f \n", a, b);} /* funzione scambio */ int scambio(float x, float y) { float t; float t; t=x; x=y; y=t; t=x; x=y; y=t; return 0; } return 0; }
L'esecuzione del precedente programma non dà il risultato atteso. Si ottiene infatti: a=3 b=5 Perchè? Nel linguaggio C tutti gli argomenti di una funzione sono passati per VALORE Le funzioni non possono alterare il valore degli argomenti nella funzione chiamante main() Come risolvere il problema ?
PUNTATORI…p … x … memoria memoria p è un puntatore alla variabile x CIOE' p è una variabile che contiene l'indirizzo della variabile x L'istruzione p = &x ; assegna l'indirizzo di x alla variabile puntatore p ( p punta a x ) L'operatore unario * applicato ad una variabile puntatore restituisce il contenuto della variabile puntata: *p è il contenuto dell’area di memoria puntata da p, cioè nel nostro esempio il valore di x
Una variabile puntatore deve essere dichiarata Ad esempio: int *p; p è una variabile puntatore ad una locazione di memoria di tipo intero ESEMPIO: int x; /* dichiarazione della variabile x */ int *p; /* dichiarazione del puntatore p */ p=&x; /* assegnazione a p dell'indirizzo di x */ *p=3;/* assegnazione al contenuto di p del valore 3*/ nomi p x indirizzi …52…3…
Esempio: int x=1, y=2, z[10]; int *p; /* dichiarazione del puntatore p */ p = &x; /* p ora punta a x */ y = *p; /* y ora vale 1 */ *p = 0; /* x ora vale 0 */ p = &z[0]; /* p ora punta a z[0] */ p = &z[0]; /* p ora punta a z[0] */ I puntatori possono apparire nelle espressioni, ad esempio: int x,y, *p; p=&x; y = *p +1; /* equivale a y = x+1; */ *p += 1; /* equivale a x = x+1; */ *p = 10; /* equivale a x=10; */ Se q è un altro puntatore ad una variabile intera, l'istruzione Se q è un altro puntatore ad una variabile intera, l'istruzione q = p; copia il contenuto di p in q, cioè q punta alla stessa variabile a cui punta p
Soluzione del problema dello scambio di variabili: utilizzo dei puntatori Soluzione del problema dello scambio di variabili: utilizzo dei puntatori Funzione: Funzione: void scambio (float *px, float *py) { float temp; temp = *px; temp = *px; *px = *py; *py = temp; } Chiamata alla funzione: scambio(&a, &b);
Problema: Prodotto matrice-vettore #include #include main(){ float a[8][8],b[8],c[8]; int i,j,n; scanf ("%d", &n); for (i=0; i<n; i++){ scanf ("%f", &b[i]); for (j=0; j<n; j++) { scanf ("%f", &a[i][j]); }} for (i=0; i<n; i++){ c[i]=0.; for (j=0; j<n; j++){ c[i]=c[i]+a[i][j]*b[j];} printf ("%f\n", c[i]); }}
Esiste una stretta relazione tra array e variabili puntatore int a[10]; int *pa; pa = &a[0]; pa pa+1 pa+2 pa+1 è l'indirizzo di a[1] … *(pa+1) è il contenuto di a[1] pa+i è l'indirizzo di a[i] … *(pa+i) è il contenuto di a[i] a[9]…a[1]a[0] a a[9]…a[1]a[0] a
PER DEFINIZIONE il nome di un array è l'indirizzo del primo elemento dell'array Ad esempio: int a[10], *pa; a[i] ⇔ *(a+i) &a[i] ⇔ a+i pa = &a[0]; ⇔ pa = a; *(pa+i) ⇔ pa[i]
MA un puntatore è una variabile, il nome di un array è una costante LE ISTRUZIONI pa=a; pa++; SONO CONSENTITE a=pa; a++; NON SONO CONSENTITE
Se il nome di un array è passato come argomento ad una funzione, in realtà è passato l'indirizzo del primo elemento dell'array Esempio: main() { int a[3]; ∶ fun(a); ∶ } Il prototipo della funzione può essere del tipo: int fun(int arr[3]); oppure int fun(int arr[]); oppure int fun(int *arr);
Somma di due vettori I versione (senza puntatori) #include main() { float a[10],b[10],c[10]; int i,n; scanf("%d",&n); for(i=0;i<n;i++) scanf("%f %f",&a[i],&b[i]); for(i=0;i<n;i++) { c[i]=a[i]+b[i]; printf("%f\n",c[i]); }
Somma di due vettori II versione (con puntatori) #include main() { float a[10],b[10],c[10]; int i,n; scanf("%d",&n); for(i=0;i<n;i++) scanf("%f %f",a+i,b+i); for(i=0;i<n;i++) { *(c+i)=*(a+i)+*(b+i); printf("%f\n",*(c+i)); }
F I N E