anno accademico 2010-2011 1 utilizzo avanzato di array e puntatori

27
Anno accademico 2010-2011 Anno accademico 2010-2011 1 Utilizzo avanzato di array Utilizzo avanzato di array e puntatori e puntatori

Upload: marino-distefano

Post on 02-May-2015

222 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

11

Utilizzo avanzato di array e Utilizzo avanzato di array e puntatoripuntatori

Page 2: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

22

SommarioSommario

• Utilizzo avanzato di array e puntatoriUtilizzo avanzato di array e puntatori Gli array multidimensionaliGli array multidimensionali Gli array di puntatoriGli array di puntatori I puntatori a puntatoriI puntatori a puntatori Allocazione dinamica della memoriaAllocazione dinamica della memoria

Page 3: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

33

• Un array di array è un array multidimensionale array multidimensionale e viene dichiarato per mezzo di una sequenza di coppie di parentesi quadre

• Anche se un array multidimensionale viene memorizzato come una sequenza di elementi, può essere manipolato come un array di array

• Per accedere ad un elemento di un array multidimensionale occorre specificare tanti indici quante sono le dimensioni dell’array

/* x è un array di tre elementi costituiti

* da array di cinque elementi (interi)

*/

int x[3][5];

Gli array multidimensionali Gli array multidimensionali 1 1

Page 4: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

44

• Gli array multidimensionali sono memorizzati con precedenza delle righe, cioè l’ultimo indice varia più velocemente

• Esempio:Esempio:

int ar[2][3]int ar[2][3]{{0,1,2},{{0,1,2},

{3,4,5}{3,4,5}

};};

012

345

1018

100010041008100C10101014

ar[1][0]

ar[1][1]

ar[1][2]

ar[0][0]

ar[0][1]

ar[0][2]

Nell’inizializzazione, ogni riga di valori è racchiusa fra parentesi graffe (in questo caso, servono per migliorare la leggibilità)

Gli array multidimensionali Gli array multidimensionali 2 2

Page 5: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

55

• L’accesso all’elemento ar[1][2]ar[1][2] viene interpretato come *(ar[1]*(ar[1]2)2), ovvero *(*(ar*(*(ar1)1)2)2)

• Poiché arar è un array di array, viene effettuato un doppio scaling: …quando si valuta *(ar*(ar1)1), “1” rappresenta un array di tre interi

(12 byte sulla macchina di riferimento) …quando si valuta *(*(ar*(*(ar1)1)2)2), “2” rappresenta 2 interi (8 byte) complessivamente si ha uno spostamento di 20 byte rispetto

all’indirizzo base (si ottiene l’indirizzo esadecimale 1014) • Se vengono specificati meno indici rispetto alle dimensioni, il

risultato è un puntatore al tipo base dell’array; per esempio…ar[1]ar[1] è equivalente a è equivalente a &ar[1][0]&ar[1][0]

e fornisce come risultato un puntatore ad intpuntatore ad int• Lo standard ANSI non impone limiti al numero di dimensioni degli

array; è comunque richiesto di gestire almeno array a sei dimensioni

Gli array multidimensionali Gli array multidimensionali 3 3

Page 6: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

66

• In fase di inizializzazione di un array multidimensionale, occorre specificare ogni riga tra parentesi graffe

• Se i valori iniziali non sono sufficienti, e l’array è staticstatic, gli elementi mancanti vengono inizializzati a zero

• Esempio:Esempio: static int examp[5][3]static int examp[5][3] { {1,2,3}, { {1,2,3}, {4},{4}, {5,6,7}{5,6,7} };};

