• Non ci sono risultati.

Università degli Studi di Udine

N/A
N/A
Protected

Academic year: 2021

Condividi "Università degli Studi di Udine"

Copied!
28
0
0

Testo completo

(1)

FONDAMENTI DI INFORMATICA

Prof. PIER LUCA MONTESSORO Ing. DAVIDE PIERATTONI

Facoltà di Ingegneria

Università degli Studi di Udine

Le trappole del linguaggio C

(2)

Questo insieme di trasparenze (detto nel seguito slide) è protetto dalle leggi sul copyright e dalle disposizioni dei trattati internazionali. Il titolo ed i copyright relativi alle slides (ivi inclusi, ma non limitatamente, ogni immagine, fotografia, animazione, video, audio, musica e testo) sono di proprietà degli autori prof. Pier Luca Montessoro e ing. Davide Pierattoni, Università degli Studi di Udine.

Le slide possono essere riprodotte ed utilizzate liberamente dagli istituti di ricerca, scolastici ed universitari afferenti al Ministero della Pubblica Istruzione e al Ministero dell’Università e Ricerca Scientifica e Tecnologica, per scopi istituzionali, non a fine di lucro. In tal caso non è richiesta alcuna autorizzazione.

Ogni altro utilizzo o riproduzione (ivi incluse, ma non limitatamente, le riproduzioni su supporti magnetici, su reti di calcolatori e stampe) in toto o in parte è vietata, se non esplicitamente autorizzata per iscritto, a priori, da parte degli autori.

L’informazione contenuta in queste slide è ritenuta essere accurata alla data della pubblicazione. Essa è fornita per scopi meramente didattici e non per essere utilizzata in progetti di impianti, prodotti, reti, ecc. In ogni caso essa è soggetta a cambiamenti senza preavviso. Gli autori non assumono alcuna responsabilità per il contenuto di queste slide (ivi incluse, ma non limitatamente, la correttezza, completezza, applicabilità, aggiornamento dell’informazione).

Nota di Copyright

(3)

Le insidie del C

#include <stdio.h>

main() {

printf ("Hello world");

}

> cc -o hello.exe hello.c

> hello

Hello world> _

(4)

"=" e "=="

if (x = y) /* ... */

Il codice viene eseguito se il valore di y, che viene assegnato alla variabile x, è diverso da 0.

if (x == y) /* ... */

Il codice viene eseguito se il valore di y è uguale a

quello di x.

(5)

Analisi lessicale del programma

Esempi:

• a/*b è interpretato come a /* b , cioè come un commento aperto prima di b, e non come a / (*b), cioè come a diviso il dato indirizzato da b.

• a---b è interpretato come a-- - b , e non come a - --b .

Il compilatore C cerca sempre di costruire

dei token di lunghezza massima.

(6)

Costanti intere

Se una costante inizia per 0 è interpretata come ottale.

struct {

int code;

char *description;

} code_table [] = {

023, "book",

072, "pencil",

112, "rubber"

(7)

La dichiarazione delle funzioni

• float g; variabile floating point g

• float f(); funzione che restituisce un valore float

• float *g; puntatore a float

• float *f(); funzione che restituisce un puntatore a float

• float (*f)(); puntatore a funzione che restituisce un valore float

• float *(*f)(); puntatore a funzione che restituisce un puntatore a float

Attenzione alla precedenza degli operatori!

(8)

Operatore di cast

Si mette tra parentesi la stessa espressione che si usa per la dichiarazione, ma senza l'identificatore della variabile.

float g; g = (float) x;

float *g; g = (float *) x;

float (*h)(); h = (float (*)()) x;

(9)

I tipi nei prototipi delle funzioni

Esempio: la funzione di libreria signal

void (*signal (int, void (*) (int))) (int);

Nel prototipo delle funzioni (ANSI C) si indicano i tipi degli argomenti esattamente come per il cast, ma senza le parentesi intorno.

puntatore a funzione che riceve un int come

parametro e non restituisce nulla ( void )

(10)

Per usare i puntatori

Se puntatori a variabile:

float *g, f; f = *g;

Se puntatori a strutture:

list_element *lep;

lep = lep->next;

x = (*lep).data;

Se puntatori a funzioni:

float (*f)(), g; g = (*f)();

(11)

Precedenze degli operatori

Esempio:

if (flags & FLAGMASK != 0)

non è equivalente a:

if (flags & FLAGMASK)

in quanto != ha la precedenza su &, e quindi risulta:

if (flags & (FLAGMASK != 0))

ovviamente sbagliato.

Non sempre sono quelle che ci si aspetta!

(12)

Precedenze degli operatori

L'operatore di shift è ancora più subdolo:

r = hi<<4 + low;

è interpretato come:

r = hi << (4 + low);

Due possibili versioni corrette sono:

r = (hi << 4) + low;

(13)

Precedenze degli operatori

Due osservazioni importanti:

- ogni operatore logico (es. && ) ha precedenza inferiore a qualsiasi operatore relazionale (es. >= ) - gli operatori di shift hanno precedenza minore degli

operatori aritmetici, ma maggiore di quelli logici.

Attenzione: " == " e " != " hanno precedenza inferiore degli operatori relazionali " > ", " < " ecc. Pertanto:

a < b == b < c significa (a < b) == (b < c)

(14)

Precedenze degli operatori

L'assegnazione viene raggruppata da destra verso sinistra:

home_score = visitor_score = 0;

è equivalente a:

visitor_score = 0;

home_score = visitor_score;

L'assegnazione ha anche minor precedenza degli

operatori di relazione, e quindi nel caso seguente sono

necessarie le parentesi:

(15)

E il punto e virgola?

if (x[i] > big);

big = x[i];

Il compilatore accetta il ";" alla fine dell'if, e ignora l'indentazione. Quindi quanto scritto è equivalente a:

if (x[i] > big) { } big = x[i];

e non a:

if (x[i] > big) big = x[i];

!!!

(16)

E il punto e virgola?

Anche dimenticare un punto e virgola può essere pernicioso:

if (n < 3) return a[0] = p;

a[1] = q;

è interpretato come:

if (n < 3)

(17)

Chiamata di funzione

Il C richiede che la chiamata di una funzione abbia sempre una lista di argomenti, eventualmente vuota:

f();

Tuttavia viene compilato senza errori anche:

f;

Questa espressione non chiama la funzione f,

bensì ne calcola l'indirizzo, e poi lo butta via...

(18)

Else

else si riferisce sempre al più vicino if all'interno dello stesso blocco. Al solito, l'indentazione non è significativa!

if (a)

if (b) f();

else

g();

(19)

Vettori

Possono essere solo unidimensionali.

Su un vettore si possono fare solo due cose:

- definirne la dimensione

- ottenere il puntatore all'elemento 0.

Tutte le altre operazioni sono realizzate mediante puntatori, anche se tramite una sintassi speciale:

v[5] è equivalente a *(v + 5)

(20)

Vettori bidimensionali

int calendar[12][31];

int *month;

int day;

Se si omette l'ultima dimensione si ottiene un vettore (il puntatore al primo elemento):

month = calendar[2];

day = month[30];

oppure

day = calendar[2][30];

(21)

char *r;

r = (char *) malloc

(strlen(s) + strlen(t) + 1);

strcpy (r, s);

strcat (r, t);

/* later... */

