1 fondamenti di informatica ii ingegneria gestionale a.a. 2001-2002 - 4° ciclo puntatori e stringhe
TRANSCRIPT
1
FONDAMENTI DI INFORMATICA IIIngegneria Gestionale
a.a. 2001-2002 - 4° Ciclo
Puntatori e Stringhe
2
PUNTATORI
Definizione:
Per puntatore s’intende una variabile che contiene l’indirizzo di un’altra variabile. Quest’ultima a sua volta può contenere un valore specifico.
Rappresentazione grafica:
varPoint var
1000
Variabile puntatore, di nome varPoint, contenente l’indirizzo della variabile di nome var
Variabile di nome var contenente il valore specifico 1000
3
PUNTATORI
Dichiarazione di puntatore:
Tipo_Variabile …., * Nome_Puntatore, ……..
Esempi:
int *varPoint;float *latPtr, *longPtr;long *varPtr, var,……;
Inizializzazione di un puntatore:
Si può inizializzare un puntatore con un puntamento a nessuna variabile in uno dei due seguenti modi.
varPoint= NULL;
varPoint=0;
4
PUNTATORI
Operatore di indirizzo &:
L’operatore di indirizzo & è un operatore unario che restituisce l’indirizzo del suo operando. L’operando di & deve essere un lvalue, ossia un oggetto a cui si può assegnare un valore. In modo simbolico si può scrivere:
Tipo_Variabile …., * Nome_Puntatore, …, Nome_Variabile,..;
Nome_Puntatore= &Nome_Variabile;
Esempio:
int var, *varPtr;
varPtr= &var;
5
PUNTATORI
Operatore * di risoluzione dei riferimenti:
L’operatore * di risoluzione dei riferimenti (detto anche di deferenziazione) è un operatore unario su operandi di tipo puntatore che restituisce un alias della variabile puntata. L’alias permette di acquisire il valore della variabile o di assegnargli un nuovo valore.
Tipo_Variabile …., * Nome_Puntatore,.. Nome_VarA,.. Nome_VarB;……………..Nome_Puntatore= &Nome_VarA;……………..Nome_VarB = * Nome_Puntatore:Esempio:
int interoA, interoB , *varPtr;
interoA= 10;
varPtr= &interoA;
interoB= *varPtr; //Assegna il valore di interoA a interoB
6
PUNTATORIAssociatività
Gli operatori & e * associano da destra verso sinistra. Ossia se si considera l’espressione che segue in cui varPtr è un puntatore a cui è stato assegnato l’indirizzo della variabile var
&*varPtr
tutto va come se si dovesse applicare l’operatore & a ciò che viene restituito da *varPtr. Poiché *varPtr restituisce var, l’applicazione dell’operatore & restituisce l’indirizzo di var. Nel caso inverso:
*&varPtr
tutto va come se si dovesse applicare l’operatore * a ciò che viene restituito da &varPtr. Poiché &varPtr restituisce l’indirizzo di varPtr, l’applicazione dell’operatore * restituisce il contenuto di varPtr, ossia proprio l’indirizzo di var. Gli operatori & e * sono quindi l’uno l’inverso dell’altro.
7
PUNTATORIChiamata per riferimento con argomenti di tipo puntatore
Un puntatore può essere passato come argomento di una chiamata a funzione. In questo caso il prototipo della funzione deve contenere la dichiarazione del puntatore:
....Nome_Funzione (…, Tipo_Variabile *, ….);
L’invocazione della funzione deve contenere in corrispondenza un puntatore (o un valore di puntatore):
Nome_Funzione (…., Nome_Puntatore, ……);
L’implementazione della funzione deve contenere in corrispondenza la dichiarazione della variabile puntatore locale:
…Nome_Funzione (….., Tipo_Variabile *Nome_Variabile, ….)
{ ….// Deferenziando Nome_variabile si accede al contenuto della variabile puntata da Nome_Puntatore nell’invocazione della funzione.
}
8
PUNTATORIEsempio di argomenti di tipo puntatore:void funct (int *); // Prototipo della funzioneint var…………funct (&var); // Invocazione della funzione………..void funct (int *localVar) // Implementazione della funzione{ ……. *localVar …….. // Accesso al contenuto di var} Nota:
questo esempio e le notazioni simboliche della pagina precedente fanno riferimento al caso di un passaggio di puntatore non costante a dati non costanti. In altre parole sia i puntatori che i dati puntati possono essere modificati. Per evitare che il valore di una variabile sia modificato si deve utilizzare il qualificatore const.
9
PUNTATORIUtilizzo dell’attributo const:
• Dichiarazione di puntatore costante a dati non costanti.
Tipo_Variabile *const Nome_Puntatore;
• Dichiarazione di puntatore non costante a dati costanti:
const Tipo_Variabile *Nome _Puntatore;
• Dichiarazione di puntatore costante a dati costanti:
const Tipo_Variabile *const Nome _Puntatore;
Nota:
Le dichiarazioni suddette inserite come dichiarazioni di parametri corrispondenti nel prototipo e nell’implementazione di una funzione permettono di rendere nell’ambito del codice della funzione i puntatori e/o i dati da essi puntati di tipo a sola lettura (read only).
10
PUNTATORIEsempio di passaggio di puntatore non costante a dati costanti:void funct (const int *); //Prototipo della funzioneint kappa;funct (&kappa); //Invocazione della funzione………………..Void funct (const int *varPtr) //Implementazione della funzione{ …….. //Non è ammesso fare un’assegnazione del tipo:
*varPtr= 100;}
11
PUNTATORIRestituzione di una variabile puntatore da una funzione:
Una chiamata a funzione può restituire una variabile puntatore. In questo caso il prototipo della funzione deve contenere la dichiarazione del tipo di puntatore in restituzione:
Tipo_Variabile *Nome_Funzione (……….);
L’invocazione della funzione può quindi essere assegnata ad una variabile puntatore del tipo dichiarato nel prototipo:
Tipo_Variabile *Nome_Variabile_Puntatore, ….;
Nome_Variabile_Puntatore = Nome_Funzione (……);
L’implementazione della funzione deve ripetere la dichiarazione del tipo di puntatore in restituzione (uguale a quella del prototipo) e la parola riservata Return deve essere seguita da un valore o variabile puntatore sempre dello stesso tipo:
Tipo_Variabile *Nome_Funzione (………..)
{……….return Nome_Variabile_Puntatore; }
12
PUNTATORIEsempio di funzione che restituisce un puntatore:
…………..
float *Calcola (float, int); //Prototipo
…………..
float *retPtr, retCalc;
retPtr= Calcola (7.5, 10); //Invocazione
……………..
float *Calcola (float datoF, int datoI) //Implementazione
{…………..
float *localPtr;
……………
return localPtr;
}
13
PUNTATORI
Operatore sizeof:
L’operatore unario sizeof restituisce la dimensione in byte dell’operando che può essere un array o un dato qualsiasi. L’operando di sizeof deve essere racchiuso tra parentesi tonde se è il nome di un tipo di dato (come int, float, ..) altrimenti non è necessario. La seguente operazione:
..sizeof Nome_Array/sizeof (Tipo_Dato_Array)
restituisce la lunghezza dell’array in elementi.
14
PUNTATORIEsempio di applicazione di sizeof:
………………..
int beta [ ]= {10, 20, 30, 40, 50};
int dim;
……………….
dim= sizeof beta/sizeof(int); //Assegna il valore 5 a dim
……………….
15
PUNTATORIAritmetica dei puntatori:
I casi considerati sono quelli di puntatori ad elementi di array, di tipo qualsiasi, e quindi di lunghezza in byte dipendente dal tipo.
Operazione sul puntatore:
Incremento (++)
Decremento (--)
Somma di un intero n
Sottrazione di un intero n
Indirizzo risultante:
Punta all’elemento successivo
Punta all’elemento precedente
Punta all’elemento dopo n elementi
Punta all’elemento precedente di n elementi
Si possono anche fare differenze tra puntatori, purché dello stesso array e, in tal caso, il risultato è un numero intero corrispondente alla distanza tra i due puntatori in numero di elementi dell’array.
16
PUNTATORI
Assegnazione tra puntatori:
Si può assegnare un puntatore ad un altro dello stesso tipo o, in generale, usando l’operatore cast, ad un altro di tipo diverso.
Puntatore di tipo void
Tutti i tipi di puntatore possono essere assegnati ad un puntatore di tipo void (void *), che è un tipo generico, ma non è vero il contrario. Un puntatore di tipo void non può nemmeno essere deferenziato
Puntatori ed operatori relazionari
Gli operatori relazionari possono essere utilizzati per confrontare i puntatori, ma ciò ha normalmente senso per puntatori ad elementi di uno stesso array.
17
PUNTATORICorrelazione tra puntatori e array
La dichiarazione di un array, come la seguente:
Tipo_Variabile …., Nome_Array [Dimensione_Array], …
comporta la dichiarazione di un puntatore costante al primo elemento dell’array di nome Nome_Array. In base a ciò l’accesso ad un elemento dell’array può ottenersi con uno dei seguenti modi:
Indicizzazione dell’array: Nome_Array [Variabile _Indice]
Nome dell’array e offset: *(Nome_Array + Variabile_Indice)
Indicizzazione di puntatore: Puntatore_1°_Elemento [Variabile_Indice]
Puntatore e offset: *(Puntatore _1°_Elemento + Variabile_Indice)
18
PUNTATORIEsempi di modi di accesso ad un array:
float floatArray [10], *floatPtr, floatVar;
int index;
floatPtr= floatArray; //Equivalente a: floatPtr= &floatArray[0];
index= 5;
floatVar= floatArray [index];
floatVar= floatArray [5];
floatVar= *(floatArray + index);
floatVar= floatPtr [index];
floatVar= *(floatPtr + index);
19
PUNTATORIPuntatori a Funzioni
Una funzione può accettare in input un puntatore ad un’altra funzione. Ciò è possibile perché il nome di una funzione è un puntatore alla funzione stessa. Il prototipo assume l’aspetto:
…. Nome _Funzione_A (…, Tipo_Restituito (*) (Lista_Tipi), ….);
La corrispondente invocazione di funzione è:
Nome_Funzione_A (…., Nome_Funzione_B, ……..);
dove Nome_Funzione_B deve corrispondere ad una funzione che ha il Tipo_Restituito e la Lista_Tipi identici a quelli indicati nel prototipo: possono esistere più funzioni con queste caratteristiche. L’implementazione è infine:
..Nome_Funzione_A (.., Tipo_Restituito(*Nome_Funzione_Locale) (Lista_Tipi), …..)
{ …….(*Nome_Funzione_Locale) (Lista_Argomenti);……..
}
20
PUNTATORIEsempio di passaggio di puntatore a funzione:
void funzA (int, int, int (*)(float, int), float); //Prototipo della funzione
int funzB (float, int); //Prototipi delle funzioni che possono essere
int funzC (float, int); //passate come parametri con il loro puntatore
………………………..
funzA (3, 5, funzC, 3.5) //Invocazione della funzione
……………………….. //Implementazione della funzione:
funzA (int var1, int var2, int (*localFunz) (float, int), float var3)
{ ………//Invocazione della funzione passata con un puntatore:
(*localFunz) (var3, 6); ………………...
}
21
STRINGHECostanti carattere:
Una costante carattere è un carattere racchiuso tra apici singoli e corrisponde ad un numero intero che è il codice ASCII di quel carattere. Sono costanti carattere: ‘a’, ‘b’, …’z’, ‘\n’. Quest’ultimo è il valore intero di new line.
Costanti stringa:
Una costante stringa è una sequenza di caratteri racchiusi tra doppi apici che vengono trattati come un’entità singola. Una costante stringa è: “abcde”.
Stringhe:
Una stringa è un array di caratteri che termina con il carattere nullo (‘\0’). Il valore di una stringa è quindi l’indirizzo costante del suo primo carattere.
22
STRINGHEDichiarazione ed inizializzazione di una stringa:
In base alla definizione di stringa la sua dichiarazione ed inizializzazione si può ottenere come segue:
char Nome_Stringa [ ]= {‘a’, ‘b’, ‘c’, … ‘z’, ‘\0’};
oppure, ricorrendo alle costanti stringa, nel modo seguente:
char Nome_Stringa[ ]= “abcd…z”;
in questo caso l’array di caratteri che compone la stringa conterrà un ultimo carattere in più, rispetto a quelli della costante stringa, automaticamente impostato a: ‘\0’.
Una stringa può anche essere inizializzata senza assegnargli un nome, ma dichiarando solo il puntatore al suo primo carattere con la dichiarazione:
char *Puntatore_alla_Stringa= “abcd….z”;
23
STRINGHE
Input di stringhe:
L’input di una stringa in un array di caratteri si può ottenere con l’operatore di estrazione dallo stream e cin nel modo seguente:
char Nome_Array [Dimensione_Array]; //Dichiarazione array
cin >> Nome_Array; //Input stringa
L’input termina alla digitazione di: spazio, tabulazione, new line o end of file. Non c’è controllo al superamento dell’ultimo posto dell’array. Ciò si può invece ottenere con l’operatore setw, che termina l’input dopo il carattere del penultimo posto e pone ‘\0’ nell’ultimo:
cin >> setw(Dimensione_Array) >> Nome_Array;
L’input di righe di testo complete si ottiene con la funzione: cin.getline (Nome_Array, Dimensione_Array, \n); per la quale l’input termina se si riempie il penultimo posto dell’array (nell’ultimo si pone: ‘\0’), oppure si digita new line o end of file.
24
STRINGHEFunzioni di libreria per le stringhe
Quelli che seguono sono i prototipi di funzioni di libreria che manipolano stringhe, confrontano stringhe, ricercano caratteri, segmentano stringhe, ne determinano la lunghezza, .. ecc.
char *strcpy (char *s1, const char *s2);
char *strcat (char *s1, const char *s2);
char *strncpy (char *s1, const char *s2, size_t n);
char *strncat (char *s1, const char *s2 , size_t n);
int strcmp (const char *s1, const char *s2);
int strncmp (const char *s1, const char *s2 , size_t n);
char *strtok (char *s1, const char *s2);
size_t strlen (const char *s):
25
RICHIAMI AI RIFERIMENTIChiamata a funzione con argomenti di tipo riferimento:
Un riferimento può essere passato come argomento di una chiamata a funzione. In questo caso il prototipo della funzione deve contenere la dichiarazione del riferimento:
….. Nome_Funzione (…., Tipo_Variabile &, …);
L’invocazione della funzione deve contenere in corrispondenza un nome di variabile che in tal caso viene passata per riferimento (ossia potrà essere direttamente riferita) invece che per valore:
…… Nome_Funzione (….., Nome_Variabile, …);
L’implementazione della funzione deve contenere in corrispondenza la dichiarazione del riferimento locale che si comporta come alias della variabile passata:
… Nome_Funzione (…., Tipo_Variabile &Nome_Locale_Variabile, …)
{…….//Attraverso il Nome_Locale_Variabile si accede direttamente in lettura/scrittura alla variabile passata nell’invocazione della funzione
……..}
26
RICHIAMI AI RIFERIMENTI
Esempio di argomento di tipo riferimento:
void funct (int &); // Prototipo della funzione
int var;
…………
funct (var); // Invocazione della funzione
………..
void funct (int &localVar) // Implementazione della funzione
{ ……. localVar = 10; // Accesso al contenuto di var
}
27
RICHIAMI AI RIFERIMENTIRestituzione di un riferimento da una funzione:
Una chiamata a funzione può restituire un riferimento al un alias. In questo caso il prototipo della funzione deve contenere la dichiarazione del tipo di riferimento in restituzione:
Tipo_Variabile &Nome_Funzione (……);
L’invocazione della funzione può quindi essere assegnata ad una variabile riferimento del tipo dichiarato nel prototipo:
Tipo_Variabile ……., &Nome_Variabile, ..;
Nome_Variabile = Nome_funzione (……..);
L’implementazione della funzione deve ripetere la dichiarazione del tipo di riferimento in restituzione (uguale a quella del prototipo) e la parola riservata return deve essere seguita dal nome di una variabile, sempre dello stesso tipo:
Tipo_variabile &Nome_Funzione (……….)
{…….. return Nome_Variabile; }
28
RICHIAMI AI RIFERIMENTI
Esempio di funzione che restituisce un riferimento:
…………..float &Calcola (float, int); //Prototipo…………..float &retCalc;retCalc= Calcola (7.5, 10); //InvocazioneretCalc= 10; //Accesso a localVar !……………..float &Calcola (float datoF, int datoI) //Implementazione{…………..
float localVar;……………
return localVar;}