• In modo analogo al caso dei vettori, se viene “parzialmente” omessa la dichiarazione della dimensione di un array multidimensionale, il compilatore la calcola sulla base del numero dei valori iniziali specificati

)(0 0 0 0 0 0

1 2 3 4 0 0 5 6 7

L’inizializzazione di L’inizializzazione di array multidimensionali array multidimensionali 1 1

Page 7: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

77

• Nel caso degli array multidimensionali, infatti, può essere omessa la dimensione dell’array più esterno, mentre è obbligatorio specificare le altre

• Esempio:Esempio: static int a_ar[][2] static int a_ar[][2] {{1,1},{0,0},{1,2}}; {{1,1},{0,0},{1,2}};

produce un array di dimensione 32, perché sono presenti 6 valori iniziali

• Esempio:Esempio:static int b_ar[][]static int b_ar[][]{{1,2,3},{4,5,6}}; /*SCORRETTO*/{{1,2,3},{4,5,6}}; /*SCORRETTO*/

Non si può determinare se l’array è 32 o 23 (il raggruppamento dei dati di inizializzazione non è sufficiente!): specificare la seconda dimensione avrebbe risolto ogni ambiguità

L’inizializzazione di L’inizializzazione di array multidimensionali array multidimensionali 2 2

Page 8: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

88

• Per passare un array multidimensionale come argomento di funzione è sufficiente specificarne il nome: il valore passato è un puntatore all’elemento iniziale dell’array che è ancora un array

• Nella funzione chiamata, l’argomento deve essere dichiarato in modo appropriato

• È possibile omettere la dimensione dell’array che viene passato, ma è necessario specificare la dimensione di ogni elemento dell’array

Array multidimensionali comeArray multidimensionali comeargomenti di funzione argomenti di funzione 1 1

int f1()int f1(){{ static int ar[5][6];static int ar[5][6]; … … … … … … f2(ar);f2(ar); … … … … … …}} int (*received_arg)[6];int (*received_arg)[6];

void f2(received_arg)void f2(received_arg)int received_arg[][6];int received_arg[][6];{{ … … … … … …}}

Page 9: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

99

• Una modalità alternativa consiste nel passare esplicitamente un puntatore al primo elemento e la dimensione dell’array

• Il vantaggio di questo approccio è la flessibilità: non occorre conoscere a priori la dimensione degli elementi dell’array; occorre però calcolare manualmente l’aritmetica degli indici: received_arg[x][y] received_arg[x][y] è memorizzato all’indirizzo

received_arg received_arg x xdim2 dim2 y y

int f1()int f1(){{ static int ar[5][6];static int ar[5][6]; … … … … … … f2(ar,5,6);f2(ar,5,6); … … … … … …}}

void void f2(received_arg,dim1,dim2)f2(received_arg,dim1,dim2)int **received_arg;int **received_arg;int dim1,dim2;int dim1,dim2;{{ … … … … … …}}

È un puntatore a unpuntatore a un puntatore puntatore aa intint

Array multidimensionali comeArray multidimensionali comeargomenti di funzione argomenti di funzione 2 2

Page 10: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1010

• Scrivere una funzione che determina il tipo del risultato di un’espressione binaria in base ai tipi degli operandi

La funzione riceve due argomenti interi che rappresentano i tipi degli operandi e fornisce un intero che rappresenta il tipo del risultato

include <stdio.h>

typedef enum {SPECIAL2, ILLEGAL, INT, FLOAT, DOUBLE, POINTER, LAST} TYPES;

TYPES type_needed(type1,type2)TYPES type1, type2;{static TYPES result_type[LAST][LAST] {

/* int float double pointer */ /*int*/ INT, FLOAT, DOUBLE, POINTER,/*float*/ FLOAT, FLOAT, DOUBLE, ILLEGAL,/*double*/ DOUBLE, DOUBLE, DOUBLE, ILLEGAL,/*pointer*/ POINTER, ILLEGAL, ILLEGAL, SPECIAL}; TYPES result result_type[type1][type2];

if (result ILLEGAL) printf(“Operazione scorretta su puntatori\n”); return result;}

Esempio Esempio 1 1

Page 11: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1111

• La parte principale del programma è costituita dalla dichiarazione ed inizializzazione dell’array result_typeresult_type: Ogni tipo di dati viene fatto corrispondere ad un valore

intero per mezzo della dichiarazione enumenum• In base alle modalità di definizione dell’array

bidimensionale, i due valori di ingresso sono indici, che individuano univocamente l’elemento dell’array corrispondente al tipo del risultato

• La dichiarazione enumenum assicura che ogni costante venga associata ad un unico valore intero e che LASTLAST rappresenti il numero totale di tipi (viene usato nella dichiarazione dell’array)

Esempio Esempio 2 2

Page 12: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1212

• La stessa dichiarazione (almeno per il compilatore) avrebbe potuto essere scritta per mezzo di interi

char result_type[4][4]char result_type[4][4]{0,1,2,3,1,1,2,{0,1,2,3,1,1,2,1,2,2,2,1,2,2,2,1,3,1,3,1,1,1,1,2};2};

diminuendo sensibilmente la comprensibilità e la mantenibilità

del programma

• Nel caso SPECIALSPECIAL, l’operazione è corretta solo se i puntatori riferiscono oggetti dello stesso tipo e l’operatore è il segno meno: il risultato è un intint

Esempio Esempio 3 3

Page 13: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1313

ar[1,2] ar[1,2] 0; /* Lecito, ma probabilmente scorretto */ 0; /* Lecito, ma probabilmente scorretto */

ar[1][2] ar[1][2] 0; /* Corretto */ 0; /* Corretto */

• Nella prima istruzione… …la virgola viene interpretata come operatore, si valuta

quindi espressione1espressione1, che vale 1 ed il cui risultato non viene utilizzato e, successivamente, espressione2espressione2, che vale 2 (le due espressioni sono costanti)

…si ottiene l’accesso ad ar[2]ar[2]

• Se arar è un array bidimensionale di intint, ar[2]ar[2] è un puntatore ad intpuntatore ad int (costante, ma potrebbe anche essere non valido)

Viene segnalato un errore di incompatibilità di tipo: fuorviante dato che la causa dell’errore è l’uso della virgola

Errori di accesso ad array Errori di accesso ad array multidimensionalimultidimensionali

Page 14: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1414

• Si consideri la dichiarazione:

char *ar_of_p[5];char *ar_of_p[5];

La variabile ar_of_par_of_p è un array di cinque elementi di tipo puntatore a carattere e nonnon un puntatore ad un array di cinque caratteri

• L’operatore di accesso all’elemento di un array “[]” ha precedenza superiore all’operatore di accesso all’indirizzo contenuto in un puntatore

• I puntatori non sono stati inizializzati, per cui puntano a posizioni di memoria qualsiasi

Gli array di puntatori Gli array di puntatori 1 1

Page 15: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1515

• Esempio:Esempio:

char *ar_of_p[5];char *ar_of_p[5];

char c0=‘a’;char c0=‘a’;

char c1=‘b’;char c1=‘b’;

ar_of_p[0]=&c0;ar_of_p[0]=&c0;

ar_of_p[1]=&c1;ar_of_p[1]=&c1;

ar_of_p[0]

ar_of_p[1]

ar_of_p[2]

ar_of_p[3]

1014

20002000

996

1004

1008

100C

1010

20012001

non definitonon definito

non definitonon definito

non definitonon definito

ar_of_p[4]

1000

c1

2002

c0

1FFF

2000

2001bb

aa

Gli array di puntatori Gli array di puntatori 2 2

Page 16: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1616

• Gli array di puntatoriarray di puntatori vengono usati per gestire array di stringhe

• Esempio: Esempio: Realizzare una funzione che, dato un intero compreso fra 1 e 12, in ingresso, stampa il nome del mese corrispondente

include <stdio.h>include <stdlib.h>char *month_text(m)int m;{ static char *month[13] {“Badmonth”, “January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November”, “December” }; if (m>12) { printf(“Valore scorretto”); exit(1); } return month[m];}

Esempio array di puntatori Esempio array di puntatori 1 1

Page 17: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1717

• La variabile monthmonth è un array di puntatori a char puntatori a char costituito da 13 elementi: come conseguenza dell’inizializzazione, ogni puntatore fa riferimento all’elemento iniziale di una stringa

• La motivazione dell’uso di un puntatore aggiuntivo con un valore inutile consiste nel non voler effettuare sottrazioni dall’indice: è comune non utilizzare l’elemento iniziale di un array quando il valore dell’indice comincia logicamente da 1

• Non definendo “Badmonth”“Badmonth”, si dovrebbe cambiare l’istru-zione di ritorno al chiamante in

return month[mreturn month[m1];1];

Esempio array di puntatori Esempio array di puntatori 2 2

Page 18: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2009-2010Anno accademico 2009-2010

1818

NotaNota::

• I caratteri che costituiscono una stringa devono essere consecutivi

• Le stringhe corrispondenti ai nomi dei mesi vengono memorizzate dal compilatore in qualunque posizione libera della memoria

2000

2009

2011

2500

2800

3000

3006

300A

300F

4000

400A

4011

401A

month[0]

month[1]

month[2]

month[3]

month[4]

month[5]

month[6]

month[7]

month[8]

month[9]

month[10]

month[11]

month[12]

1000

1004

1008

100C

1010

1014

1018

101C

1020

1024

1028

102C

1030

‘B’

‘a’

‘d’

‘m’

‘o’

‘n’

‘t’

‘h’

‘\0’

‘J’

‘a’

‘n’

‘u’

‘a’

‘r’

‘y’

‘\0’

‘F’

‘e’

‘b’

‘r’

‘u’

‘a’

‘r’

‘y’

‘\0’

‘M’

‘a’

‘r’

‘c’

‘h’

‘\0’

2000

2001

2002

2003

2004

2005

2006

2007

2008

2009

200A

200B

200C

200D

200E

200F

2010

2011

2012

2013

2014

2015

2016

2017

2018

2019

2500

2501

2502

2503

2504

2505

Esempio array di puntatori Esempio array di puntatori 3 3

Page 19: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

1919

• I puntatori a puntatoripuntatori a puntatori sono costrutti usati in programmi sofisticati: per dichiarare un puntatore a puntatore occorre far precedere il nome della variabile da due asterischi consecutivi

int **p;int **p;dichiara pp come puntatore ad unpuntatore ad un puntatore ad intpuntatore ad int

• Per accedere al valore dell’intint, è necessario utilizzare i doppi asterischi:

j j **p; **p; assegna un intero a jj

I puntatori a puntatori I puntatori a puntatori 1 1

Page 20: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2020

• Esempio:Esempio:

int r int r 5; 5;

int *q int *q &r; &r;

int **p int **p &q; &q;

È possibile assegnare valori ad rr come: rr10; /*Assegnamento diretto*/10; /*Assegnamento diretto*/

*q*q10; /*Assegnamento10; /*Assegnamento concon unun livellolivello didi indirezione*/indirezione*/

**p**p10; /*Assegnamento10; /*Assegnamento concon duedue livellilivelli didi indirezione*/indirezione*/

4 byte

r

q

p

5

1004

99C

100C

99C

1004

I puntatori a puntatori I puntatori a puntatori 2 2

Page 21: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2121

/* Codice per la costruzione di I (matrice identità) */

#include<stdlib.h>#include<stdio.h>

main(){int id[100][100];int n, i, j;

printf(“Introdurre la dimensione della matrice identità\n”);scanf(“%d”, &n);

for (i0; in; i) for (j0; jn; j) id[i][j] (ij)?1:0;exit(0);}

Esempio 1: Matrice identitàEsempio 1: Matrice identità

Page 22: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2222

/* Si valuta se a è simmetrica… */ sim 1; r 0; do { c r 1; do { if (a[r][c] ! a[c][r]) sim 0; c; } while (c<DIM && sim1); r; } while (r<DIM1 && sim1);

if (sim1) printf(“Matrice simmetrica”); else printf(“Matrice non simmetrica”); exit(0);}

