Upload
drago-brunetti
View
221
Download
1
Embed Size (px)
Citation preview
Anno accademico 2010-2011Anno accademico 2010-2011
11
Array e puntatori in CArray e puntatori in C
Anno accademico 2010-2011Anno accademico 2010-2011
22
SommarioSommario
• Gli array ed i puntatoriGli array ed i puntatori Dichiarazione e memorizzazione di arrayDichiarazione e memorizzazione di array L’inizializzazione di arrayL’inizializzazione di array L’aritmetica dei puntatoriL’aritmetica dei puntatori Il passaggio di puntatori come argomenti di Il passaggio di puntatori come argomenti di
funzionefunzione Gli algoritmi di ordinamentoGli algoritmi di ordinamento
• Le stringheLe stringhe
Anno accademico 2010-2011Anno accademico 2010-2011
Gli array ed i puntatoriGli array ed i puntatori
33
Anno accademico 2010-2011Anno accademico 2010-2011
• Nel linguaggio C, un arrayarray è un insieme di variabili dello stesso tipo memorizzate consecutivamente
• Ogni variabile dell’array, detta elementoelemento, può essere acceduta mediante il nome dell’array ed un indiceindice (un espressione), con il primo elemento individuato dall’indice di valore 0
• Esempio:Esempio: Memorizzare la temperatura media registrata per ogni giorno dell’anno Si dichiara un array di 365 elementi (piuttosto che 365
variabili!), identificati con un solo nome, e che occupano posizioni di memoria consecutive
• Nota:Nota: Gli array contengono informazione correlata (le temperature di un anno, i voti di esame di uno studente, etc.)
Gli arrayGli array
44
Anno accademico 2010-2011Anno accademico 2010-2011
• La sintassi della dichiarazione di arraydichiarazione di array è:
• La dichiarazione viene effettuata inserendo una coppia di parentesi quadre dopo il nome dell’array
• La dimensione dell’array viene specificata inserendo il numero di elementi all’interno delle parentesi quadre
La dichiarazione di array La dichiarazione di array 1 1
Valori inizialiValori iniziali
SpecificatorSpecificatore di tipoe di tipo
}}
[[Nome Nome dell’arraydell’array
Dimensione Dimensione dell’arraydell’array
==
]]
{{
55
Anno accademico 2010-2011Anno accademico 2010-2011
• Il riferimento ad un elemento dell’arrayriferimento ad un elemento dell’array è invece l’operazione di accesso al dato elemento ed avviene utilizzando il nome dell’array seguito dall’indice dell’elemento (racchiuso fra parentesi quadre)
• Le istruzioni di dichiarazione di un array e di riferimento ad un elemento dell’array sono molto simili nella forma, ma molto diverse nel significato
/* I seguenti sono riferimenti a elementi
* dell’array; i valori 0,1,2,…
* specificano gli elementi cui accedere
*/
daily_temp[0] 2;daily_temp[1] 5;daily_temp[2] 3;… … …
/* La seguente è una dichiarazione;
* il valore 365 specifica il numero
* di elementi dell’array
*/
int daily_temp[365];
La dichiarazione di array La dichiarazione di array 2 2
66
Anno accademico 2010-2011Anno accademico 2010-2011
• Esempio:Esempio: Calcolo della temperatura media annua
include <stdio.h>include <stdlib.h>define DAYS_IN_YEAR 365
main()
{
int j, sum0; int daily_temp[DAYS_IN_YEAR];
/* si assegnano i valori a daily_temp[] */
for (j0; j<DAYS_IN_YEAR; j) sum daily_temp[j]; printf(“La temperatura media dell’anno è %d.\n”, sum/DAYS_IN_YEAR);
exit(0);
}
La dichiarazione di array La dichiarazione di array 3 3
77
Anno accademico 2010-2011Anno accademico 2010-2011
• EsempioEsempio
• ar[2] e ar[4] sono indefiniti: il contenuto delle posizioni di memoria è quello rimasto da esecuzioni precedenti (garbagegarbage)
int ar[5]; /* dichiarazione */int ar[5]; /* dichiarazione */
ar[0] ar[0] 15; 15;
ar[1] ar[1] 17; 17;
ar[3] ar[3] 3 3;;ar[4]
ar[0]ar[1]ar[2]ar[3]
1018
0FFC100010041008100C10101014
33
15151717
non non definitodefinito
non non definitodefinito
4 byte
La memorizzazione di arrayLa memorizzazione di array
88
Anno accademico 2010-2011Anno accademico 2010-2011
• La presenza di valori indefiniti in alcuni elementi dell’array può provocare errori difficili da rilevare
Occorre inizializzare l’intero vettore
Dichiarare l’array staticstatic (vettore a durata fissaa durata fissa): gli elementi del vettore, non inizializzati esplicitamente, vengono posti a zero
Valori diversi possono essere specificati, facendoli seguire alla dichiarazione dell’array, racchiusi fra parentesi graffe: tali valori devono essere espressioni costanti che possano essere convertite automaticamente nel tipo dell’array
99
L’inizializzazione di array L’inizializzazione di array 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• EsempioEsempio
• Nota:Nota: il valore floatingpoint 3.5 viene convertito nel valore intero 3
1028
0FFC100010041008100C10101014
4 byte
1018101C10201024 br[4]
br[0]br[1]br[2]br[3]
ar[4]
ar[0]ar[1]ar[2]ar[3]
55
1517
non definito
00
0000
00 00 11 22 33 44
static int ar[5]; static int ar[5];
static int br[5]static int br[5]{1,2,3.5,4,5};{1,2,3.5,4,5};
1010
L’inizializzazione di array L’inizializzazione di array 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Specificare un numero maggiore di valori di inizializzazione, rispetto agli elementi dell’array, costituisce un errore segnalato dal compilatore
• Se vengono specificati meno valori rispetto alla dimensione, gli elementi rimanenti vengono inizializzati a zero
• Esempio:Esempio: La dichiarazione
static int cr[5] static int cr[5] {1,2,3}; {1,2,3};
produce l’inizializzazionecr[0] 1cr[1] 2cr[2] 3cr[3] 0cr[4] 0 1111
L’inizializzazione di array L’inizializzazione di array 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
• Se vengono specificati i valori iniziali, può essere omessa la dimensione dell’array: il compilatore calcola automatica-mente il numero degli elementi sulla base del numero dei valori iniziali specificati
• Esempio:Esempio:
static char dr[] static char dr[] {‘a’,‘b’,‘c’,‘d’}; {‘a’,‘b’,‘c’,‘d’};
comporta la creazione di un array di quattro elementi, di tipo charchar, caratterizzati dai valori iniziali
dr[0] ‘a’dr[1] ‘b’dr[2] ‘c’dr[3] ‘d’
1212
L’inizializzazione di array L’inizializzazione di array 4 4
Anno accademico 2010-2011Anno accademico 2010-2011
• Poiché in formato elettronico viene memorizzato e trasmesso ogni tipo di informazione (anche personale, quindi coperta da privacy), viene posta attenzione alla sicurezza rispetto ad accessi indesiderati
• I file, nei sistemi multiutente, sono provvisti di vari livelli di protezione, il primo dei quali è costituito dall’autenticazione al sistema tramite password
• Oltre ai tipi di protezione standard, il contenuto di un file riservato può essere codificato, utilizzando tecniche crittografiche che producono, a partire dal testo in chiaro, il cosiddetto crittogrammacrittogramma, o testo cifrato
• Il legittimo proprietario del file (e chi da lui autorizzato) è l’unico depositario della chiave di decodifica ed è l’unico in grado di operare l’inversione da testo cifrato a testo in chiaro 1313
Crittografia Crittografia 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Inoltre, negli attuali sistemi informativi distribuiti, e più in generale nel settore delle telecomunicazioni, la crittografia ha assunto rilievo ed interesse crescenti nelle infrastrutture di sicurezza
1414
Crittografia Crittografia 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Se il sistema di cifra, o cifrariocifrario, è ben congegnato, l’operazione di decifrazionedecifrazione o decifratura deve risultare semplice al legittimo proprietario (o al destinatario del messaggio), ma di complessità proibitiva alla “spia”
possibile in quanto gli utenti “legittimi” possiedono un’informazione che deve rimanere inaccessibile alla spia, la chiave del cifrariochiave del cifrario
• Occorre notare la distinzione tra decifrazione e decrittazionedecrittazione, l’operazione illegittima in cui non ci si può avvalere della chiave
1515
Crittografia Crittografia 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
/* Dato un carattere, ne fornisce un valore codificato */define ILLEGAL_VAL 1
char encode(ch)char ch;{ static unsigned char encoder[128] {127,124,121,118,115,112, 109,106,103,100,97,94,91,88,85,82,79,76,73,70,67,64,61, 58,55,52,49,46,43,40,37,34,31,28,25,22,19,16,13,10,7,4, 1,126,123,120,117,114,111,108,105,102,99,96,93,90,87,84, 81,78,75,72,69,66,63,60,57,54,51,48,45,42,39,36,33,30, 27,24,21,18,15,12,9,6,3,0,125,122,119,116,113,110,107, 104,101,98,95,92,89,86,83,80,77,74,71,68,65,62,59,56,53, 50,47,44,41,38,35,32,29,26,23,20,17,14,11,8,5,2}
/* Controlla la presenza di caratteri illeciti */ if (ch > 127) return ILLEGAL_VAL; else return encoder[ch]; /* Fornisce il carattere codificato */}
48=‘0’ 48=‘0’ 111=‘o’111=‘o’
CiaoCiao
6D\56D\5
1616
Crittografia Crittografia 4 4
Anno accademico 2010-2011Anno accademico 2010-2011
• Il codice Shift CypherShift Cypher con K3 era utilizzato da Giulio Cesare
Esercizio:Esercizio: Con K11, si somma 11 al valore corrispondente alla lettera e, nel caso che la somma superi 25, si divide il numero per 26 e si considera il resto della divisione intera
we will meet at midnightwe will meet at midnight
22 4 22 8 11 11 12 4 4 19 0 19 12 8 3 13 8 6 7 19
7 15 7 19 22 22 23 15 15 4 11 4 23 19 14 24 19 17 18 4
hphtwwxppelextoytrsehphtwwxppelextoytrse
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
1717
Crittografia Crittografia 5 5
Anno accademico 2010-2011Anno accademico 2010-2011
/* Dato un vettore, stabilisce se vi sono almeno due elementi uguali tra loro */
#define MAX_DIM 256typedef int[MAX_DIM] VECTOR;
int TwinSearch (v) /* ricerca degli elementi gemelli */VECTOR v;{ int c 0; int k 0; int found 1; /* ricerca senza successo ritorna 1 */
for(c 0; ((c < (MAX_DIM1)) && (found 1)); c) { for(k (c1); ((k < MAX_DIM) && (found 1)); k) { if (v[c] v[k]) found 1; /* ricerca con successo */ } }
return found;}
1818
Esempio Esempio 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
/* Inverte gli elementi di un vettore */
#include <stdio.h>
int main()
{
/*dichiarazioni*/
int a[10], b[10];
int i, dim10;
/*input elementi*/
for(i0;i<dim;i) {
printf(“inserire l’elemento a[%d]: ”,i);
scanf(“%d”, &a[i]);
}
/*stampa vettore*/
printf(“\nIl vettore è:\n\n”);
for(i0;i<dim;i) printf(“a[%d] %d\n”, i, a[i]); printf(“\n”);
/*inversione vettore*/ for(i0;i<dim;i) b[i]a[dim1i];
/*stampa vettore invertito*/ printf(“Il vettore invertito è:\n\n”);
for(i0;i<dim;i) printf(“b[%d] %d\n”, i, b[i]);
return 0; }
1919
Esempio Esempio 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Il C permette l’utilizzo degli operatori additivi in concomitanza con i puntatori
• Se pp è un puntatore, l’espressione pp33 è lecita ed individua il terzo oggetto che segue quello puntato da pp
• Poiché pp contiene un indirizzo, operazioni aritmetiche su pp forniscono nuovi indirizzi
• Il compilatore non opera semplicemente una somma tra 3 e pp, ma moltiplica 3 per la dimensione dell’oggetto puntato da pp: effettua cioè uno scalingscaling
• Esempio:Esempio: Se l’indirizzo contenuto in pp è 1000 e pp è un puntatore a long intlong int, allora pp33 identifica l’indirizzo 1018 (8 byte per gli interi lunghi); se pp è un puntatore a charchar, pp33 rappresenta l’indirizzo 1003
2020
L’aritmetica dei puntatori L’aritmetica dei puntatori 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Nell’ipotesi di puntatori che si riferiscono allo stesso tipo di dato, è lecito sottrarre il valore di un puntatore da un altro: l’operazione fornisce un valore intero che rappresenta il numero di oggetti compresi fra i due puntatori
• Se il primo puntatore è relativo a un indirizzo inferiore al secondo, il risultato è un intero negativo
• È lecito anche sottrarre un valore intero da un puntatore: il risultato è un puntatore
&a[0]&a[3] 3&a[3]&a[0] 3
2121
L’aritmetica dei puntatori L’aritmetica dei puntatori 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• EsempioEsempio
long *p1, *p2, k;long *p1, *p2, k;
int j;int j;
char *p3; char *p3;
p1p1&k;&k;
p2p2p1p1 4; /* OK */4; /* OK */
jjp2p2p1; /* OK a j viene assegnato 4 */p1; /* OK a j viene assegnato 4 */
jjp1p1p2; /* OK a j viene assegnato p2; /* OK a j viene assegnato 4 */4 */
p1p1p2p22; /* OK tipi dei puntatori compatibili */2; /* OK tipi dei puntatori compatibili */
p3p3p1p11; /* NO tipi diversi di puntatori */1; /* NO tipi diversi di puntatori */
jjp1p1p3; /* NO tipi diversi di puntatori */p3; /* NO tipi diversi di puntatori */2222
L’aritmetica dei puntatori L’aritmetica dei puntatori 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
• Il linguaggio C prevede la definizione di puntatori nullipuntatori nulli, ovvero di puntatori che non puntano ad alcun oggetto valido
• Un puntatore nullo è un qualsiasi puntatore a cui sia assegnato il valore zero
char *p;char *p;
pp0; /* rende p un puntatore nullo */0; /* rende p un puntatore nullo */
In questo caso il compilatore non effettua la conversione esplicita dell’espressione intera nel tipo del puntatore
• La definizione del puntatore nullo è utile all’interno di istruzioni di controllo: il puntatore nullo è l’unico puntatore cui è associato il valore FALSE; tutti i puntatori validi valgono TRUE 2323
L’aritmetica dei puntatori L’aritmetica dei puntatori 4 4
Anno accademico 2010-2011Anno accademico 2010-2011
• Il compilatore segnala i tentativi di utilizzo congiunto di puntatori di tipi diversi
• Un’eccezione alla regola è costituita dall’uso di puntatori come argomenti di funzione: in mancanza di un prototipoprototipo, il compilatore non effettua controlli per verificare la corrispondenza di tipo fra parametro attuale e parametro formale
si possono produrre risultati inconsistenti nel caso di parametri di tipo disomogeneo
• Il prototipoprototipo di una funzione è una dichiarazione di funzione antecedente alla sua definizione: permette al compilatore di compiere il controllo sui tipi degli argomenti che vengono passati alla funzione
2424
Il passaggio di puntatori come Il passaggio di puntatori come argomenti di funzione argomenti di funzione 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
include <stdio.h>include <stdlib.h>
void clr(p)
int *p;
{
*p 0 /* Memorizza 0 alla locazione p */}
main()
{
static short s[3] {1,2,3};
clr(&s[1]); /* Azzera l’elemento 1 di s[] */
printf(“s[0]%d\ns[1]%d\ns[2]%d\n”, s[0],s[1],s[2]); exit(0);
}
s[0]1
s[1]2
s[2]3
s[0]1
s[1]0
s[2]0
pp è un puntatore a int int vengono azzerati 4 byte, quindi sia s[1] s[1] che s[2]s[2]
2525
Il passaggio di puntatori come Il passaggio di puntatori come argomenti di funzione argomenti di funzione 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• È possibile accedere agli elementi di un array attraverso…
…l’uso del nome dell’array con il relativo indice
…l’uso dei puntatori
• Infatti vale la regola che…
Aggiungere un intero ad un puntatore all’inizio di un Aggiungere un intero ad un puntatore all’inizio di un array, ed accedere all’indirizzo puntato array, ed accedere all’indirizzo puntato dall’espressione, equivale ad utilizzare l’intero come dall’espressione, equivale ad utilizzare l’intero come indice dell’arrayindice dell’array
• Inoltre, un nome di array non seguito da un indice viene interpretato come un puntatore all’elemento iniziale dell’array
ar è equivalente a &ar[0]
Se p&ar[0] *(pe) è equivalente a ar[e]
2626
L’accesso agli elementi di array L’accesso agli elementi di array mediante puntatori mediante puntatori 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Combinando le due relazioni, si ottiene la regola generale
• Un nome di array viene trasformato dal compilatore C in un puntatore all’elemento iniziale dell’array e quindi gli indici vengono interpretati come spostamenti dalla posizione di indirizzo base indirizzo base
• In considerazione del meccanismo di scaling, lo spostamento determina il numero di elementi da oltrepassare
• Esempio:Esempio:
ar[n] equivale a *(arn)
ar[2] ar[2] *(ar*(ar2)2)
Sono equivalenti: in entrambi i casi, arar è un puntatore all’elemento iniziale dell’array e 2 è un fattore di spostamento che richiede al compilatore di aggiungere due al valore del puntatore 2727
L’accesso agli elementi di array L’accesso agli elementi di array mediante puntatori mediante puntatori 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Tuttavia… …i valori delle variabili puntatore possono essere
modificati …i nomi di array non sono variabili, ma riferimenti a
indirizzi delle variabili array e, come tali, non possono essere modificati
• Un nome di array non associato ad un indice o ad un operatore “accesso all’indirizzo di” (**) non può apparire alla sinistra di un operatore di assegnamentofloat ar[7], *p;
par; /* OK equivale a p&ar[0] */arp; /* NO assegnamento su un indirizzo di array */∥ /* NO assegnamento su un indirizzo di puntatore */ar; /* NO: non è possibile incrementare un indirizzo di array */ar[1]*(p5); /* OK ar[1] è una variabile */p; /* OK è possibile incrementare una variabile puntatore */ 2828
L’accesso agli elementi di array L’accesso agli elementi di array mediante puntatori mediante puntatori 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
• In C, un nome di array, utilizzato come argomento di funzione, viene interpretato come indirizzo del primo elemento dell’array
• EsempioEsempio
Nella funzione chiamata è necessario dichiarare l’argomento come un puntatore all’elemento iniziale di un array
main()main()
{{
extern float func();extern float func();
float x;float x;
static float farray[5]; static float farray[5];
x x func(farray) /* equivalente a: func(&farray[0]) */ func(farray) /* equivalente a: func(&farray[0]) */
… … … … … …
func(ar)func(ar)float ar[];float ar[];{{ … … … … … …}}
func(ar)func(ar)float *ar;float *ar;{{ … … … … … …}}
Non è specificata la dimensione perché non si alloca memoria
2929
Il passaggio di array Il passaggio di array come argomenti di funzione come argomenti di funzione 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Anche nel secondo caso, ciò che viene passato è un puntatore al primo elemento dell’array ed il compilatore è in grado di convertire automaticamente arar in un puntatore a floatfloat
• In termini di leggibilità, la seconda versione è preferibile, poiché evidenzia che l’oggetto passato è l’indirizzo di base di un array e non un generico puntatore a una variabile floatfloat (scalare o composta?)
• La dichiarazione della dimensione dell’array nella definizione dell’argomento è comunque corretta: il compilatore può usare l’informazione sulla dimensione per effettuare controlli sui valori limite
3030
Il passaggio di array Il passaggio di array come argomenti di funzione come argomenti di funzione 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Non è possibile ottenere la dimensione di un array all’interno di una funzione cui viene passato come argomento, ma solo laddove l’array è effettivamente dichiarato
include <stdio.h>include <stdlib.h>
void print_size(arg)
float arg[];{ printf(“La dimensione di arg è: %d\n”,sizeof(arg));}
main(){ void print_size(); static float f_array[10];
printf(“La dimensione di f_array è: %d\n”,sizeof(f_array)); print_size(f_array); exit(0);}
Sulla macchina di riferimento, l’esecuzione del programma fornisce:
La dimensione di f_array è: 40
La dimensione di arg è: 4
3131
Il passaggio di array Il passaggio di array come argomenti di funzione come argomenti di funzione 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
• Il compilatore, di solito, non controlla che l’accesso agli elementi di un array venga effettuato rispettandone i limiti dimensionali
È possibile accedere per errore ad elementi per i quali non è stata allocata memoria (aree di memoria riservate ad altre variabili, riservate ad altri processi, etc.)
• Esempio:Esempio:
main()
{
int ar[10], j;
for(j0; j<10; j) ar[j] 0;}
Essendo ar ar un array di 10 elementi, quelli cui è possibile accedere in modo corretto hanno indice da 0 a 9: il ciclo for for contiene un errore offoffbybyoneone
Probabilmente verrebbe azzerata la variabile j j il ciclo diventa infinito
3232
Uscita dal limite superiore di un Uscita dal limite superiore di un arrayarray
Anno accademico 2010-2011Anno accademico 2010-2011
• L’ordinamentoordinamento di una sequenza di informazioni consiste nel disporre le stesse informazioni in modo da rispettare una qualche relazione d’ordine; ad esempio, una relazione d’ordine “minore o uguale” dispone le informazioni in modo “non decrescente”
• L’ordinamento è un’operazione molto importante perché permette di ridurre notevolmente i tempi di ricercaricerca di un’informazione, nell’ambito di una sequenza di informazioni
• Nel caso in cui tale sequenza risulta ordinata, secondo una qualche relazione d’ordine, è infatti possibile sfruttare la stessa relazione d’ordine per effettuare la ricerca 3333
Gli algoritmi di ordinamento Gli algoritmi di ordinamento 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Esistono due categorie di algoritmi di ordinamento: la classificazione è fatta in base alla complessità di calcolocomplessità di calcolo e alla semplicità semplicità algoritmicaalgoritmica
• La complessità di calcolo si riferisce al numero di operazioni necessarie all’ordinamento; tali operazioni sono essenzialmente confronti e scambi tra gli elementi dell’insieme da ordinare
• La semplicità algoritmica si riferisce alla lunghezza e alla comprensibilità del codice
3434
Gli algoritmi di ordinamento Gli algoritmi di ordinamento 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Algoritmi semplici di ordinamentoAlgoritmi semplici di ordinamentoAlgoritmi che presentano complessità O(n2), dove n è il numero di informazioni da ordinare: sono caratterizzati da poche e semplici istruzioni, dunque si realizzano con poche linee di codice
• Algoritmi evoluti di ordinamentoAlgoritmi evoluti di ordinamentoAlgoritmi che presentano complessità computazionale O(nlog2n): sono più complessi, fanno spesso uso di ricorsionericorsione; la convenienza del loro utilizzo si rileva quando il numero n di informazioni da ordinare è molto elevato 3535
Gli algoritmi di ordinamento Gli algoritmi di ordinamento 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
• La strategia BubblesortBubblesort (ordinamento a bollaordinamento a bolla) prevede il confronto dei primi due elementi di un array, e lo scambio, se il primo è maggiore del secondo
• Dopo il primo confronto, si effettua un confronto fra il secondo ed il terzo elemento (con eventuale scambio), fra il terzo ed il quarto, etc.
• Gli elementi “pesanti” (grandi) tendono a scendere verso il fondo del vettore, mentre quelli “leggeri” (più piccoli) salgono (come bolle) in superficie 3636
Bubblesort Bubblesort 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Il confronto fra tutte le coppie di elementi adiacenti viene detto passaggiopassaggio Se, durante il primo passaggio, è stato effettuato almeno uno
scambio, occorre procedere ad un ulteriore passaggio
Ad ogni passaggio, almeno un elemento assume la sua posizione definitiva (l’elemento più grande del sottoinsieme attualmente disordinato)
• Devono essere effettuati al più n1 passaggi
• Al kesimo passaggio vengono effettuati nk confronti (con eventuali scambi): almeno k1 elementi sono già ordinati
• Complessivamente, vengono effettuati n(n1)/2 confronti
La complessità computazionale del Bubblesort è La complessità computazionale del Bubblesort è OO((nn22))
3737
Bubblesort Bubblesort 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
define FALSE 0define TRUE 1include <stdio.h>
void bubble_sort(list, list_size)
int list[], list_size;
{
int j, temp, sortedFALSE; while(!sorted)
{
sorted TRUE; /* assume che list sia ordinato */ for(j0; j<list_size1; j) {
if(list[j]>list[j1]) { /* almeno un elemento non è in ordine */
sorted FALSE; temp list[j]; list[j] list[j1]; list[j1] temp; }
} /* fine del ciclo for */
} /* fine del ciclo while */
}
NotaNota
Nel caso migliore, quando il vettore è già ordinato, si effettua un solo passaggio, con n1 confronti e nessuno scambio
La complessità scende a O(n)
3838
Bubblesort Bubblesort 3 3
Anno accademico 2010-2011Anno accademico 2010-2011
3939
Le stringheLe stringhe
Anno accademico 2010-2011Anno accademico 2010-2011
• Una stringastringa è un array di caratteri terminato dal carattere nullo, corrispondente alla sequenza di escape \0\0 (con valore numerico associato zero)
• Una stringa costantestringa costante (o letteraleletterale) è una serie di caratteri racchiusi fra doppi apici: tale stringa è di tipo array di caratteriarray di caratteri, con ogni carattere che occupa un byte
• Ad ogni stringa viene aggiunto automaticamente dal compilatore un carattere nullo, ad indicarne la fine
4040
DefinizioneDefinizione
Anno accademico 2010-2011Anno accademico 2010-2011
• Per memorizzare una stringa occorre dichiarare un array di charchar, che può essere inizializzato con una stringa costante
static char str[]static char str[]“testo”;“testo”;• L’array ha dimensione maggiore di uno rispetto alla
lunghezza della stringa, per consentire la memorizzazione del carattere nullo di terminazione (strstr ha lunghezza 6 byte)
• Il compilatore segnala un errore se si dichiara la lunghezza della stringa n, e si inizializza con una stringa costante di lunghezza >nstatic char str[3]static char str[3]“quattro”; /* SCORRETTO */“quattro”; /* SCORRETTO */
static char str1[3]static char str1[3]“tre”; /* CORRETTO */“tre”; /* CORRETTO */
I compilatori ANSI, generalmente, consentono di specificare una dimensione di array che non includa il carattere terminatore
4141
Dichiarazione e inizializzazione Dichiarazione e inizializzazione 11
Anno accademico 2010-2011Anno accademico 2010-2011
• È possibile inizializzare un puntatore a charchar con una stringa costante:
char *ptr = “altro testo”;char *ptr = “altro testo”;
si crea un array di caratteri, inizializzato ad “altro testo”“altro testo”, ri-servando però memoria anche per il puntatore
Nel caso dell’array, tutti i successivi accessi utilizzano il nome dell’array come riferimento per l’indirizzo dell’elemento iniziale dell’array: tale indirizzo non può essere modificato
Il puntatore è una variabile e può essere modificato: l’indirizzo relativo alla prima inizializzazione viene perso
2000 1006
1005
1002
1001
1000
0FFF
1004
1003
strstr
‘\0’
‘o’
‘t’
‘e’
‘s’
‘t’
ptrptr
‘\0’
‘o’
‘t’
‘e’
‘s’
‘t’
‘o’
‘a’ ‘l’
‘t’
‘r’1009
1008
1007
1006
100B
100E
100D
100C
1011
100F
100A
‘ ’
1010
4242
Dichiarazione e inizializzazione Dichiarazione e inizializzazione 22
Anno accademico 2010-2011Anno accademico 2010-2011
• Un puntatore a charchar può essere inizializzato con una stringa costante, perché una stringa è un array di charchar
• Una stringa costante viene interpretata come un puntatore al primo carattere della stringa
include <stdlib.h>main()
{
char array[10];
char *ptr1 “10 spazi”; char *ptr2;
array “not OK”; /* non è possibile assegnare un indirizzo */ array[5] ‘A’; /* OK */ *(ptr15) ‘B’; /* OK */ ptr1 “OK”; ptr1[5] ‘C’; /* opinabile a causa dell’assegnamento precedente */ *ptr2 “not OK”;/* conflitto di tipi */ ptr2 “OK”; /* opinabile perché non c’è inizializzazione */ exit(0);
}4343
Gli assegnamenti a stringheGli assegnamenti a stringhe
Anno accademico 2010-2011Anno accademico 2010-2011
• Occorre notare la differenza fra stringhe costanti e costanti di tipo carattere:
• È possibile assegnare una costante carattere all’indirizzo contenuto in un puntatore a charchar; è invece scorretto effettuare la stessa operazione relativamente ad una stringa
char ch char ch ‘a’; /* Per ‘a’ è riservato un byte */ ‘a’; /* Per ‘a’ è riservato un byte */
/* Vengono riservati due byte per “a”, oltre allo/* Vengono riservati due byte per “a”, oltre allo
* spazio necessario alla memorizzazione di ps* spazio necessario alla memorizzazione di ps
*/*/
char *ps char *ps “a”; “a”;
char *p2; char *p2;
p2 p2 ‘a’; /* not OK */ ‘a’; /* not OK */
p2 p2 “a”; /* OK */ “a”; /* OK */
char *p1;char *p1;
*p1 *p1 ‘a’; /* OK */ ‘a’; /* OK */
*p1 *p1 “a”; /* not OK “a”; /* not OK */*/
Le stringhe sono interpretate come puntatori a carattere 4444
Stringhe e caratteri Stringhe e caratteri 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Le inizializzazioni e gli assegnamenti non sono simmetrici; è infatti possibile scrivere
char *p char *p “string”; “string”; ma non… *p *p “string”; “string”;
• Nota:Nota: vale per inizializzazioni ed assegnamenti di tutti i tipi di dati
float f;float f; float *pf float *pf &f; /*OK */ &f; /*OK */ *pf *pf &f; /* SCORRETTO */ &f; /* SCORRETTO */
Carattere
Float
Puntatore a carattere
Puntatore a float
4545
Stringhe e caratteri Stringhe e caratteri 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Le stringhe possono essere lette e scritte utilizzando le funzioni scanf()scanf() e printf()printf(), con lo specificatore di formato %s%s
• L’argomento della funzione scanf()scanf() deve essere un puntatore ad un array di caratteri di dimensioni sufficienti a contenere la stringa in ingresso, che si intende terminata da un qualsiasi carattere di spaziatura
• La funzione scanf()scanf(), dopo aver letto il dato in ingresso, aggiunge automaticamente il carattere \0\0 in fondo alla stringa
• L’argomento della funzione printf()printf() deve essere un puntatore ad un array di caratteri terminato dal carattere nullo (che non viene stampato)
4646
Lettura e scrittura di stringhe Lettura e scrittura di stringhe 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
• Esempio:Esempio: Scrivere un programma che legge una stringa dalla periferica d’ingresso di default e la stampa dieci volte
include <stdio.h>include <stdlib.h>define MAX_CHAR 80
main()
{
char str[MAX_CHAR];
int i;
printf(“Introdurre una stringa:”);
scanf(“%s”, str);
for (i0; i<10; i) printf(“%s\n”, str);
exit(0);
}
È possibile utilizzare il nome dell’array come argomento per le funzioni di I/O, in quanto puntatore all’inizio dell’array
4747
Lettura e scrittura di stringhe Lettura e scrittura di stringhe 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
• Poiché nell’espressione *str*str i due operatori hanno la stessa precedenza ed associatività de-stra, l’espressione viene analiz-zata dal compilatore nel modo seguente:
Valutazione dell’operatore di incre-mento postfisso; il compilatore passa strstr all’operatore successivo e lo incrementa solo al termine della valutazione dell’espressione
int strlen(str)
char *str;
{
int i;
for (i0; *str; i) ; /* istruzione vuota */
return i;
}
Valutazione dell’operatore * *, applicato a strstr Completamento dell’espressione, con l’incremento di strstr
• La funzione strlen()strlen(), restituisce il numero di caratteri che compongono una stringa (escluso il carattere nullo)
4848
Le funzioni di libreria per le Le funzioni di libreria per le stringhe stringhe strlen()strlen()
Anno accademico 2010-2011Anno accademico 2010-2011
• L’operatore di incremento postfisso è obbligatorio: un incremento prefisso non produrrebbe un risultato corretto, dato che il primo elemento non verrebbe copiato
void strcpy(s1, s2)
char *s1, *s2;
{
while(*s2 *s1) ; /*istruzione vuota */
}
• Il risultato dell’assegnamento costituisce la condizione di test per il ciclo whilewhile
• Se *s2*s2 vale zero (per il carattere di terminazione), si ha l’uscita dal ciclo
• La funzione strcpy()strcpy() copia una stringa in un’altra
4949
Le funzioni di libreria per le Le funzioni di libreria per le stringhe stringhe strcpy()strcpy()
Anno accademico 2010-2011Anno accademico 2010-2011
• La funzione strstr()strstr() effettua la ricerca di una sottostringa all’interno di una stringa, operazione detta comunemente pattern matchingpattern matching
• La funzione prevede come argomenti due puntatori a stringhe di caratteri ed effettua la ricerca di un’occorrenza della seconda stringa nella prima: se esiste un’occorrenza, viene restituita la posizione
d’inizio nell’array altrimenti, viene restituito 1
• Nota:Nota: la maggior parte delle funzioni della libreria di runtime restituisce 0 o 1, come valore di errore (per strstr()strstr(), 0 corrisponde all’occorrenza della seconda stringa all’inizio della prima)
5050
Le funzioni di libreria per le Le funzioni di libreria per le stringhe stringhe strstr()strstr() 1 1
Anno accademico 2010-2011Anno accademico 2010-2011
/* Restituisce la posizione di str2 in str1; restituisce 1 se non esiste occorrenza */int strstr(str1, str2)
char *str1, *str2;
{
char *p, *q, *substr;
/* Itera su ogni carattere di str1 */
for(substrstr1; *substr; substr) {
p substr; q str2; /* Controlla se l’occorrenza di str2 corrisponde alla posizione corrente */
while(*q)
if(*q ! *p) goto no_match; /* serve per uscire dal while, ma restare nel for */
/* Si giunge qui solo se si è trovata un’occorrenza di str2 */
return substrstr1; /* Si giunge qui se non è stata riscontrata un’occorrenza di str2 (nel ciclo while) */
no_match: ;
}
/* Si giunge qui se non vi sono occorrenze di str2 in str1 */
return 1;}
5151
Le funzioni di libreria per le Le funzioni di libreria per le stringhe stringhe strstr()strstr() 2 2
Anno accademico 2010-2011Anno accademico 2010-2011
strcpy()strcpy() Copia una stringa in un array
strncpy()strncpy() Copia una parte di una stringa in un array
strcat()strcat() Concatena due stringhe
strncat()strncat() Concatena parte di una stringa ad un’altra
strcmp()strcmp() Confronta due stringhe
strncmp()strncmp() Confronta due stringhe per una lunghezza data
strchr()strchr() Cerca la prima occorrenza di un carattere specificato in una stringa
strcoll()strcoll() Confronta due stringhe sulla base di una sequenza di confronto definita
strcspn()strcspn() Calcola la lunghezza di una stringa che non contiene i caratteri specificati
strerror()strerror() Fa corrispondere ad un numero di errore un messaggio di errore testuale
strlen()strlen() Calcola la lunghezza di una stringa
strpbrk()strpbrk() Cerca la prima occorrenza di uno tra i caratteri specificati all’interno di una stringa
strrchr()strrchr() Cerca l’ultima occorrenza di un carattere in una stringa
strspn()strspn() Calcola la lunghezza di una stringa che contenga caratteri specificati
strstr()strstr() Cerca la prima occorrenza di una stringa in un’altra
strtok()strtok() Divide una stringa in una sequenza di simboli
strxfrm()strxfrm() Trasforma una stringa in modo che sia utilizzabile come argomento per strcmp()strcmp()
5252
Le funzioni di libreria in Le funzioni di libreria in string.hstring.h
Anno accademico 2010-2011Anno accademico 2010-2011
/* Esempio di conversione da stringa ad intero */
include <stdio.h>include <stdlib.h>
main()
{
char anno_nascita[5], anno_corrente[5];
int anni;
printf(“Inserire l’anno di nascita: ”);
scanf(“%s”, anno_nascita);
printf(“Inserire l’anno corrente: ”);
scanf(“%s”, anno_corrente);
/* atoi() converte una stringa in un intero */
anni atoi(anno_corrente) atoi(anno_nascita); printf(“Età: %d\n”, anni);
exit(0);
}5353
Esempio: Calcolo dell’età Esempio: Calcolo dell’età
Anno accademico 2010-2011Anno accademico 2010-2011
/* Conta il numero di parole in una stringa */
include <ctype.h>
int word_count(s)
char *s;
{
int count0;
while(*s !`\0´) {
while(isspace(*s)) /* salta la spaziatura */
s; if(*s !`\0´) /* trovata una parola */ {
count; while(!isspace(*s) && *s !`\0´) s; /* salta la parola */ }
}
return count;
}
5454
Esempio: Parole nella stringa Esempio: Parole nella stringa
Anno accademico 2010-2011Anno accademico 2010-2011
/* Letta in input una stringa, verifica se è palindroma */
include <stdio.h>include <stdlib.h>include <string.h>
main()
{
char parola[32], i0, n;
printf(“Inserisci una parola (lunga al max 31 caratteri): ”);
scanf(“%s”, parola);
n strlen(parola); while((i n/2) && (parola[i] parola[n1i]))
i; if(i n/2) printf(“La parola %s è palindroma.\n”, parola);
else
printf(“La parola %s non è palindroma.\n”, parola);
exit(0);
}5555
Esempio: Parole palindrome Esempio: Parole palindrome
Anno accademico 2010-2011Anno accademico 2010-2011
/* Letta una stringa alfabetica, la riscrive con solo lettere maiuscole*/
include <stdlib.h>include <stdio.h>include <string.h>
main()
{ char s[100], t[100]; int i;
printf(“Inserisci una stringa: ”); scanf(“%s”, s); for (i0; istrlen(s); i) { if (s[i] 97 && s[i] 122) t[i] s[i] 32; else t[i] s[i]; } printf(“Stringa maiuscola: %s\n”, t);
exit(0);}
5656
Esempio: Da minuscole a Esempio: Da minuscole a maiuscole maiuscole