Anno accademico Array e puntatori in C
Anno accademico Sommario Gli array ed i puntatoriGli array ed i puntatori Dichiarazione e memorizzazione di array Dichiarazione e memorizzazione di array Linizializzazione di array Linizializzazione di array Laritmetica dei puntatori Laritmetica dei puntatori Il passaggio di puntatori come argomenti di funzione Il passaggio di puntatori come argomenti di funzione Gli algoritmi di ordinamento Gli algoritmi di ordinamento Le stringheLe stringhe
Anno accademico Gli array ed i puntatori 3
Anno accademico arrayNel linguaggio C, un array è un insieme di variabili dello stesso tipo memorizzate consecutivamente elemento indiceOgni variabile dellarray, detta elemento, può essere acceduta mediante il nome dellarray ed un indice (un espressione), con il primo elemento individuato dallindice di valore 0 Esempio:Esempio: Memorizzare la temperatura media registrata per ogni giorno dellanno 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 array 4
Anno accademico dichiarazione di arrayLa sintassi della dichiarazione di array è: La dichiarazione viene effettuata inserendo una coppia di parentesi quadre dopo il nome dellarray La dimensione dellarray viene specificata inserendo il numero di elementi allinterno delle parentesi quadre La dichiarazione di array 1 Valori iniziali Specificatore di tipo } [ Nome dellarray Dimensione dellarray = ] { 5
Anno accademico riferimento ad un elemento dellarrayIl riferimento ad un elemento dellarray è invece loperazione di accesso al dato elemento ed avviene utilizzando il nome dellarray seguito dallindice dellelemento (racchiuso fra parentesi quadre) Le istruzioni di dichiarazione di un array e di riferimento ad un elemento dellarray sono molto simili nella forma, ma molto diverse nel significato /* I seguenti sono riferimenti a elementi * dellarray; 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 dellarray */ int daily_temp[365]; La dichiarazione di array 2 6
Anno accademico Esempio:Esempio: Calcolo della temperatura media annua include define DAYS_IN_YEAR 365 main() { int j, sum 0; int daily_temp[DAYS_IN_YEAR]; /* si assegnano i valori a daily_temp[] */ for (j 0; j<DAYS_IN_YEAR; j ) sum daily_temp[j]; printf(La temperatura media dellanno è %d.\n, sum/DAYS_IN_YEAR); exit(0); } La dichiarazione di array 3 7
Anno accademico EsempioEsempio garbagear[2] e ar[4] sono indefiniti: il contenuto delle posizioni di memoria è quello rimasto da esecuzioni precedenti (garbage) int ar[5]; /* dichiarazione */ ar[0] 15; ar[1] 17; ar[3] 3 ; ar[4] ar[0] ar[1] ar[2] ar[3] FFC C non definito 4 byte La memorizzazione di array 8
Anno accademico La presenza di valori indefiniti in alcuni elementi dellarray può provocare errori difficili da rilevare Occorre inizializzare lintero vettore static a durata fissa Dichiarare larray static (vettore a durata fissa): gli elementi del vettore, non inizializzati esplicitamente, vengono posti a zero Valori diversi possono essere specificati, facendoli seguire alla dichiarazione dellarray, racchiusi fra parentesi graffe: tali valori devono essere espressioni costanti che possano essere convertite automaticamente nel tipo dellarray 9 Linizializzazione di array 1
Anno accademico EsempioEsempio Nota:Nota: il valore floating point 3.5 viene convertito nel valore intero FFC C byte C br[4] br[0] br[1] br[2] br[3] ar[4] ar[0] ar[1] ar[2] ar[3] non definito static int ar[5]; static int br[5] {1,2,3.5,4,5}; 10 Linizializzazione di array 2
Anno accademico Specificare un numero maggiore di valori di inizializzazione, rispetto agli elementi dellarray, 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] {1,2,3}; produce linizializzazione cr[0] 1 cr[1] 2 cr[2] 3 cr[3] 0 cr[4] 0 11 Linizializzazione di array 3
Anno accademico Se vengono specificati i valori iniziali, può essere omessa la dimensione dellarray: il compilatore calcola automatica- mente il numero degli elementi sulla base del numero dei valori iniziali specificati Esempio:Esempio: static char dr[] {a,b,c,d}; char comporta la creazione di un array di quattro elementi, di tipo char, caratterizzati dai valori iniziali dr[0] a dr[1] b dr[2] c dr[3] d 12 Linizializzazione di array 4
Anno accademico 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 dallautenticazione al sistema tramite password crittogrammaOltre 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 crittogramma, o testo cifrato Il legittimo proprietario del file (e chi da lui autorizzato) è lunico depositario della chiave di decodifica ed è lunico in grado di operare linversione da testo cifrato a testo in chiaro 13 Crittografia 1
Anno accademico 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 14 Crittografia 2
Anno accademico cifrario decifrazioneSe il sistema di cifra, o cifrario, è ben congegnato, loperazione di decifrazione o decifratura deve risultare semplice al legittimo proprietario (o al destinatario del messaggio), ma di complessità proibitiva alla spia chiave del cifrario possibile in quanto gli utenti legittimi possiedono uninformazione che deve rimanere inaccessibile alla spia, la chiave del cifrario decrittazioneOccorre notare la distinzione tra decifrazione e decrittazione, loperazione illegittima in cui non ci si può avvalere della chiave 15 Crittografia 3
Anno accademico /* 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 111=o Ciao6D\5 16 Crittografia 4
Anno accademico Shift CypherIl codice Shift Cypher con K 3 era utilizzato da Giulio Cesare Esercizio: Esercizio: Con K 11, 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 midnight hphtwwxppelextoytrse 17 Crittografia 5
Anno accademico /* Dato un vettore, stabilisce se vi sono almeno due elementi uguali tra loro */ #define MAX_DIM 256 typedef 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_DIM 1)) && (found 1)); c ) { for(k (c 1); ((k < MAX_DIM) && (found 1)); k ) { if (v[c] v[k]) found 1; /* ricerca con successo */ } return found; } 18 Esempio 1
Anno accademico /* Inverte gli elementi di un vettore */ #include int main() { /*dichiarazioni*/ int a[10], b[10]; int i, dim 10; /*input elementi*/ for(i 0;i<dim;i ) { printf(inserire lelemento a[%d]:,i); scanf(%d, &a[i]); } /*stampa vettore*/ printf(\nIl vettore è:\n\n); for(i 0;i<dim;i ) printf(a[%d] %d\n, i, a[i]); printf(\n); /*inversione vettore*/ for(i 0;i<dim;i ) b[i] a[dim 1 i]; /*stampa vettore invertito*/ printf(Il vettore invertito è:\n\n); for(i 0;i<dim;i ) printf(b[%d] %d\n, i, b[i]); return 0; } 19 Esempio 2
Anno accademico Il C permette lutilizzo degli operatori additivi in concomitanza con i puntatori pp 3 pSe p è un puntatore, lespressione p 3 è lecita ed individua il terzo oggetto che segue quello puntato da p ppPoiché p contiene un indirizzo, operazioni aritmetiche su p forniscono nuovi indirizzi p p scalingIl compilatore non opera semplicemente una somma tra 3 e p, ma moltiplica 3 per la dimensione delloggetto puntato da p : effettua cioè uno scaling Esempio: pp long int p 3 p char p 3Esempio: Se lindirizzo contenuto in p è 1000 e p è un puntatore a long int, allora p 3 identifica lindirizzo 1018 (8 byte per gli interi lunghi); se p è un puntatore a char, p 3 rappresenta lindirizzo Laritmetica dei puntatori 1
Anno accademico Nellipotesi di puntatori che si riferiscono allo stesso tipo di dato, è lecito sottrarre il valore di un puntatore da un altro: loperazione 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 21 Laritmetica dei puntatori 2
Anno accademico EsempioEsempio long *p1, *p2, k; int j; char *p3; p1 &k; p2 p1 4; /* OK */ j p2 p1; /* OK a j viene assegnato 4 */ j p1 p2; /* OK a j viene assegnato 4 */ p1 p2 2; /* OK tipi dei puntatori compatibili */ p3 p1 1; /* NO tipi diversi di puntatori */ j p1 p3; /* NO tipi diversi di puntatori */ 22 Laritmetica dei puntatori 3
Anno accademico puntatori nulliIl linguaggio C prevede la definizione di puntatori 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; p 0; /* rende p un puntatore nullo */ p 0; /* rende p un puntatore nullo */ In questo caso il compilatore non effettua la conversione esplicita dellespressione intera nel tipo del puntatore La definizione del puntatore nullo è utile allinterno di istruzioni di controllo: il puntatore nullo è lunico puntatore cui è associato il valore FALSE; tutti i puntatori validi valgono TRUE 23 Laritmetica dei puntatori 4
Anno accademico Il compilatore segnala i tentativi di utilizzo congiunto di puntatori di tipi diversi prototipoUneccezione alla regola è costituita dalluso di puntatori come argomenti di funzione: in mancanza di un prototipo, 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 prototipoIl prototipo 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 24 Il passaggio di puntatori come argomenti di funzione 1
Anno accademico include void clr(p) int *p; { *p 0 /* Memorizza 0 alla locazione p */ } main() { static short s[3] {1,2,3}; clr(&s[1]); /* Azzera lelemento 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 p int s[1] s[2] p è un puntatore a int vengono azzerati 4 byte, quindi sia s[1] che s[2] 25 Il passaggio di puntatori come argomenti di funzione 2
Anno accademico È possibile accedere agli elementi di un array attraverso… …luso del nome dellarray con il relativo indice …luso dei puntatori Infatti vale la regola che… Aggiungere un intero ad un puntatore allinizio di un array, ed accedere allindirizzo puntato dallespressione, equivale ad utilizzare lintero come indice dellarray Inoltre, un nome di array non seguito da un indice viene interpretato come un puntatore allelemento iniziale dellarray ar è equivalente a &ar[0] Se p &ar[0] *(p e) è equivalente a ar[e] 26 Laccesso agli elementi di array mediante puntatori 1
Anno accademico Combinando le due relazioni, si ottiene la regola generale indirizzo baseUn nome di array viene trasformato dal compilatore C in un puntatore allelemento iniziale dellarray e quindi gli indici vengono interpretati come spostamenti dalla posizione di indirizzo base In considerazione del meccanismo di scaling, lo spostamento determina il numero di elementi da oltrepassare Esempio:Esempio: ar[n] equivale a *(ar n) ar[2] *(ar 2) ar Sono equivalenti: in entrambi i casi, ar è un puntatore allelemento iniziale dellarray e 2 è un fattore di spostamento che richiede al compilatore di aggiungere due al valore del puntatore 27 Laccesso agli elementi di array mediante puntatori 2
Anno accademico 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 allindirizzo di (*) non può apparire alla sinistra di un operatore di assegnamento float ar[7], *p; p ar; /* OK equivale a p &ar[0] */ ar p; /* NO assegnamento su un indirizzo di array */ &p ar; /* NO assegnamento su un indirizzo di puntatore */ ar ; /* NO: non è possibile incrementare un indirizzo di array */ ar[1] *(p 5); /* OK ar[1] è una variabile */ p ; /* OK è possibile incrementare una variabile puntatore */ 28 Laccesso agli elementi di array mediante puntatori 3
Anno accademico In C, un nome di array, utilizzato come argomento di funzione, viene interpretato come indirizzo del primo elemento dellarray EsempioEsempio Nella funzione chiamata è necessario dichiarare largomento come un puntatore allelemento iniziale di un array main(){ extern float func(); float x; static float farray[5]; x func(farray) /* equivalente a: func(&farray[0]) */ … … … func(ar) float ar[]; { … … … … … …}func(ar) float *ar; { … … … … … …} Non è specificata la dimensione perché non si alloca memoria 29 Il passaggio di array come argomenti di funzione 1
Anno accademico ar floatAnche nel secondo caso, ciò che viene passato è un puntatore al primo elemento dellarray ed il compilatore è in grado di convertire automaticamente ar in un puntatore a float floatIn termini di leggibilità, la seconda versione è preferibile, poiché evidenzia che loggetto passato è lindirizzo di base di un array e non un generico puntatore a una variabile float (scalare o composta?) La dichiarazione della dimensione dellarray nella definizione dellargomento è comunque corretta: il compilatore può usare linformazione sulla dimensione per effettuare controlli sui valori limite 30 Il passaggio di array come argomenti di funzione 2
Anno accademico Non è possibile ottenere la dimensione di un array allinterno di una funzione cui viene passato come argomento, ma solo laddove larray è effettivamente dichiarato include 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, lesecuzione del programma fornisce: La dimensione di f_array è: 40 La dimensione di arg è: 4 31 Il passaggio di array come argomenti di funzione 3
Anno accademico Il compilatore, di solito, non controlla che laccesso 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(j 0; j< 10; j ) ar[j] 0; } ar for off by one Essendo ar un array di 10 elementi, quelli cui è possibile accedere in modo corretto hanno indice da 0 a 9: il ciclo for contiene un errore off by one j Probabilmente verrebbe azzerata la variabile j il ciclo diventa infinito 32 Uscita dal limite superiore di un array
Anno accademico ordinamentoLordinamento di una sequenza di informazioni consiste nel disporre le stesse informazioni in modo da rispettare una qualche relazione dordine; ad esempio, una relazione dordine minore o uguale dispone le informazioni in modo non decrescente ricercaLordinamento è unoperazione molto importante perché permette di ridurre notevolmente i tempi di ricerca di uninformazione, nellambito di una sequenza di informazioni Nel caso in cui tale sequenza risulta ordinata, secondo una qualche relazione dordine, è infatti possibile sfruttare la stessa relazione dordine per effettuare la ricerca 33 Gli algoritmi di ordinamento 1
Anno accademico complessità di calcolo semplicità algoritmicaEsistono due categorie di algoritmi di ordinamento: la classificazione è fatta in base alla complessità di calcolo e alla semplicità algoritmica La complessità di calcolo si riferisce al numero di operazioni necessarie allordinamento; tali operazioni sono essenzialmente confronti e scambi tra gli elementi dellinsieme da ordinare La semplicità algoritmica si riferisce alla lunghezza e alla comprensibilità del codice 34 Gli algoritmi di ordinamento 2
Anno accademico Algoritmi semplici di ordinamentoAlgoritmi semplici di ordinamento Algoritmi che presentano complessità O ( n 2 ), 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 ordinamento ricorsione Algoritmi che presentano complessità computazionale O ( n log 2 n ): sono più complessi, fanno spesso uso di ricorsione; la convenienza del loro utilizzo si rileva quando il numero n di informazioni da ordinare è molto elevato 35 Gli algoritmi di ordinamento 3
Anno accademico Bubblesortordinamento a bollaLa strategia Bubblesort (ordinamento 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 36 Bubblesort 1
Anno accademico passaggioIl confronto fra tutte le coppie di elementi adiacenti viene detto passaggio 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 (lelemento più grande del sottoinsieme attualmente disordinato) Devono essere effettuati al più n 1 passaggi Al k esimo passaggio vengono effettuati n k confronti (con eventuali scambi): almeno k 1 elementi sono già ordinati Complessivamente, vengono effettuati n (n 1)/2 confronti La complessità computazionale del Bubblesort è O ( n 2 ) 37 Bubblesort 2
Anno accademico define FALSE 0 define TRUE 1 include void bubble_sort(list, list_size) int list[], list_size; { int j, temp, sorted FALSE; while(!sorted) { sorted TRUE; /* assume che list sia ordinato */ for(j 0; j<list_size 1; j ) { if(list[j]>list[j 1]) { /* almeno un elemento non è in ordine */ sorted FALSE; temp list[j]; list[j] list[j 1]; list[j 1] temp; } } /* fine del ciclo for */ } /* fine del ciclo while */ } Nota Nel caso migliore, quando il vettore è già ordinato, si effettua un solo passaggio, con n 1 confronti e nessuno scambio La complessità scende a O ( n ) 38 Bubblesort 3
Anno accademico Le stringhe
Anno accademico stringa \0Una stringa è un array di caratteri terminato dal carattere nullo, corrispondente alla sequenza di escape \0 (con valore numerico associato zero) stringa costante letterale array di caratteriUna stringa costante (o letterale) è una serie di caratteri racchiusi fra doppi apici: tale stringa è di tipo array di caratteri, con ogni carattere che occupa un byte Ad ogni stringa viene aggiunto automaticamente dal compilatore un carattere nullo, ad indicarne la fine 40 Definizione
Anno accademico charPer memorizzare una stringa occorre dichiarare un array di char, che può essere inizializzato con una stringa costante static char str[] testo; strLarray ha dimensione maggiore di uno rispetto alla lunghezza della stringa, per consentire la memorizzazione del carattere nullo di terminazione ( str 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 > n static char str[3] quattro; /* SCORRETTO */ static char str1[3] tre; /* CORRETTO */ I compilatori ANSI, generalmente, consentono di specificare una dimensione di array che non includa il carattere terminatore 41 Dichiarazione e inizializzazione 1
Anno accademico charÈ possibile inizializzare un puntatore a char con una stringa costante: char *ptr = altro testo; char *ptr = altro testo; altro testo si crea un array di caratteri, inizializzato ad altro testo, ri- servando però memoria anche per il puntatore Nel caso dellarray, tutti i successivi accessi utilizzano il nome dellarray come riferimento per lindirizzo dellelemento iniziale dellarray: tale indirizzo non può essere modificato Il puntatore è una variabile e può essere modificato: lindirizzo relativo alla prima inizializzazione viene perso FFF str \0 o t e s t ptr o t e s t o a l t r B 100E 100D 100C F 100A Dichiarazione e inizializzazione 2
Anno accademico char charUn puntatore a char può essere inizializzato con una stringa costante, perché una stringa è un array di char Una stringa costante viene interpretata come un puntatore al primo carattere della stringa include main() { char array[10]; char *ptr1 10 spazi; char *ptr2; array not OK; /* non è possibile assegnare un indirizzo */ array[5] A; /* OK */ *(ptr1 5) B; /* OK */ ptr1 OK; ptr1[5] C; /* opinabile a causa dellassegnamento precedente */ *ptr2 not OK;/* conflitto di tipi */ ptr2 OK; /* opinabile perché non cè inizializzazione */ exit(0); } 43 Gli assegnamenti a stringhe
Anno accademico Occorre notare la differenza fra stringhe costanti e costanti di tipo carattere: charÈ possibile assegnare una costante carattere allindirizzo contenuto in un puntatore a char; è invece scorretto effettuare la stessa operazione relativamente ad una stringa char ch a; /* Per a è riservato un byte */ /* Vengono riservati due byte per a, oltre allo * spazio necessario alla memorizzazione di ps * spazio necessario alla memorizzazione di ps */ */ char *ps a; char *p2; p2 a; /* not OK */ p2 a; /* OK */ char *p1; *p1 a; /* OK */ *p1 a; /* not OK */ Le stringhe sono interpretate come puntatori a carattere 44 Stringhe e caratteri 1
Anno accademico Le inizializzazioni e gli assegnamenti non sono simmetrici; è infatti possibile scrivere char *p string; ma non… *p string; *p string; Nota:Nota: vale per inizializzazioni ed assegnamenti di tutti i tipi di dati float f; float f; float *pf &f; /*OK */ float *pf &f; /*OK */ *pf &f; /* SCORRETTO */ *pf &f; /* SCORRETTO */ Carattere Float Puntatore a carattere Puntatore a float 45 Stringhe e caratteri 2
Anno accademico scanf() printf() %sLe stringhe possono essere lette e scritte utilizzando le funzioni scanf() e printf(), con lo specificatore di formato %s scanf()Largomento della funzione 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 scanf() \0La funzione scanf(), dopo aver letto il dato in ingresso, aggiunge automaticamente il carattere \0 in fondo alla stringa printf()Largomento della funzione printf() deve essere un puntatore ad un array di caratteri terminato dal carattere nullo (che non viene stampato) 46 Lettura e scrittura di stringhe 1
Anno accademico Esempio:Esempio: Scrivere un programma che legge una stringa dalla periferica dingresso di default e la stampa dieci volte include define MAX_CHAR 80 main() { char str[MAX_CHAR]; int i; printf(Introdurre una stringa:); scanf(%s, str); for (i 0; i<10; i ) printf(%s\n, str); exit(0); } È possibile utilizzare il nome dellarray come argomento per le funzioni di I/O, in quanto puntatore allinizio dellarray 47 Lettura e scrittura di stringhe 2
Anno accademico *strPoiché nellespressione *str i due operatori hanno la stessa precedenza ed associatività de- stra, lespressione viene analiz- zata dal compilatore nel modo seguente: str Valutazione delloperatore di incre- mento postfisso; il compilatore passa str alloperatore successivo e lo incrementa solo al termine della valutazione dellespressione int strlen(str) char *str; { int i; for (i 0; *str ; i ) ; /* istruzione vuota */ return i; } * str Valutazione delloperatore *, applicato a str str Completamento dellespressione, con lincremento di str strlen()La funzione strlen(), restituisce il numero di caratteri che compongono una stringa (escluso il carattere nullo) 48 Le funzioni di libreria per le stringhe strlen()
Anno accademico Loperatore 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 */ } whileIl risultato dellassegnamento costituisce la condizione di test per il ciclo while *s2Se *s2 vale zero (per il carattere di terminazione), si ha luscita dal ciclo strcpy()La funzione strcpy() copia una stringa in unaltra 49 Le funzioni di libreria per le stringhe strcpy()
Anno accademico strstr() pattern matchingLa funzione strstr() effettua la ricerca di una sottostringa allinterno di una stringa, operazione detta comunemente pattern matching La funzione prevede come argomenti due puntatori a stringhe di caratteri ed effettua la ricerca di unoccorrenza della seconda stringa nella prima: se esiste unoccorrenza, viene restituita la posizione dinizio nellarray altrimenti, viene restituito 1 Nota: strstr()Nota: la maggior parte delle funzioni della libreria di run time restituisce 0 o 1, come valore di errore (per strstr(), 0 corrisponde alloccorrenza della seconda stringa allinizio della prima) 50 Le funzioni di libreria per le stringhe strstr() 1
Anno accademico /* 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(substr str1; *substr; substr ) { p substr; q str2; /* Controlla se loccorrenza 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 unoccorrenza di str2 */ return substr str1; /* Si giunge qui se non è stata riscontrata unoccorrenza di str2 (nel ciclo while) */ no_match: ; } /* Si giunge qui se non vi sono occorrenze di str2 in str1 */ return 1; } 51 Le funzioni di libreria per le stringhe strstr() 2
Anno accademico strcpy() Copia una stringa in un array strncpy() Copia una parte di una stringa in un array strcat() Concatena due stringhe strncat() Concatena parte di una stringa ad unaltra strcmp() Confronta due stringhe strncmp() Confronta due stringhe per una lunghezza data strchr() Cerca la prima occorrenza di un carattere specificato in una stringa strcoll() Confronta due stringhe sulla base di una sequenza di confronto definita strcspn() Calcola la lunghezza di una stringa che non contiene i caratteri specificati strerror() Fa corrispondere ad un numero di errore un messaggio di errore testuale strlen() Calcola la lunghezza di una stringa strpbrk() Cerca la prima occorrenza di uno tra i caratteri specificati allinterno di una stringa strrchr() Cerca lultima occorrenza di un carattere in una stringa strspn() Calcola la lunghezza di una stringa che contenga caratteri specificati strstr() Cerca la prima occorrenza di una stringa in unaltra strtok() Divide una stringa in una sequenza di simboli strxfrm() strcmp() Trasforma una stringa in modo che sia utilizzabile come argomento per strcmp() 52 Le funzioni di libreria in string.h
Anno accademico /* Esempio di conversione da stringa ad intero */ include main() { char anno_nascita[5], anno_corrente[5]; int anni; printf(Inserire lanno di nascita: ); scanf(%s, anno_nascita); printf(Inserire lanno 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); } 53 Esempio: Calcolo delletà
Anno accademico /* Conta il numero di parole in una stringa */ include int word_count(s) char *s; { int count 0; 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; } 54 Esempio: Parole nella stringa
Anno accademico /* Letta in input una stringa, verifica se è palindroma */ include main() { char parola[32], i 0, n; printf(Inserisci una parola (lunga al max 31 caratteri): ); scanf(%s, parola); n strlen(parola); while((i n/2) && (parola[i] parola[n 1 i])) i ; if(i n/2) printf(La parola %s è palindroma.\n, parola); else printf(La parola %s non è palindroma.\n, parola); exit(0); } 55 Esempio: Parole palindrome
Anno accademico /* Letta una stringa alfabetica, la riscrive con solo lettere maiuscole*/ include main() { char s[100], t[100]; int i; printf(Inserisci una stringa: ); scanf(%s, s); for (i 0; i strlen(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); } 56 Esempio: Da minuscole a maiuscole