Puntatori e loro aritmetica. Formattazione dati e cast. Tipi di dato strutturato

OBIETTIVO DELLA LEZIONE
    Puntatori
  1. Comprendere cosa è un puntatore e come possa essere utilizzato per accedere a vettori e matrici
  2. Essere in grado di utilizzare correttamente un puntatore sfruttando l'aritmetica dei puntatori
  3. Riconoscere gli errori nei programmi derivanti dalla non corretta applicazione dell'aritmetica dei puntatori

    Formattazione e cast
  4. Essere in grado di gestire correttamente l'output di numeri, vettori e stringhe
  5. Essere in grado di gestire correttamente la conversione tra tipi di dati diversi attraverso il cast

    Tipi di dato strutturato
  6. Comprendere l'importanza della progettazione dei tipi di dato come regola di buona programmazione
  7. Essere in grado di progettare ed impiegare correttamente tipi di dato definiti dall'utente
  8. Conoscere le modalità di accesso dei tipi di dato definiti dall'utente
.:. LUCIDI DELLA LEZIONE .:.


Note

Struttura della memoria e allocazione. Puntatori

Variabili , tipi, visualizzazione, dichiarazione funzioni

Lab

Prima di iniziare

Rileggi velocemente il riassunto della lezione di stamattina che trovi in questa pagina (sezione Note). I costrutti presentati saranno molto utili per risolvere gli esercizi di oggi.

Esercizio 1 (Ripasso teoria puntatori)
Prova a rispondere alle seguenti domande.
Se non trovi le risposte o non sei sicuro, rivedi la lezione.
--------------------------------------------------------------------------------
1. La memoria che viene impiegata da un programma è stata allocata dal:
- programma stesso
- dal sistema operativo
- da nessuno dei due, è pronta dall'avvio della macchina

--------------------------------------------------------------------------------
2. In quanti segmenti è divisa la memoria allocata a disposizione dal programma?
- 1
- 4
- 2
- 3
- 5

--------------------------------------------------------------------------------
3. Le funzioni allocano i loro parametri formali:
- sullo heap
- sullo stack
- nell'area del programma

--------------------------------------------------------------------------------
4. Il segmento di memoria che contiene il programma può crescere se il programma ha necessità?
- No
- Sì

--------------------------------------------------------------------------------
5. Avendo dichiarato int x[100]; che differenza c'è fra x e x[0]?
- x è un indirizzo, mentre x[0] è il primo dato contenuto nell'array
- Nessuna, sono entrambi riferimenti all'indirizzo prima cella

--------------------------------------------------------------------------------
6. Avendo dichiarato int x[100]; che differenza c'è fra x e &x[0]?
- Nessuna, sono entrambi riferimenti all'indirizzo prima cella
- Sono diversi in quanto uno punta all'array mentre l'altro e' l'indirizzo del primo elemento

--------------------------------------------------------------------------------
7. Avendo la seguente dichiarazione: float * p; si evince che p è:
- nulla, la riga è sbagliata
- un puntatore a float
- un puntatore flottante
- un puntatore con un cast a float

--------------------------------------------------------------------------------
8. Avendo definito int i; e int *pi; cosa vuole dire che è possibile fare in modo che pi punti a i?
- Che pi è una cella che conterrà l'indirizzo della variabile i
- Che saranno la stessa cosa e potrò intercambiarli nel codice.
Esercizio 2: Studio indirizzi di un vettore
Compila il seguente codice salvando il file con il nome di indirizzi_Vettore.c:
//indirizzi_Vettore.c
#include <stdio.h>
#include <stdlib.h>

