Upload
lamthuan
View
216
Download
0
Embed Size (px)
Citation preview
Questo insieme di trasparenze è stato ideato e realizzato dai ricercatori e professori del Dipartimento di Informatica e Sistemistica dell’Università di Napoli. Esse possono essere impiegate liberamente per fini didattici esclusivamente senza fini di lucro, a meno di un esplicito consenso scritto degli Autori. Nell’uso dovrà essere esplicitamente riportata la fonte e gli Autori. Gli Autori non sono responsabili per eventuali imprecisioni contenute in tali trasparenze né per eventuali problemi, danni o malfunzionamenti derivanti dal loro uso o applicazione
Outline
• I linguaggi C e C++: introduzione• Elementi Lessicali• Commenti• Identificatori• Parole Chiave• Costanti Letterali• Costanti simboliche• I tipi• Le variabili• Istruzioni di Assegnamento• Assegnazione: esempi
Il linguaggio C
• Linguaggio di alto livello compilato• Bell Labs, USA• Standardizzato negli anni ’80• Caratteristiche
– Supporto ai tipi di dato strutturato– Supporto alla programmazione modulare– Meccanismi di basso livello che consentono uso efficiente
delle risorse hw– Integrato in Unix– Diffusi i compilatori per gli altri ambienti – Elevata portabilità
• Compilabilità del programma in diversi ambienti
Il linguaggio C++
• C “migliorato”
• Bell Labs, anni ‘90
• Mantiene le caratteristiche positive del linguaggio C
• Tra i miglioramenti:
– Supporto alla programmazione ad oggetti
• Approccio bottom-up
Elementi lessicali
• Un programma, scritto in un qualsiasi linguaggio di programmazione, prima di essere eseguito viene sottoposto ad un processo di traduzione
• Lo scopo di questo processo è quello di tradurre il programma originale (codice sorgente) in uno semanticamente equivalente, ma eseguibile su una certa macchina
• Il processo di compilazione è suddiviso in più fasi, ciascuna delle quali volta all'acquisizione di opportune informazioni necessarie alla fase successiva
Elementi lessicali
• La prima di queste fasi è nota come “analisi lessicale” ed ha il compito di riconoscere gli elementi costitutivi del linguaggio sorgente, individuandone anche la categoria lessicale
• Ogni linguaggio prevede un certo numero di categorie lessicali e in C++ possiamo distinguere in particolare le seguenti categorie:– Commenti;– Identificatori;– Parole riservate;– Costanti letterali;– Segni di punteggiatura e operatori;
Commenti
• I commenti, come in qualsiasi altro linguaggio, hanno valore soltanto per il programmatore e vengono ignorati dal compilatore.
• È possibile inserirli nel proprio codice in due modi diversi:– racchiudendoli tra i simboli /* e */– facendoli precedere dal simbolo //
• Nel primo caso e` considerato commento tutto quello che è compreso tra /* e */, il commento quindi si può estendere anche su più righe o trovarsi in mezzo al codice..
Identificatori
• Gli identificatori sono simboli definiti dal programmatore per riferirsi a cinque diverse categorie di oggetti:
– Variabili;
– Etichette;
– Tipi definiti dal programmatore;
– Funzioni;
– Costanti simboliche;
Oggetti dotati di identificatori
• Variabili– Le variabili sono contenitori di valori di un qualche
tipo – Ogni variabile può contenere un singolo valore che
può cambiare nel tempo– Il tipo di questo valore viene stabilito una volta per
tutte e non può cambiare
• Etichette– Una etichetta è un nome il cui compito è quello di
identificare una istruzione del programma – Le etichette sono utilizzate dalle istruzioni di salto
incondizionato (“goto”)
Oggetti dotati di identificatori
• Tipi– Un tipo identifica un insieme di valori e di operazioni definite su
questi valori– C/C++ (come ogni linguaggio) fornisce
• un certo numero di tipi primitivi (cui è associato un identificatore predefinito)
• dei meccanismi per permettere ai programmatori la costruzione di nuovi tipi a partire dai tipi primitivi
– Ai nuovi tipi i programmatori associano un identificatore
• Funzioni– In C/C++ i sottoprogrammi si chiamano “funzioni”
• Costanti simboliche– Le costanti simboliche servono ad identificare valori che non
cambiano nel tempo
Identificatori
• Un identificatore deve iniziare con una lettera o con carattere di underscore (_), seguiti da un numero qualsiasi di lettere, cifre o underscore
• Viene fatta distinzione tra lettere maiuscole e lettere minuscole
• Tutti gli identificatori presenti in un programma devono essere diversi tra loro, indipendentemente dalla categoria cui appartengono
Parole chiave
• Il C/C++, così come ogni linguaggio di programmazione, si riserva delle parole chiave (keywords) il cui significato è prestabilito e che non possono essere utilizzate dal programmatore come identificatori
• Sono inoltre da considerare parole chiave tutte quelle che iniziano con un doppio underscore __;– riservate per le implementazioni del linguaggio e per le librerie standard
Costanti letterali
• Valori prefissati inseriti all’interno del programma
• Si possono avere– Costanti intere
– Costanti reali
– Costanti di tipo carattere• Racchiuse tra apici singoli
– Costanti di tipo stringa• Racchiuse tra apici doppi
Costanti intere
• Una costante intera può essere:
– Una sequenza di cifre decimali, eventualmente con segno;
– Uno 0 (zero) seguito da un intero, in ottale (base 8);
– 0x o 0X seguito da un intero, in esadecimale (base 16);
• Nella rappresentazione in esadecimale, oltre alle cifre decimali, è consentito l'uso delle lettere da "A" a "F" e da "a" a "f“
• Esempio
Costanti intere• Il segno può essere espresso solo in base 10, negli altri casi esso è
sempre +• La base in cui viene scritta la costante determina il modo in cui essa
viene memorizzata • Il compilatore sceglierà il tipo da utilizzare sulla base delle seguenti
regole:– Base 10: il più piccolo atto a contenerla tra
• int, • long int, unsigned long int
– Base 8 o 16: il più piccolo atto a contenerla tra • int, unsigned int, • long int, unsigned long int
• Si può forzare il tipo da utilizzare aggiungendo alla costante un suffisso costituito da “u” o “U” e/o “l” o “L”
Costanti reali• Si esprimono sia in virgola fissa esplicitando la
posizione del punto …– Esempi: -10.1, +0.005, -0.001
• Sia in virgola mobile– Segno, Mantissa
– “e” o “E”
– Segno, esponente
– Esempi: 0.1e-23, 10.00003e10, -1.3e-99, 0.1E12
• Il tipo scelto per rappresentare una costante reale è double, se non diversamente specificato utilizzando i suffissi “F” o “f” per float, o “L” o “l” per long double
Costanti simboliche
• Utili per fare riferimento a valori costanti ricorrenti o semplicemente utilizzati nel programma
• Costanti tipizzate– Variabili il cui valore è dichiarato costante nel corpo del
programmaconst tipo_var nome_var = valore_const;Ogni tentativo di modifica della variabile nome_var verrà segnalato
come errore in fase di compilazione
• Costanti non tipizzate dichiarate mediante direttiva di precompilazione #define
#define nome_const valore_const Il compilatore sostituirà ad ogni occorrenza di nome_const il valore
valore_const
• “valore_const” è una costante letterale
Differenze
• Costanti non tipizzate– La direttiva # define NOME valore produce la
sostituzione di tutte le successive occorrenze di NOME con valore (vengono sostituiti i simboli con i valori corrispondenti)• non provoca allocazione di memoria
– Il valore delle costanti può essere cambiato modificando solo la direttiva #define corrispondente
– Il tipo dell’valore è implicitamente determinato dal compilatore
– Devono essere dichiarate nel contesto delle direttive di precompilazione
Differenze
• Costanti tipizzate
– Sono a tutti gli effetti delle variabili, di valore però immodificabile
– Il tipo è esplicitamente dichiarato dal programmatore
– Possono essere dichiarate in diversi punti del programma
Il concetto di tipo
• Il “tipo” rappresenta un insieme di elementi all’interno del quale può essere scelto un valore.
• Se un’informazione è di un certo tipo, il suo valore sarà costituito da un elemento all’interno del relativo insieme
• Rappresentazione dell’informazione – TIPO, VALORE, ATTRIBUTO
• Per es. il tipo intero raggruppa in un insieme tutti i numeri interi ed, in astratto, ha cardinalità infinita (tipo)
• Un’informazione di tipo intero sarà costituita, dunque, da un numero intero (valore)
• L’attributo relativo all’informazione indica poi il significato da associare ad essa (attributo)
Tipi semplici e strutturati
• Un tipo semplice contiene un’informazione atomica, non divisibile, cioè, in più informazioni singolarmente significative
• Un tipo strutturato contiene un’informazione divisibile in più sotto-informazioni, ciascuna di queste, a loro volta, di tipo semplice o strutturato
• Per es.:– il tipo numero intero è un tipo semplice;
– il tipo numero complesso è un tipo strutturato;
– il tipo studente universitario è un tipo strutturato
Il concetto di variabile
• La “variabile” è un elemento presente pressoché in tutti i linguaggi di programmazione
• Essa può essere considerata come il “contenitore” usato per memorizzare un’informazione
• Ogni qualvolta, cioè, che un’informazione deve essere memorizzata, è necessario utilizzare una apposita variabile
Le variabili in C++
• Ogni variabile, prima di poter essere utilizzata, deve essere dichiarata.
• Questo è necessario, innanzitutto, per fare in modo che il calcolatore, all’atto dell’esecuzione del programma, possa preparare in anticipo lo spazio in memoria per ospitare la variabile (e quindi l’informazione).
• Questa operazione viene definita “allocazione”
• Lo spazio deve essere tanto maggiore quanto più l’informazione è “articolata”
Le variabili in C++
• L’informazione su quanto spazio allocare viene comunicata al calcolatore proprio all’atto della dichiarazione di una variabile– Ciò avviene attraverso l’associazione della variabile al tipo cui
essa appartiene
• Ogni volta che una variabile viene dichiarata, quindi, si specifica anche il tipo al quale essa appartiene– Essendo i registri di un calcolatore di dimensione finita ed in
numero finito, in un linguaggio di programmazione, il tipo individua sempre un insieme finito e ben preciso di elementi
– Il calcolatore, all’atto dell’allocazione di una variabile, conoscendo la cardinalità del tipo, può dedurre quanto grande deve essere lo spazio da allocare
I tipi nei linguaggi di programmazione
• Ogni linguaggio introduce una serie di tipi predefiniti (“built-in”)
• Questi sono i tipi che l’utente può direttamente utilizzare
• In genere i tipi predefiniti sono quelli necessari per le applicazioni più generiche: interi, reali, caratteri, stringhe di caratteri…etc.
Tipi atomici fondamentali
• I tipi fondamentali predefiniti dal linguaggio C++ sono:
• bool (valore logico)
• char (carattere)
• int (intero)
• float (reale)
• double (reale)
Memoria occupata
• La quantità di memoria allocata per ogni tipo predefinito dipende può variare con l’architettura dell’elaboratore e con l’implementazione del compilatore– the sizes of even primitive types in C and C++ are implementation-
defined (that is, not precisely defined by the standard).– even though most implementations of C and C++ on 32-bit systems
define type int to be 4 bytes, the size of an int could change when code is ported to a different system
• Per ottenere la occupazione effettiva di memoria di un tipo il linguaggio fornisce la funzione sizeof– Es:
• sizeof(int);• long int a;
sizeof(a);
Tipi primitivi predefiniti
• Ad essi possono essere applicati i qualificatori signed, unsigned, short e long
• Questi qualificatori non sono applicabili a tutti i tipi indifferentemente
• In particolare le configurazioni possibili sono:– short int– long int– unsigned char– unsigned short int– unsigned int– unsigned long int– long double
Definire nuovi tipi
• Alcuni linguaggi, come anche il C++, danno comunque la possibilità di costruire nuovi tipi per le specifiche esigenze
“typedef”, “enum”
• I tipi possono essere costruiti mediante:– aggregazione dei tipi già esistenti;
– utilizzo di opportuni costrutti sintattici per la creazione di tipi del tutto nuovi• Ad es, tipi enumerativi
Tipi enumerativi
• Il nuovo tipo viene definito elencando tutti i possibili valori che ne fanno parte
• Esempio:– enum Colore {rosso, giallo, blu, verde};– typedef enum{r, g, b} Colore;
• Il compilatore associa ad ogni valore elencato un intero corrispondente alla posizione occupata a partire da 0
• I valori interi possono essere esplicitati– enum Colore{rosso=1, giallo=2, blu=4, verde=3};
Allocazione di una variabile
• La dichiarazione (allocazione) di una variabile, in C++, avviene con la seguente sintassi:
tipovar nomevar;
• Per es., per dichiarare una variabile di tipo intero, con il nome i, si scrive:
int i
• i è un’istanza del tipo intero
Esempio: allocazione di una variabile
• Supponiamo che una certa implementazione del C++ specifichi che una variabile appartenente al tipo int possa contenere un qualunque numero intero compreso tra 0 e 65535
• In questo caso, cosa succede nel calcolatore quando si scrive
int i;
• all’atto della sua dichiarazione viene allocata dal calcolatore un’area di memoria di 16 bit
Dopo l’allocazione
• Una volta allocata, una variabile può essere scritta e letta.• Subito dopo l’allocazione, che valore assume la variabile?• Subito dopo l’allocazione il valore di una variabile è
indeterminato– In particolare, il valore è impredicibile perché dipende dal
contenuto preesistente della particolare locazione di memoria che il calcolatore ha deciso di utilizzare per ospitare il dato
• Operazioni di lettura su una variabile allocata e non ancora inizializzata sono, quindi, del tutto prive di senso
• E’ necessario inizializzare una certa variabile prima di poterla usare assegnandole un valore
Inizializzazione
• È possibile inizializzare una variabile contemporaneamente all’atto della sua allocazione:
int a = 0;
char c = ‘g’;
• Questa, quando sensata, è una tecnica che aiuta ad evitare errori dovuti all’aver dimenticato variabili non inizializzate
Istruzione di assegnamento
• ll C/C++ è un linguaggio basato sul paradigma imperativo
• L'operatore di assegnamento è denotato dal simbolo = (uguale) e viene applicato con la sintassi:
< lvalue > = < rvalue >;• Il termine lvalue rappresenta un riferimento ad
una regione di memoria (in generale un identificatore di variabile),
• Mentre un rvalue è una qualsiasi espressione la cui valutazione produca un valore
Assegnamento: esempi
• variabile = espressione;
• il valore dell’espressione viene registrato (assegnato) alla variabile
Assegnamento
• Il risultato dell'assegnamento è il valore prodotto dalla valutazione della parte destra (rvalue) ed ha come effetto l'assegnazione di tale valore alla regione di memoria denotata nella parte sinistra (lvalue)
• L’assegnamento produce come risultato l’assegnazione del valore alla variabile: dopo l’assegnamento la valutazione della variabile produrrà lo stesso valore fino a che un nuovo assegnamento non verrà eseguito su di essa
Assegnamento
• Si osservi che una variabile può apparire sia a destra che a sinistra di un assegnamento, – se tale occorrenza si trova a destra, produce il valore contenuto
nella variabile– se invece si trova a sinistra, essa denota la locazione di memoria
da modificare
• Poiché un identificatore di variabile può trovarsi contemporaneamente su ambo i lati di un assegnamento è necessaria una semantica non ambigua: come in qualsiasi linguaggio imperativo (Pascal, Basic, ...) la semantica dell'assegnamento impone che prima si valuti la parte destra e poi si esegua l'assegnamento del valore prodotto all'operando di sinistra
Assegnamento
• NB: l’assegnamento non è una relazione di uguaglianza
– produce una modifica della memoria
Associatività dell’assegnamento
• Poiché un assegnamento produce come risultato il valore prodotto dalla valutazione della parte destra (è cioè a sua volta una espressione), è possibile legare in cascata più assegnamenti:– Clarabella = Pippo = 5;
• Essendo l'operatore di assegnamento associativo a destra, l'esempio precedente è da interpretare come– Clarabella = (Pippo = 5);
• cioè viene prima assegnato 5 alla variabile Pippo e il risultato di tale assegnamento (il valore 5) viene poiassegnato alla variabile Clarabella
Istruzioni di assegnamento
• Esistono anche altri operatori che hanno come effetto collaterale l'assegnazione di un valore
• La maggior parte di essi sono delle utili abbreviazioni
• Esempi:Pippo += 5; // equivale a Pippo = Pippo + 5;Pippo -= 10; // equivale a Pippo = Pippo - 10;Pippo *= 3; // equivale a Pippo = Pippo * 3;
• si tratta cioè di operatori derivanti dalla concatenazione dell'operatore di assegnamento con un altro operatore binario
Autoincremento e autodecremento
• Gli altri operatori che hanno come effetto laterale l'assegnamento sono quelli di autoincremento e autodecremento
• EsempiPippo++; // cioè Pippo += 1;++Pippo; // sempre Pippo += 1;Pippo--; // Pippo -= 1;--Pippo; // Pippo -= 1;
• Questi due operatori possono essere utilizzati sia in forma prefissa (righe 2 e 4) che in forma postfissa (righe 1 e 3)
• Il risultato comunque non è proprio identico poiché la forma postfissa restituisce come risultato il valore della variabile e poi incrementa tale valore e lo assegna alla variabile, la forma prefissa invece prima modifica il valore associato alla variabile e poi restituisce tale valore