24 aprile 2002 Avvisi: • Risultati 1o Esonero: (entro) lunedi 27 disponibili nella pag. WEB , ma anche esposti nella bacheca fuori dal corridoio 2o dente, piano terra. • “Speciale 1o Esonero”: soluzioni , commenti, correzioni compiti prossima lezione (giovedì 2 maggio). • Progetti: gia’ disponibili nella pag. WEB. Qualche minuto di “laboratorio” Esercizio 6.19 Scrivere un programma C che simuli il lancio di due dadi. Il programma dovra’ utilizzare rand per lanciare il primo dado e poi invocarla nuovamente per lanciare il secondo dado: poi calcolera’ la somma dei due valori. (Nota: tale somma puo’ variare tra 2 e 12). Tale programma dovra’ lanciare i due dadi 36.000 volte e poi dovra’ visualizzare i seguenti risultati: • Un vettore di frequenze F per i risultati di ogni lancio cioe’ tale che F(i) rappresenta quante volte la somma dei due dadi e’ stata uguale ad i con i=2,3,…12. • Una matrice D 6x6 tale che D(i,j) rappresenta quante volte si e’ ottenuto i col primo dado e j con il secondo dado con i,j=1,2,…,6. Vediamo le soluzioni proposte da voi… Chiamata di funzioni per riferimento • Chiamata per riferimento usando puntatori come argomenti – Si passa l’indirizzo di un argomento usando l’operatore & – Consentono di cambiare il valore nella locazione di memoria – Gli array non si possono passare con & perche’ il nome dell’array e’ gia’ un puntatore • operatore * – Usato come alias per una variabile all’interno di una funzione void double(int *number) {*number = 2 * (*number);} *number si usa come alias per la variabile passata 1. 2. 3. /* Elevare al cubo mediante una chiamata per valore */ #include <stdio.h> int cubeByValue(int); 4. 5. 6. 7. 8. 9. 10. 11. main() { int number = 5; printf("The original value of number is %d\n", number); number = cubeByValue(number); printf("The new value of number is %d\n", number); return 0; } 12. 13. 14. 15. int cubeByValue(int n) { return n * n * n; /* eleva al cubo */ } The original value of number is 5 The new value of number is 125 Output 1 /* Fig. 7.7: fig07_07.c 2 Elevare al cubo mediante chiamata per riferimento 3 mediante puntatori */ 4 5 #include <stdio.h> 6 7 void cubeByReference( int * ); Notare che viene dato 8 l’indirizzo di number – 9 int main() infatti cubeByReference 10 { aspetta un puntatore 11 int number = 5; (indirizzo di una variabile). 12 13 printf( "The original value of number is %d", number ); 14 cubeByReference( &number ); 15 printf( "\nThe new value of number is %d\n", number ); 16 17 return 0; 18 } All’interno di cubeByReference, 19 si usa *nPtr (*nPtr e’ number). 20 void cubeByReference( int *nPtr ) 21 { 22 *nPtr = *nPtr * *nPtr * *nPtr; 23 } The original value of number is 5 The new value of number is 125 Output Usare il qualificatore Const con i puntatori • Qualificatore const – una variabile non puo’ essere cambiata – Utile avere const se la funzione non deve cambiare una variabile – Tentativi di cambiare un const produce “errore” in compilazione • Puntatori const – puntano alla stessa locazione di memoria – Devono essere inizializzati quando sono dichiarati int *const myPtr = &x; • Tipo int *const – puntatore costante a un int const int *myPtr = &x; • Puntatori regolari a const int const int *const Ptr = &x; • const puntatore a const int • x puo’ essere cambiato, ma non *Ptr 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. /* Fig7_10 Converting lowercase letters to uppercase letters */ /* using a non-constant pointer to non-constant data */ #include <stdio.h> void convertToUppercase(char *); main() { char string[] = "characters"; printf("The string before conversion is: %s\n", string); convertToUppercase(string); printf("The string after conversion is: %s\n", string); return 0; } void convertToUppercase(char *s) { while (*s != '\0') { 16. 17. if (*s >= 'a' && *s <= 'z') *s -= 32; /* convert to ASCII uppercase letter */ 18. 19. 20. ++s; } } /* increment s to point to the next character */ The string before conversion is: characters The string after conversion is: CHARACTERS Output 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. /* Fig7_11 Printing a string one character at a time using */ /* a non-constant pointer to constant data */ #include <stdio.h> void printCharacters(const char *); main() { char string[] = "print characters of a string"; printf("The string is:\n"); printCharacters(string); putchar('\n'); return 0; } 13. 14. 15. 16. 17. void printCharacters(const char *s) { for ( ; *s != '\0'; s++) /* no initialization */ putchar(*s); } The string is: print characters of a string Output 1. 2. 3. 4. 5. 6. 7. /* Fig7_12.c Attempting to modify data through a /* non-constant pointer to constant data */ #include <stdio.h> void f(const int *); main() { int y; 8. 9. 10. f(&y); return 0; } 11. 12. 13. 14. void f(const int *x) { *x = 100; /* cannot modify a const object */ } */ /* f attempts illegal modification */ 13 Warning: assignment of read-only location Dev-C++ 13 ERROR: Cannot modify a const object Borland 1. 2. 3. /* Fig. 7.13 Attempting to modify a constant pointer to */ /* non-constant data */ #include <stdio.h> 4. 5. 6. 7. main() { int x, y; int * const ptr = &x; 8. ptr = &y; /* attempt to modify a const pointer*/ 9. 10. return 0; } 10 Warning: assignment to read-only variable ‘ptr’ Dev-C++ 10 ERROR: Cannot modify a const object Borland 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 /* Fig. 7.14: fig07_14.c Attempting to modify a constant pointer to constant data */ #include <stdio.h> int main() { int x=5, y; const int * const ptr = &x; *ptr = 7; ptr = &y; return 0; } FIG07_13.c: Error E2024 FIG07_13.c 15: Cannot modify a const object in function main 16: Cannot modify a const object in function main *** 2 errors in Compile *** Bubble Sort usando chiamata per riferimento • Implementare bubblesort usando puntatori – Scambia due elementi – La funzione swap deve ricevere un indirizzo (usando &) degli elementi dell’array • Gli elementi dell’array hanno una chiamata-pervalore per default – Usando puntatori e l’operatore *, la funzione swap puo’ scambiare elementi dell’array 1 /* Fig. 7.15: fig07_15.c 2 This program puts values into an array, sorts the values into 3 ascending order, and prints the resulting array. */ 4 #include <stdio.h> 5 #define SIZE 10 6 void bubbleSort( int *, const int ); 7 8 int main() 9 { 11 int a[ SIZE ] = { 2, 6, 4, 8, 10, 12, 89, 68, 45, 37 }; 12 int i; 13 Bubblesort prende 14 printf( "Data items in original order\n" ); l’indirizzo dell’array. 15 Il nome di un array e’ un 16 for ( i = 0; i < SIZE; i++ ) puntatore.. 17 printf( "%4d", a[ i ] ); 18 19 bubbleSort( a, SIZE ); /* ordina l’array */ 20 printf( "\nData items in ascending order\n" ); 21 22 for ( i = 0; i < SIZE; i++ ) 23 printf( "%4d", a[ i ] ); 24 25 printf( "\n" ); 27 return 0; 28 } 29 30 void bubbleSort( int *array, const int size ) 31 { 32 void swap( int *, int * ); 33 int pass, j; 34 for ( pass = 0; pass < size - 1; pass++ ) 35 36 for ( j = 0; j < size - 1; j++ ) 37 38 39 if ( array[ j ] > array[ j + 1 ] ) swap( &array[ j ], &array[ j + 1 ] ); 40 } 41 42 void swap( int *element1Ptr, int *element2Ptr ) 43 { 44 int hold = *element1Ptr; 45 *element1Ptr = *element2Ptr; 46 *element2Ptr = hold; 47 } Data items in original order 2 6 4 8 10 12 89 68 Data items in ascending order 2 4 6 8 10 12 37 45 45 37 Output Nelle lezioni precedenti… 103 104 105 106 107 108 109 110 111 112 113 114 115 116 void bubbleSort( int a[] ) { int pass, j, hold; for ( pass = 1; pass <= SIZE - 1; pass++ ) for ( j = 0; j <= SIZE - 2; j++ ) if ( a[ hold a[ j a[ j } } j = ] + ] > a[ j + 1 ] ) { a[ j ]; = a[ j + 1 ]; 1 ] = hold; Aritmetica con i puntatori • Alcune operazioni aritmetiche possono essere utilizzate con i puntatori – Incrementa/decrementa puntatori (++ o --) – Si puo’ aggiungere/sottrarre un intero a/da un puntatore ( + o += , - o -=) – Puntatori possono essere sottratti uno dall’altro – Attenzione: Sono operazioni senza significato a meno che non siano effettuate su array. Aritmetica con i puntatori • int v[5] (supp int e’ di 4 byte) – vPtr = v oppure vPtr = &v[0] • vPtr punta al primo elemento v[0]nella locazione 3000. (vPtr = 3000) – vPtr +=2; assegna a vPtr valore 3008 • vPtr punta a v[2], ma un int vale 4 byte! locazione 3000 v[0] 3004 v[1] variabile puntatore vPtr 3008 v[2] 3012 v[3] 3016 v[4] Aritmetica con i puntatori • Sottrarre puntatori – Restituisce il numero di elementi tra uno e l’altro – vPtr2 = &v[2]; vPtr = &v[0]; vPtr2 - vPtr = 2. (numero di elementi del vettore tra vPtr2 e vPtr ) • Confronti tra puntatori ( <, == , > ) – Per vedere quale puntatore punta all’elemento dellarray di indice maggiore… – Anche per controllare se un puntatore punta a Aritmetica con i puntatori • Puntatori dello stesso tipo possono essere assegnati uno all’altro – Se non sono dello stesso tipo, deve essere usato un operatore cast – Eccezione: puntatori a void (tipo void *) • Puntatori generici, rappresentano qualunque tipo • Non occorre casting per convertire un puntatore ad un puntatore void • Puntatori void non possono essere dereferenziati