Sei sulla pagina 1di 16

Funzioni

Esempio. Stampa la tabella dei valori ak , per a = 2, 3, 4, 5 e


k = 0, 1, 2, 3, e fa quattro “bip”.
#define NUM 4
int main(void)
{ int a, k, from=2, to=5;
double p;
for(a=from; a<=to; a++) {
for(k=0; k<NUM; k++) {
p=power(a, k);
printf( "\t%g", p );
}
printf( "\n" ); beep();
}
return 0;
}
Corso di Laboratorio di LinguaggiCorso A – p.27/57

Funzioni
Prototipo di una funzione.
Riproduzione dell’intestazione, seguita da ‘;’.
Sintatticamente analogo a una dichiarazione di
variabile;
scope: dalla dichiarazione a fine file;
i nomi dei parametri sono facoltativi;
dà visibilità alla funzione, anche prima della sua
definizione. Es.:
double power(int base, int expo);
void beeps(int n);
oppure
double power(int, int);
void beeps(int); Corso di Laboratorio di LinguaggiCorso A – p.28/57
Funzioni
double power(int base, int expo);
...
int main(void)
{ ...
p=power(a,k); /* Ok, qui power() e‘ nota ... */
...
}

/* ... anche se definita dopo


(o anche in un altro file). */
double power(int base, int expo) {...}

Corso di Laboratorio di LinguaggiCorso A – p.29/57

Array
Array monodimensionali.
Sono variabili indicizzate, omogenee per tipo.
sintassi della dichiarazione:

hstorage-classiopt htype-namei hdichiaratore-arrayi;

hdichiaratore-arrayi è composto da un dichiaratore (=un


identificatore, o più complesso) seguito dall’operatore
[hdimi]

htype-namei è il nome del tipo di ogni elemento dell’array.


hdimi è un’espressione costante di valore intero ≥ 0.

Corso di Laboratorio di LinguaggiCorso A – p.30/57


Array
Se T è un tipo, x un identificatore e N è un intero, la
dichiarazione

T x[N ];
|{z}
dichiaratore

crea le variabili x[0], x[1], . . . , x[N − 1].


se k ≥ N , l’uso di x[k] in un’espressione non è illegale,
ma il risultato è indefinito (no bound checking!).

Esempio.
int x[5];
int a=0;
x[5]=3; // Fuori da x[] !!!
a=a+x[5]; // a=indefinito!
Corso di Laboratorio di LinguaggiCorso A – p.31/57

Array
L’operatore di assegnazione = non può essere utilizzato
tra array.
int x[10], y[10];
...
x=y; /* Errore! */
Una funzione non può ritornare array.

Corso di Laboratorio di LinguaggiCorso A – p.32/57


Array
Array multidimensionali.
Sono specificati come array di array, usando più volte
l’operatore [ ].

Es.: | {z } [4] ;
int x[3]
| {z }

Memorizzati per righe (l’ultimo indice varia per primo).


Leggere la dichiarazione da sx a dx, associando a dx:
array di 3 (array di 4 int).

Nota. L’espressione x[2] è perfettamente valida, ha tipo


“array di 4 int” e corrisponde alla terza riga di x.

Corso di Laboratorio di LinguaggiCorso A – p.33/57

Array
int x[3][4];

x[0][0], x[0][1], x[0][2], x[0][3], → x[0]


x[1][0], x[1][1], x[1][2], x[1][3], → x[1]
x[2][0], x[2][1], x[2][2], x[2][3], → x[2]

Esercizio. Dichiarando

double y[3][4][2];

come è memorizzato y?
che tipo hanno le espressioni y[1] e y[2][2]?

Corso di Laboratorio di LinguaggiCorso A – p.34/57


Array
y ha tipo “array di 3 (array di 4 (array di 2 double));

y[0][0][0], y[0][0][1], y[0][1][0], y[0][1][1],