int main()
{
    int i, x[100];

    for(i=0; i<100; i++) x[i]=i+1;  // riempiamo il vettore

    printf("Il valore di x e' %d\n", x);
    printf("Il valore di x[0] e' %d\n", x[0]);
    printf("L'indirizzo di x[0] e' %d\n", &x[0]);
    printf("Il valore di x[99] e' %d\n", x[99]);
    printf("L'indirizzo di x[99] e' %d\n", &x[99]);
    printf("La memoria occupata dal vettore e' %d\n",
        (void *)&x[99]+sizeof(int)-(void *)&x[0]);
    getchar();
    return 0 ;
}
Quindi segui quanto di seguito elencato:
  1. studia i valori delle printf stampati a monitor;
  2. controlla se la distanza in memoria fra gli elementi è quella che immaginavi
  3. verifica perché è stata usata la riga:
    printf("La memoria occupata dal vettore e' %d\n", (void *)&x[99]+sizeof(int)-(void *)&x[0]);
    e non una semplice differenza fra indirizzi, ad esempio:
    &x[99] - &x[0]
soluzione.
Esercizio 3: Puntatori ed indirizzi
Per ognuna delle richieste di seguito elencate scrivere una singola riga di codice.
Assumi che siano già state dichiarate due variabili in virgola mobile n1 e n2, e che n1 sia stata inizializzata a 3,14.
1. Dichiara fp che punti ad un tipo di dato float. 
2. Assegna l'indirizzo della variabile n1 a fp. 
3. Visualizza il valore dell'oggetto puntato da fp. 
4. Assegna a n2 il VALORE dell'oggetto puntato da fp. 
5. Visualizza il valore di n2. 
6. Visualizza l'indirizzo di n1 (usare la printf con il parametro "%p") . 
7. Visualizza l'indirizzo memorizzato in fp (usare la printf con il parametro "%p") e verifica se è uguale a quello del punto 6.
soluzione.
Esercizio 4: Puntatori ed array
Scrivi una programma che presenti i seguenti requisiti:
1. dichiara un array A di 5 elementi interi 
2. dichiara un puntatore ad intero p 
3. associa l'indirizzo di inizio di A (A oppure &A[0] ) al puntatore p 
4. inizializza questo array con i numeri crescenti 5,6,7,8,9 
5. stampa gli elementi con il ciclo for indirizzando gli elementi dell'array con il classico modo A[i] nella printf 
6. stampa nuovamente l'array A usando l'aritmetica dei puntatori, indirizzando gli elementi con *(p +i ) 
7. verificare se, indirizzando gli elementi con *p + i, il programma funziona in modo corretto. 