Esempio 2: Matrice simmetricaEsempio 2: Matrice simmetrica/* Si legge una matrice quadrata ** composta da numeri reali** e si stabilisce se è simmetrica*/

#include <stdio.h>#include <stdlib.h>#define DIM 100

main(){ char r, c, sim; float a[DIM][DIM];

/* Lettura della matrice a */ for(r0;rDIM;r) { for(c0;c<DIM;c) scanf(“%f”,&a[r][c]); }

Page 23: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2323

/* Funzione per il calcolo di Ab, con…** A: matrice mn di float (in input)** b: vettore di dimensione n di float (in input) ** m, n: interi, numero di righe e colonne di A (in input)** x: vettore di float di dimensione m, risultato (in output) */

float *prod_mv(a, b, m, n, x)float a[][100], b[], x[]; /* ma, nella funzione, sono puntatori */int m, n;{ int i, j;

for (i0; im; i) { x[i] 0.0; for (j0; jn; j) x[i] a[i][j]b[j]; } return x;}

Esempio 3: Prodotto Esempio 3: Prodotto matricematricevettorevettore

Page 24: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2424

Esempio 4: Prodotto Esempio 4: Prodotto matricematricematricematrice

• ProblemaProblemaCalcolo della matrice prodotto AB, con A e B matrici rettangolari di dimensioni, rispettivamente, mn e nc

Page 25: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2525

• Dichiarare array equivale a fare un’ipotesi (una stima) sulla dimensione massima possibile dei vettori che potranno essere fonte di elaborazione per il particolare programma

Si suppone di conoscere la quantità di memoria da allocare nel momento in cui si scrive il codice sorgente Generalmente si sovrastima, quindi si spreca memoria Se la stima è sufficientemente stringente per la

situazione corrente, può essere una sottostima per il futuro (occorre aggiornare il sorgente)

• Di norma, l’occupazione di memoria dipende Di norma, l’occupazione di memoria dipende strettamente dai dati in ingressostrettamente dai dati in ingresso

L’allocazione dinamica della L’allocazione dinamica della memoria memoria 1 1

Page 26: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2626

• In C, esistono quattro funzioni della libreria di runtime (stdlib.hstdlib.h) che permettono l’allocazione allocazione dinamica della memoriadinamica della memoria malloc() malloc() alloca un numero specificato di byte in

memoria e restituisce un puntatore all’inizio del blocco allocato

calloc()calloc() come malloc()malloc(), ma inizializza a zero i byte allocati; consente di allocare la memoria per più di un oggetto alla volta

realloc()realloc() cambia la dimensione di un blocco preceden-temente allocato

free()free() libera la memoria che era stata allocata con malloc()malloc(), calloc()calloc() o realloc()realloc()

L’allocazione dinamica della L’allocazione dinamica della memoria memoria 2 2

Page 27: Anno accademico 2010-2011 1 Utilizzo avanzato di array e puntatori

Anno accademico 2010-2011Anno accademico 2010-2011

2727

• Esempio:Esempio:

• L’argomento di malloc()malloc() è la dimensio-ne in byte del blocco da allocare

• Usando calloc()calloc(), l’istruzione di alloca-zione della memoria sarebbe

list=(int*)calloc(sort_num,sizeof(int));list=(int*)calloc(sort_num,sizeof(int));

• La funzione calloc()calloc() accetta due argo-menti: il primo è il numero di oggetti a cui riservare memoria, il secondo è la dimensione di ciascun oggetto

• Le funzioni malloc() malloc() e calloc() calloc() me-morizzano gli elementi in modo contiguo in un singolo blocco

include <stdio.h>include <stdlib.h>

main()

{

extern void bubble_sort();

int *list, j, sort_num;

printf(“Numero dei valori da introdurre:”);

scanf(“%d”, &sort_num);

list(int *)malloc(sort_numsizeof(int)); for (j0; j<sort_num; j) scanf(“%d”, listj); bubble_sort(list, sort_num);

exit(0);

}

L’allocazione dinamica della L’allocazione dinamica della memoria memoria 3 3