free (r);

I puntatori non sono vettori !

char *r;

strcpy (r, s);

strcat (r, t);

char r[100];

strcpy (r, s);

strcat (r, t);

Ancora meglio...

NO! OK

(22)

Conversione automatica di tipo

int strlen (char s[])

è equivalente a scrivere

int strlen (char *s)

Tuttavia questo non si applica in altri contesti:

extern char *str;

non è equivalente a scrivere

extern char str[];

come

char *str = "hello\n";

(23)

Attenzione ai limiti dei vettori

int a[10], i;

for (i = 1; i <= 10; i++) a[i] = 0;

Se la variabile i viene allocata dopo l'ultimo

elemento del vettore, il programma entra in

un loop infinito!

(24)

Ordine di valutazione

Il C garantisce l'ordine di valutazione delle espressioni (a differenza, per esempio, del Pascal).

Quindi si può scrivere:

if (count != 0 && sum/count < low_awg) printf ("average < %g\n", low_avg);

senza ottenere un errore per divisione per zero se

count == 0.

Uso tipico: non viene valutata se

(25)

Ordine di valutazione

Attenzione: non è definito l'ordine di valutazione per qualsiasi operatore.

Per esempio, in

if (f() < g())

può essere chiamata prima la funzione f o la funzione g indifferentemente.

I soli operatori per i quali è garantito l'ordine di valutazione sono:

&& || ?: ,

(26)

Variabili locali

char *strcat (char *s, char *t) {

char r[SIZE];

...

return r;

}

Quando la funzione termina, l'indirizzo della stringa r

viene copiato come valore di ritorno, ma la stringa

stessa è deallocata.

(27)

char *concatena (char str1[], char str2[]) {

int i, j;

char tmp[MAXSIZE];

for (i = 0; str1[i] != '\0'; i++) tmp[i] = str1[i];

for (j = i, i = 0;

str2[i] != '\0'; i++, j++) tmp[j] = str2[i];

return tmp;

}

Esempio

viene restituito il puntatore

alla stringa, ma essa non

esiste più

(28)

Variabili locali

char *strcat (char *s, char *t) {

static char r[SIZE];

...

return r;

}

Due tra le soluzioni possibili:

char r[SIZE];

char *strcat (char *s, char *t) {

...

Riferimenti

Documenti correlati

Le slide possono essere riprodotte ed utilizzate liberamente dagli istituti di ricerca, scolastici ed universitari afferenti al Ministero della Pubblica Istruzione e al Ministero

Le slide possono essere riprodotte ed utilizzate liberamente dagli istituti di ricerca, scolastici ed universitari afferenti al Ministero della Pubblica Istruzione e al Ministero

Ogni altro utilizzo o riproduzione (ivi incluse, ma non limitatamente, le riproduzioni su supporti magnetici, su reti di calcolatori e stampe) in toto o in parte è vietata, se

L’informazione contenuta in queste slide è ritenuta essere accurata alla data della pubblicazione.. Essa è fornita per scopi meramente didattici e non per essere utilizzata in

Le slide possono essere riprodotte ed utilizzate liberamente dagli istituti di ricerca, scolastici ed universitari afferenti al Ministero della Pubblica Istruzione e al Ministero

uguali con il carattere riservato seguito da uno solo dei byte ripetuti più un.. contatore del numero

In ogni caso non può essere dichiarata conformità all’informazione contenuta in queste slide.. In ogni caso questa nota di copyright e il suo richiamo in calce ad ogni slide non

In ogni caso questa nota di copyright e il suo richiamo in calce ad ogni slide non devono mai essere rimossi e devono essere riportati anche in utilizzi parziali.. Nota