Suggerimento
La stampa degli elementi dell'array A puo' essere implementata mediante la riga
printf("Elemento -->  %d", A[i]);  nel ciclo for.
La stampa dell'array A con puntatori si ottiene mediante una porzione di codice del tipo
printf("Elemento -->  %d", *(p +i );  nel ciclo for.
Indirizzare gli elementi dell'array A con *p + i e' comunque corretto, nonostante in C l'operatore '*' abbia precedenza sull'operatore '+'. Questo e' pero' dovuto ad una pura casualita' di valori consecutivi degli elementi del vettore A (5,6,7,8,9) fanno si' che il risultato ottenuto con *(p+i) e *p +i sia lo stesso. Tuttavia, onde evitare spiacevoli errori difficilmente rilevabili, si consiglia di utilizzare SEMPRE le parentesi; in questo modo ne giova anche la leggibilita' del codice.

soluzione.
Esercizio 5: Tipi di dato e visualizzazione
Individua gli errori nelle istruzioni di seguito elencate:
1. per visualizzare il carattere 'c' 
		printf("%s\n" , 'c' );
2. per visualizzare il seguente numero in percentuale 4,345% 
		printf("%.3f%" , 4,345 ); 
3. per visualizzare il carattere della stringa "gennaro" 
		printf("%c\n" , "gennaro" );
4. printf(%d%d , 13, 17); 
5. printf("%s\n" , 'MariaChiara' );
soluzione.
Esercizio 6: Studio tipo di dato strutturato
Considera la seguente traccia:
// MissItalia.c
#include <stdio.h>
#include <stdlib.h>

typedef struct
	{
		char nome[256] ;
		char cognome[256] ;
  		int voto[3];  // voto[0] e' il voto della giuria (da 0 a 100),
  		              // voto[1] quello della giuria speciale e voto[2] il voto
  		              // telefonico.
  		int altezza;
  		int peso;
  		int cucina;    // 0= aiuto!!!  10= apre un ristorante
 	} MissItalia;     // Iniziale maiuscola


int main()
{
	int i; 

	MissItalia ragazza1;
	MissItalia * p1;

	MissItalia ragazza2;
	MissItalia * p2;

       p1 = &ragazza1;
       p2 = &ragazza2;

	// inseriamo la prima ragazza
	printf("Dammi il nome -->");
	scanf("%s", p1->nome );
	printf("Dammi il cognome -->");
	scanf("%s", p1->cognome );

	p1->altezza   = 180;
	p1->voto[0] = 80;
	p1->voto[1] = 90;
	p1->voto[2] = 99;
	p1->peso      = 78;
	p1->cucina    = 0;  // aiuto!!!

	// inseriamo la seconda ragazza
	printf("Dammi il nome -->");
	scanf("%s", p2->nome );
	printf("Dammi il cognome -->");
	scanf("%s", p2->cognome );

	p2->altezza   = 180;
	p2->voto[0] = 85;
	p2->voto[1] = 85;
	p2->voto[2] = 90;
	p2->peso      = 88;
	p2->cucina    = 10;  // meglio...
    
	

	// stampo i dati immessi
	printf("\n\n\n------------****------------\n");
	printf("Nome:%s   Cognome:%s \n", p1->nome , p1->cognome );
	printf("altezza:%d   Peso:%d \n", p1->altezza, p1->peso  );
	printf("voto: %d %d %d  \n", p1->voto[0] , p1->voto[1] , p1->voto[2]  );
	printf("cucina [0=aiuto .. 10=professionista] = %d \n", p1->cucina );

       // stampo i dati immessi
	printf("\n\n\n------------****------------\n");
	printf("Nome:%s   Cognome:%s \n", p2->nome , p2->cognome );
	printf("altezza:%d   Peso:%d \n", p2->altezza, p2->peso  );
	printf("voto: %d %d %d  \n", p2->voto[0] , p2->voto[1] , p2->voto[2]  );
	printf("cucina [0=aiuto .. 10=professionista] = %d \n", p2->cucina );

	// inserire qui il codice della comparazione
 

}
Scrivi il codice che:
  1. mostra le differenze di punteggio fra le due concorrenti i cui dati sono stati immessi;
  2. mostra la differenza di indirizzo di memoria fra p1 e p2.


soluzione.
Esercizio 7 (ripasso programmazione)
Scrivi il programma bisestile.c che chiede all'utente un numero e stampa a monitor se trattasi di un anno bisestile.

Considera come bisestile un anno divisibile per quattro tranne quelli secolari che non sono multipli di 400.
Attenzione: l'espressione (anno % 4) vale 0 se la variabile anno è divisibile per 4 senza resto.
soluzione.

Esercizio 8(ripasso programmazione)
Completa e salva il programma espressioni.c sottoriportato affinche' stampi con delle semplici printf il valore delle seguenti ESPRESSIONI :
  1. (a + b + c + d)
  2. (a + b + c + d++)
  3. (a + b + c + ++d)
  4. (a = 7)
  5. (a == 8)
  6. (a *= 9)
  7. ( x[0] )
  8. ( x[0]==5 )
  9. ( x[a=11]==6 )
  10. ( 1,2,3,4 )
  11. ( 1,2,3, a=7 )
Il valore delle espressioni e' quello che prevedevi? Quali di loro hanno cambiato il valore delle variabili?
// espressioni.c
#include <stdio.h>
#include <stdlib.h>
int main()
{
	int a,b,c,d; 
	int x[3];
	
	a=1;b=1;c=1;d=1;
	x[0]=1; x[3]=1;x[2]=1;

	/* aggiungi il codice che serve per visualizzare
	   il valore delle espressioni richieste */
	   
	return 0;
}
soluzione.





Informazioni sul sito