y[0][2][0], y[0][2][1], y[0][3][0], y[0][3][1],
y[1][0][0], y[1][0][1], y[1][1][0], y[1][1][1],
y[1][2][0], y[1][2][1], y[1][3][0], y[1][3][1],
y[2][0][0], y[2][0][1], y[2][1][0], y[2][1][1],
y[2][2][0], y[2][2][1], y[2][3][0], y[2][3][1]

Corso di Laboratorio di LinguaggiCorso A – p.35/57

Array
y[1] è un (array di 4 (array di 2 double))

y[1][0][0], y[1][0][1],
y[1][1][0], y[1][1][1],
y[1] ⇐⇒
y[1][2][0], y[1][2][1],
y[1][3][0], y[1][3][1],

y[2][2] è un array di 2 double.

y[2][2] ⇐⇒ y[2][2][0], y[2][2][1]

Corso di Laboratorio di LinguaggiCorso A – p.36/57


Array
Array come tipi incompleti.
In vari contesti si può omettere la prima dimensione di
un array.

int x[];
double y[][10];
/* la seconda dim. e‘ obbligatoria! */

In questo caso l’array ha tipo incompleto.


Le altre dimensioni sono necessarie per l’accesso
corretto in memoria.
Comunque una dichiarazione di tipo incompleto non
crea l’array, ma ne dà visibilità.

Corso di Laboratorio di LinguaggiCorso A – p.37/57

Array
Passaggio di parametri.
Nelle definizioni di funzione i parametri array si
dichiarano sempre con gli operatori [ ].
Il tipo può però essere incompleto: la prima dimensione
è opzionale, quelle successive sono obbligatorie.
La seguente funzione ritorna l’indice corrispondente al massimo elemento del vettore v[].
Si noti che la “lunghezza” n viene passata esplicitamente.
int pos_max(double v[], int n)
{
int i, res;

res=0;
for(i=1; i<n; i++)
if( v[res]<v[i] )
res=i;
return res;
}
Corso di Laboratorio di LinguaggiCorso A – p.38/57
Array
Nelle funzioni, i parametri di tipo array sono specificati
sempre con [ ] — il tipo può essere incompleto.
Il passaggio di un parametro array ha l’effetto di un
passaggio by reference.
La contraddizione con quanto detto in precedenza sul
passaggio by value è solo apparente.
Di fatto viene passato un puntatore by value.

Corso di Laboratorio di LinguaggiCorso A – p.39/57

