Fondamenti di programmazione parte 1 -...

51
Fondamenti di programmazione parte 1 Elementi di informatica IGLP

Transcript of Fondamenti di programmazione parte 1 -...

Fondamenti di programmazioneparte 1

Elementi di informatica

IGLP

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

Dal programma sorgente al programma eseguibile

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..

Commenti

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

Segni di punteggiatura e operatori

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

Esempi

NB: l’occupazione di memoria è riferita ad un certo elaboratore

Dichiarazioni equivalenti

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

Esempio: allocazione di una variabile

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

Esempio

Esercizi

• Scambio del valore di due variabili

– Esempio

• Input: a = 10, b = 20

• Output: a = 20, b = 10

• Scambio del valore di tre variabili

– Esempio

• Input : a = 10, b = 20, c = 30

• Output: a = 20, b = 30, c = 10