Array
#define COLS 5
void somma_colonne(int x[][COLS], int sum[],
int Nr_rows)
{ int i, j;
for(j=0; j<COLS; j++) {
sum[j]=0;
for(i=0; i<Nr_rows; i++)
sum[j]+=x[i][j];
}
...
int m[3][COLS]= { {1,2,3,4,5},
{6,7,8,9,10},
{11,12,13,14,15} };
int s[COLS];
somma_colonne(m, s, 3);
// in uscita s=(18,21,24,27,30) Corso di Laboratorio di LinguaggiCorso A – p.40/57
Array
Valori iniziali.
La dichiarazione di un array unidimensionale con valori
iniziali ha la struttura

hstorage-classiopt htypei hvariable-namei[hdimi]={hvaluesi}

hvaluesi è una lista di valori costanti separati da virgole;


se si specificano meno di hdimi valori, le rimanenti celle
dell’array ricevono un valore iniziale determinato dalle
regole di inizializzazione.
Se hvaluesi contiene più di hdimi valori si ha un errore.
Esempio.

int x[5]={-1,2,7}; // x[0]=-1, x[1]=2, x[2]=7


Corso di Laboratorio di LinguaggiCorso A – p.41/57

Array
L’inizializzazione completa un array con tipo incompleto.

int x[]={3,5,10}; // x e‘ lungo 3!

Per array multidimensionali — array di array. . . — il


contenuto iniziale viene specificato applicando
ricorsivamente le regole di inizializzazione.
Esempio.
double x[10][5] = { // Valori per:
{2.0, 3.0, 7.0, 10.0}, // x[0][0], x[0][1], x[0][2], x[0][3]
{-1.0, 4.0, 3.0} // x[1][0], x[1][1], x[1][2]
};
int y[3][3]={ {3}, {4,5,6}, {7} };
// Inizializza
// y[0][0]=3, y[1][0]=4, y[1][1]=5, y[1][2]=6, y[2][0]=7;

Corso di Laboratorio di LinguaggiCorso A – p.42/57


Array
Esercizio. Cosa stampa?
/* prova2.c */
#include <stdio.h>
#define ROWS 10
#define COLS 5
double m[ROWS][COLS] = { {2.0, 3.0, 7.0, 10.0}, {-1.0, 4.0, 3.0} };

int main(void)
{ int i, j;
for(i=0; i<ROWS; i++) {
for(j=0; j<COLS; j++)
printf( "\t%g", m[i][j] );
printf( "\n" );
}
printf("\n");
for(i=0; i<ROWS; i++)
printf( "%d\n", pos_max(m[i],COLS) );
return 0;
}
Corso di Laboratorio di LinguaggiCorso A – p.43/57

Stringhe
Stringhe di testo e caratteri.
Il linguaggio C fornisce un supporto minimo per la
gestione di stringhe.
Il tipo char garantisce, in ogni implementazione, di
poter rappresentare i codici numerici dei caratteri
stampabili (es. ASCII 0–127).
Le stringhe sono memorizzabili come array di char.
Convenzionalmente, un array di char che rappresenta
una stringa ha come ultimo elemento il carattere ’\0’.
Il carattere ’\0’ è il terminatore di stringa.
Si comporta a tutti gli effetti come la costante
numerica 0.

Corso di Laboratorio di LinguaggiCorso A – p.44/57


Stringhe
Una sequenza di caratteri compresa tra doppi apici " è
detta stringa costante.
Una stringa costante come "Pippo" corrisponde a un
array di char “anonimo” di classe static contenente
la sequenza di char

’P’, ’i’, ’p’, ’p’, ’o’, ’\0’.

Una stringa costante è un inizializzatore valido per un


array di char.

char nome[]="Pippo";

Corso di Laboratorio di LinguaggiCorso A – p.45/57

Stringhe
Il C non offre altri tipi di supporto nativi per i dati di tipo
stringa.
Operatori come il concatenamento, l’assegnazione o il
confronto di stringhe non fanno parte del linguaggio.
char s1[]="Pippo, s2[]="Pluto", s3[20];
printf( s1+s2 ); // Sbagliato
if( s1<s2 ) ... // Sbagliato
s3=s1; // Sbagliato

La libreria standard contiene però moltissime funzioni


per l’elaborazione di stringhe.
Per accedere a queste funzioni si include il file di
intestazione string.h.

#include <string.h>

Corso di Laboratorio di LinguaggiCorso A – p.46/57


Puntatori
Un puntatore è una variabile che contiene l’indirizzo di
(“punta a”) un’altra variabile.
Dichiarazione.
Se T è un nome di tipo, la dichiarazione

T *p;

dichiara una variabile di tipo “puntatore a T ”.


Il tipo di p è “T ∗”.
p può contenere l’indirizzo di una qualunque variabile
valida di tipo T .

Corso di Laboratorio di LinguaggiCorso A – p.47/57

Puntatori
Assegnazione e dereferenziazione.
L’operatore &hvariabilei ritorna l’indirizzo della variabile
argomento.
Se p è un’espressione di tipo T * che punta a una
variabile x di tipo T ,

l’espressione *p è equivalente a x.

Notare che * è un operatore diverso,


nelle dichiarazioni, e
nelle espressioni da valutare (operatore di
dereferencing).

Corso di Laboratorio di LinguaggiCorso A – p.48/57


Puntatori
Esempio.
int x=3;
int *px;
...
px=&x;
...
*px=*px+1; //x=4

Corso di Laboratorio di LinguaggiCorso A – p.49/57

Puntatori
Passaggio di parametri per riferimento.
In C il passaggio per riferimento non esiste.
Le variabili di tipo puntatore permettono di gestire in
modo esplicito il passaggio di riferimenti.
Se una funzione func deve modificare un parametro a,
deve ricevere il suo indirizzo (e trattarlo di
conseguenza).
void func(int *a) // dimezza il valore di a
{
*a /=2;
}
...
int x=5;
func(&x); // x=2
Corso di Laboratorio di LinguaggiCorso A – p.50/57
Puntatori
Puntatori e vettori.
Se p, x sono un puntatore e un vettore dichiarati come

T x[N ];
T *p;

k è un’espressione intera 0 ≤ k ≤ N − 1 e
p punta a x[0],

p[k ] equivale a x[k ].

Un puntatore si può quindi usare come se fosse un vettore.

Attenzione: se k ≥ N , o k < 0, il risultato di un accesso


a p[k ] è indeterminato.
Corso di Laboratorio di LinguaggiCorso A – p.51/57

Puntatori
Puntatori e vettori.
Ogni variabile di tipo T [] (“vettore di T ”), nella
valutazione delle espressioni, viene convertita in un
puntatore a T .

T x[N ];
T *p;

p=x è equivalente a p=&x[0];


int x[10];
int *p;
p=x; // Punta a x[0]
p[7]=3; // x[7]=3

Attenzione: x=p non è legale. Un vettore non è un puntatore.

Corso di Laboratorio di LinguaggiCorso A – p.52/57


Puntatori
Nella dichiarazione di parametri di funzione, tipi come

T [] e T *

sono sinonimi.
Quindi il passaggio dei vettori che avviene “per
riferimento” non è un’eccezione, ma è conforme alle
regole di valutazione delle espressioni in C e alla
“semantica” dei puntatori.

int func(char *s) ... equivale a


int func(char s[]) ...

Corso di Laboratorio di LinguaggiCorso A – p.53/57

Puntatori
La seguente versione di pos_max è equivalente a quella
già data.
int pos_max(double *v, int n)
{
int i, res;

res=0;
for(i=1; i<n; i++)
if( v[res]<v[i] )
res=i;
return res;
}

Corso di Laboratorio di LinguaggiCorso A – p.54/57


Tipi derivati: typedef
La dichiarazione

typedef T DX ; /* (1) */

dove T è un htypenamei (“tipo base”) e DX è un


dichiaratore (anche complesso) contenente un
identificatore X ,
non crea una variabile di nome X , ma
rende X un htypenamei;
X può essere usato al posto di un htypenamei in
successive dichiarazioni di variabile;
si dice che X è un “tipo derivato”, con tipo-base T .

Corso di Laboratorio di LinguaggiCorso A – p.55/57

Tipi derivati: typedef


La riga

X var;

dichiara var con lo stesso tipo base T e lo stesso


dichiaratore specificato per X in (1); equivale a

T Dvar ;

si sostituisce var a X in DX .

typedef int Bool;/* Definisce un tipo... */


Bool x, y; /* ...crea le variabili */

/* Questo vett[10] e‘ un
dichiaratore di array. */
typedef int vett[10]; Corso di Laboratorio di LinguaggiCorso A – p.56/57

vett x, y; /* Due vettori... */


Tipi derivati: typedef
I dichiaratori possono diventare molto complessi.
L’uso di typedef migliora la leggibilità.

int *(*x[10])(); /* x= array di puntatori a


funzioni che ritornano un puntatore a int. */

typedef int *pint; /* pint=puntatore a intero */


typedef pint func();
/* func=funzione che ritorna pint */
typedef func *pfunc; /* pfunc=puntatore a
funzione che ritorna pint */
typedef func_table pfunc[10];
/* func_table= array di pfunc */
func_table x; /* x= come sopra! */

Corso di Laboratorio di LinguaggiCorso A – p.57/57

Potrebbero piacerti anche