SlideShare a Scribd company logo
12BHDxx Informatica
     Programmazione in C
Settimana n.1


Obiettivi                  Contenuti
• Problem solving          • Concetto di programma
• Diagrammi di flusso e    • Diagrammi di flusso
  pseudo codice            • Pseudo codice
                           • Alcuni problemi di esempio




                                                          2
Cosa impariamo in questo corso?
Dalla specifica di un problema alla sua realizzazione come
         programma da eseguire su un elaboratore


                 Costruzione di
                 un programma




                                                             3
Progettare

  Problema



 Soluzione



 Soluzione
  formale


Realizzazione


                4
Difficoltà

• I punti critici nello sviluppo di un progetto risiedono
  essenzialmente in:
  -   Sviluppo di una soluzione “informale”
  -   Formalizzazione di una soluzione
       • Permette una più semplice “traduzione” nelle regole di realizzazione


• La soluzione di un problema passa generalmente
  attraverso lo sviluppo di un algoritmo
                                                                        ???????




                                                                                  5
Algoritmo
Con il termine di algoritmo si intende la descrizione precisa
(formale) di una sequenza finita di azioni che devono
essere eseguite per giungere alla soluzione di un problema




                                                                6
Algoritmo
Il termine deriva dal tardo latino ”algorismus” che a sua
volta deriva dal nome del matematico persiano Muhammad
ibn Mūsa 'l-Khwārizmī (780-850), che scrisse un noto
trattato di algebra




                                                            7
Algoritmi e vita quotidiana


  1. metti l’acqua
2. accendi il fuoco
      3. aspetta
 4. se l’acqua non
  bolle torna a 3
 5. butta la pasta
 6. aspetta un po’
     7. assaggia
    8. se è cruda
      torna a 6
  9. scola la pasta




                                    8
Algoritmo

• Algoritmo: Sequenza di operazioni atte a risolvere un
  dato problema
  -   Esempi:
      • Una ricetta di cucina
      • Istruzioni di installazione di un elettrodomestico


• Spesso non è banale!
  -   Esempio:
      • MCD?
      • Quale algoritmo seguiamo per ordinare un mazzo di carte?




                                                                   9
Esempio di flusso

• Problema: Calcolo del massimo
                                       Problema
  tra due valori A e B

• Soluzione: Il massimo è il più
  grande tra A e B...                  Soluzione


• Soluzione formale:
                                       Soluzione
  1. inizialmente: max = 0
                                        formale
  2. se A >B allora max = A; stop
  3. altrimenti max = B; stop




                                                   10
Difficoltà

• I punti critici nello sviluppo di un programma risiedono
  essenzialmente in:
  -   Sviluppo di una soluzione “informale”
  -   Formalizzazione di una soluzione
       • Permette una più semplice “traduzione” nelle regole del linguaggio di
         programmazione


• La soluzione di un problema passa generalmente
  attraverso lo sviluppo di un algoritmo




                                                                                 11
Altro esempio di flusso

• Problema: Calcolo del massimo
  comun divisore (MCD) fra due           Problema
  valori A e B

• Soluzione: Usiamo la definizione di    Soluzione
  MCD...

• Soluzione formale: ???                 Soluzione
                                          formale




                                                     12
Stadi di sviluppo di un programma

1. Scrittura di un programma
    -    File “sorgente”                           Scrittura
                                               del programma
    -    Scritto utilizzando un linguaggio
         di programmazione


2. Traduzione di un programma in un              Traduzione
   formato comprensibile al calcolatore        del programma
    •    Articolato in più fasi
    •    Gestito automaticamente da un
         programma chiamato traduttore


•       In questo corso ci occuperemo del
        primo punto
    •    Ma è importante sapere cosa succede
         nella fase successiva!
                                                               13
Stadi di sviluppo di un programma
• Problema

• Idea
  -   Soluzione

• Algoritmo
  -   Soluzione formale

• Programma
  -   Traduzione dell‟algoritmo in una forma comprensibile ad un elaboratore
      elettronico

• Test

• Documentazione

                                                                               14
Formalizzazione della soluzione

• La differenza tra una soluzione informale ed una formale
  sta nel modo di rappresentare un algoritmo:
  -   Informale: Descrizione a parole
  -   Formale: Descrizione in termini di sequenza di operazioni
      elementari


• Esistono vari strumenti per rappresentare una soluzione
  in modo formale
  -   Più usati:
       • Pseudo-codice
       • Diagrammi di flusso




                                                                  15
Formalizzazione della soluzione (Cont.)

• Pseudo-codice
  -   Vantaggi
      • Immediato
  -   Svantaggi
      • Descrizione dell‟algoritmo poco astratta
      • Interpretazione più complicata


• Diagrammi di flusso
  -   Vantaggi
      • Più intuitivi perchè utilizzano un formalismo grafico
      • Descrizione dell‟algoritmo più astratta
  -   Svantaggi
      • Richiedono l‟apprendimento della funzione dei vari tipi di blocco


                                                                            16
Traduzione di un programma


  File
               Compilatore
sorgente


                                            Librerie
                               Linker      Librerie
                                          Librerie
                  File
                oggetto



  Questo file può essere        File
  direttamente caricato      eseguibile
  in memoria ed eseguito



                                                       17
Cosa vuol dire “programmare”?

• La programmazione consiste nella scrittura di un
  “documento” (file sorgente) che descrive la soluzione del
  problema in oggetto
  -   Esempio: Massimo comun divisore tra due numeri


• In generale non esiste “la” soluzione ad un certo
  problema
  -   La programmazione consiste nel trovare la soluzione più
      efficiente, secondo una certa metrica, al problema di interesse




                                                                        18
Cosa vuol dire “programmare”? (Cont.)

• Programmare è un‟operazione “creativa”!
  -   Ogni problema è diverso da ogni altro
  -   Non esistono soluzioni analitiche o “universali”!


• Programmare è un‟operazione complessa
  - Impensabile un approccio “diretto” (dal problema al
    programma sorgente definitivo)
  - Tipicamente organizzata per stadi successivi




                                                          19
Stadi di sviluppo di un programma (Cont.)

              Problema
                    Esperienza


              Soluzione
                      Strumenti automatici e
                      metodi formali
              Soluzione
               formale
                          Tecniche di programmazione
                          automatica

             Programma


                                                       20
Stadi di sviluppo di un programma (Cont.)

• La costruzione di un programma è generalmente
  un‟operazione iterativa

• Sono previsti passi a ritroso che rappresentano le reazioni
  a risultati non rispondenti alle esigenze nelle diverse fasi

• La suddivisione in più fasi permette di mantenere i passi
  a ritroso più brevi possibile (e quindi meno dispendiosi)

• E' necessario quindi effettuare dei test tra una fase e la
  successiva affinché i ricicli siano i più corti possibili


                                                                 21
Stadi di sviluppo di un programma (Cont.)

• Una volta scritto e collaudato il programma, possono
  verificarsi le seguenti situazioni:
  -   Il programma è stato scritto non correttamente:
      Torno indietro di un livello
  -   Il programma è descritto male in termini formali, ma corretto
      concettualmente:
      Torno indietro di due livelli
  -   Il programma è errato concettualmente, e necessita di una
      differente soluzione:
      Torno all'inizio




                                                                      22
Diagrammi di flusso
Diagrammi di flusso (flow-chart)

• Sono strumenti grafici che rappresentano l‟evoluzione
  logica della risoluzione del problema

• Sono composti da:
  -   Blocchi elementari per descrivere azioni e decisioni
      (esclusivamente di tipo binario)
  -   Archi orientati per collegare i vari blocchi e per descrivere la
      sequenza di svolgimento delle azioni




                                                                         24
Diagrammi di flusso: Blocchi di inizio/fine




       Start

                              Stop




                                              25
Diagrammi di flusso: Blocchi di azione




  azione                 azione
 generica                 di I/O




                                         26
Diagrammi di flusso: Blocco di decisione




         V     condizione   F




                                           27
Diagrammi di flusso: Blocco di connessione




                                             28
Diagramma di flusso : Esempio

           Start



             1



                     F
             2            5

                 V

             3           Stop



             4


                                29
Diagramma di flusso : Esempio



           Start




                                Stop



                                       30
Costruzione di diagrammi di flusso

• Per mezzo dei diagrammi di flusso si possono
  rappresentare flussi logici complicati a piacere

• E‟ però preferibile scrivere diagrammi di flusso strutturati,
  che seguano cioè le regole della programmazione
  strutturata

• Così facendo si ottiene:
  -   Maggiore formalizzazione dei problemi
  -   Riusabilità del codice
  -   Maggiore leggibilità



                                                                  31
Diagrammi di flusso strutturati
• Definizione formale:
  -   Diagrammi di flusso strutturati: Composti da strutture elementari
      indipendenti tra loro
  -   Struttura elementare = Composizione particolare di blocchi
      elementari
  -   Sempre riducibili ad un diagramma di flusso elementare costituito
      da un'unica azione


• Rispetto a diagrammi di flusso non strutturati questo
  implica l‟assenza di salti incondizionati all'interno del flusso
  logico del diagramma




                                                                          32
Diagrammi di flusso strutturati (Cont.)

• Un diagramma di flusso è detto strutturato se contiene
  solo un insieme predefinito di strutture elementari:
  - Uno ed uno solo blocco Start
  - Uno ed uno solo blocco Stop
  - Sequenza di blocchi (di azione e/o di input-output)
  - If - Then - ( Else )
  - While - Do
  - Repeat - Until




                                                           33
Sequenza




struttura-1

    .
    .
    .                    struttura


struttura-2


                                     34
If-Then-Else




      V       condizione     F



struttura-1                struttura-2




                                         35
If-Then




    V       condizione   F


struttura




                             36
While-Do




condizione
             F

     V

struttura


                 37
do - while




    struttura



    condizione
F
          V
                 38
Teorema di Böhm - Jacopini

        Qualunque diagramma di flusso è sempre
         trasformabile in un diagramma di flusso
           strutturato equivalente a quello dato



•   Quindi, qualunque flusso logico può essere realizzato
    utilizzando solamente due strutture di controllo:
    -   Meccanismo di decisione
    -   Meccanismo di ripetizione (loop)




                                                            39
Settimana n.2


Obiettivi                      Contenuti
• Utilizzo del compilatore e   • Uso del compilatore
  ciclo scrittura-             • Variabili (tipo int, float)
  compilazione-esecuzione.     • Scheletro base di un
• Struttura base di un           programma C
  programma in C.              • Espressioni aritmetiche ed
• Costrutti condizionali         operatori base (+ - * / %)
  semplici                     • Scanf e printf a livello
                                 elementarie
                               • Costrutto if e if-else
                               • Operatori relazionali

                                                               40
Dalla soluzione al programma

• La scrittura del programma vero e proprio è praticamente
  immediata a partire dalla soluzione formale

• I linguaggi di programmazione forniscono infatti costrutti
  di diversa complessità a seconda del tipo di linguaggio




                                                               41
Quali linguaggi?

• Diversi livelli (di astrazione)
  - Linguaggi ad alto livello
     • Elementi del linguaggio hanno complessità equivalente ai blocchi
       dei diagrammi di flusso strutturati (condizionali, cicli,…)
        - Esempio: C, C++, Basic, Pascal, Fortran, Java, etc.
        - Indipendenti dall‟hardware
  - Linguaggi “assembler”
     • Elementi del linguaggio sono istruzioni microarchitetturali
        - Dipendenti dall‟hardware
        - Esempio: Assembler del microprocessore Intel Pentium




                                                                          42
Quali linguaggi? (Cont.)

• Esempi:
  - Linguaggi ad alto livello
        …
        if (x > 3) then x = x+1;
        …



  - Linguaggi assembler
        …
        LOAD Reg1, Mem[1000]       Specifico per una specifica
        ADD Reg1, 10               architettura (microprocessore)
        …




                                                                    43
Elementi del linguaggio

• Essendo il linguaggio un‟astrazione, esistono alcuni
  fondamentali elementi sintattici essenziali per l‟uso del
  linguaggio stesso:
    - Parole chiave (keyword)
    - Dati
    - Identificatori
    - Istruzioni


• Gli elementi sintattici definiscono la struttura formale di
  tutti i linguaggi di programmazione



                                                                44
Parole chiave (keyword)

• Vocaboli “riservati” al traduttore per riconoscere altri
  elementi del linguaggio
  -   Le istruzioni sono tutte identificate da una keyword
  -   Esempio: La keyword PRINT in alcuni linguaggi identifica il
      comando di visualizzazione su schermo


• Non possono essere usate per altri scopi

• Costituiscono i “mattoni” della sintassi del linguaggio




                                                                    45
Dati

• Vista calcolatore:
  -   Dato = Insieme di bit memorizzato in memoria centrale


• Vista utente:
  -   Dato = Quantità associata ad un certo significato


• Il linguaggio di programmazione supporta la vista utente

• Dato individuato da:
  -   Un nome (identificatore)
  -   Una interpretazione (tipo)
  -   Una modalità di accesso (costante o variabile)

                                                              46
Identificatore

• Indica il nome di un dato (e di altre entità) in un
  programma

• Permette di dare nomi intuitivi ai dati

• Esempio:
  -   X, raggio, dimensione, …


• Nome unico all‟interno di un preciso “ambiente di
  visibilità”
  - Dati diversi = Nomi diversi!



                                                        47
Tipo

• Indica l‟intepretazione dei dati in memoria

• Legato allo spazio occupato da un dato

• Permette di definire tipi “primitivi” (numeri, simboli)
  indipendentemente dal tipo di memorizzazione del
  sistema




                                                            48
Tipo di accesso

• Indica la modalità di accesso ai dati:
  -   Variabili
       • Dati modificabili
       • Valore modificabile in qualunque punto del programma
  -   Costanti
       • Dati a sola lettura
       • Valore assegnato una volta per tutte




                                                                49
Astrazione dei dati


                                100
                                101
  X; intero;                3   102
  valore=3                      103
                           „a‟  104    Indirizzi
 c; carattere;
  valore=„a‟                    105
                                106
    t; reale;                   107
                        -11.564
valore=-11.564                  108

                        Memoria

                                                   50
Istruzioni

• Indicano le operazioni che il linguaggio permette di
  eseguire (traducendole) a livello macchina:
  -   Pseudo-istruzioni
      • Direttive non eseguibili
  -   Istruzioni elementari
      • Operazioni direttamente corrispondenti ad operazioni hardware
      • Esempio: Interazione con i dispositivi di I/O, modifica/accesso a dati
  -   Istruzioni di controllo del flusso
      • Permettono di eseguire delle combinazioni di operazioni complesse




                                                                                 51
Esempio di programma
PROGRAM prova;                                   Identificatori
// programma di prova Pseudo-istruzione         PAROLE CHIAVE
CONSTANTS
   pi = 3.14159
   coeff = 0.19         Specifica di celle di memoria
VARIABLES
   x: INTEGER         Specifica di tipo      Istruzione
   y: REAL                                  di controllo
   c: CHARACTER                              del flusso
BEGIN PROGRAM
   x = 2;                             Istruzioni
                                      elementari           Parte
    IF (y > 2) THEN y = x * pi;
                                                        “operativa”
    PRINT x, y;
END PROGRAM
                                                                 52
Linguaggio di programmazione

• Imparare un linguaggio significa conoscere:
  - Le parole chiave
  - I tipi predefiniti
  - Le istruzioni e la loro sintassi


• In questo corso:
  - Linguaggio C


• Estensione dei concetti a linguaggi analoghi è immediata




                                                             53
Linguaggio C
Genesi del linguaggio C


• Sviluppato tra il 1969 ed il 1973
  presso gli AT&T Bell Laboratories
  - B. Kernighan e D. Ritchie
  - Per uso interno
  - Legato allo sviluppo del sistema
    operativo Unix                     Brian Kernighan   Dennis Ritchie


• Nel 1978 viene pubblicato “The C
  Programming Language”, prima
  specifica ufficiale del linguaggio
  - Detto “K&R”


                                                                    55
Caratteristiche generali del linguaggio C
• Il C è un linguaggio:
  -   Imperativo ad alto livello
       • ... ma anche poco astratto
  -   Strutturato
       • ... ma con eccezioni
  -   Tipizzato
       • Ogni oggetto ha un tipo
  -   Elementare
       • Poche keyword
  -   Case sensitive
       • Maiuscolo diverso da minuscolo negli identificatori!
  -   Portabile
  -   Standard ANSI



                                                                56
Storia

• Sviluppo
  - 1969-1973
  - Ken Thompson e Dennis Ritchie
  - AT&T Bell Labs


• Versioni del C e Standard
  -   K&R (1978)
  -   C89 (ANSI X3.159:1989)
  -   C90 (ISO/IEC 9899:1990)
  -   C99 (ANSI/ISO/IEC 9899:1999, INCITS/ISO/IEC 9899:1999)


• Non tutti i compilatori sono standard!
  - GCC: Quasi C99, con alcune mancanze ed estensioni
  - Borland & Microsoft: Abbastanza C89/C90

                                                               57
Diffusione attuale

• I linguaggi attualmente più diffusi al mondo sono:
  -   C
  -   C++, un‟evoluzione del C
  -   Java, la cui sintassi è tratta da C++
  -   C#, estremamente simile a Java e C++
• Il linguaggio C è uno dei linguaggi più diffusi
• La sintassi del linguaggio C è ripresa da tutti gli altri
  linguaggi principali




                                                              58
Un esempio



#include <stdio.h>

int main(void)
{
   printf("hello, worldn");

    return 0;
}




                               59
Applicazioni “console”

• Interazione utente limitata a due casi
  - Stampa di messaggi, informazioni e dati a video
  - Immissione di un dato via tastiera
• L‟insieme tastiera+video viene detto terminale
• Nessuna caratteristica grafica
• Elaborazione
  - Sequenziale
  - Interattiva
  - Mono-utente




                                                      60
Modello di applicazioni “console”


  Scrittura                         somma.c
 programma            Programma
                     sorgente in C



                     Compilatore C


                                 somma.exe
                      Programma
                       eseguibile




                                        Visualizzazione
   Immissione dati
                                            risultati
                                                          61
Compilatore C        Compilatore C

 • Traduce i programmi sorgenti scritti in linguaggio C in
   programmi eseguibili
 • È a sua volta un programma eseguibile, a disposizione del
   programmatore
 • Controlla l‟assenza di errori di sintassi del linguaggio
 • Non serve all‟utente finale del programma
 • Ne esistono diversi, sia gratuiti che commerciali




                                                               62
Scrittura
programma       Scrittura del programma

• Un sorgente C è un normale file di testo
• Si utilizza un editor di testi
   - Blocco Note
   - Editor specializzati per programmatori




                                              63
Editor per programmatori

•   Colorazione ed evidenziazione della sintassi
•   Indentazione automatica
•   Attivazione automatica della compilazione
•   Identificazione delle parentesi corrispondenti
•   Molti disponibili, sia gratuiti che commerciali




                                                      64
Scrittura
programma
                Compilatore C            Ambienti integrati

 • Applicazioni software integrate che contengono al loro
   interno
    - Un editor di testi per programmatori
    - Un compilatore C
    - Un ambiente di verifica dei programmi (debugger)
 • IDE: Integrated
   Development
   Environment




                                                              65
Identificatori

• Si riferiscono ad una delle seguenti entità:
  -   Costanti
  -   Variabili
  -   Tipi
  -   Sottoprogrammi
  -   File
  -   Etichette


• Regole:
  -   Iniziano con carattere alfabetico o “_”
  -   Contengono caratteri alfanumerici o “_”




                                                 66
Identificatori (Cont.)

• Caratteristiche:
  -   Esterni: Gli oggetti del sistema
       • Case insensitive
       • Significativi almeno i primi 6 caratteri
  -   Interni: Le entità del programma
       • Case sensitive
       • Significativi almeno i primi 31 caratteri
  - Riservati:
       • Parole chiave del linguaggio
       • Elementi della libreria C standard




                                                     67
Commenti
• Testo libero inserito all‟interno del programma

• Non viene considerato dal compilatore

• Serve al programmatore, non al sistema!

• Formato:
   - Racchiuso tra /* */
   - Non è possibile annidarli
   - Da // fino alla fine della linea

• Esempi:
   /* Questo è un commento ! */
   /* Questo /* risulterà in un */          errore */
   // Questo è un altro commento


                                                        68
Parole chiave

• Riservate!

• Nel C standard sono 32
  auto              double   int        struct
  break             else     long       switch
  case              enum     register   typedef
  char              extern   return     union
  const             float    short      unsigned
  continue          for      signed     void
  default           goto     sizeof     volatile
  do                if       static     while

                                                   69
Parole chiave (Cont.)

• Riservate!

• Nel C99 sono 37 (in neretto quelle aggiunte nel C99)
 auto              break        case          char
 const             continue     default       do
 double            else         enum          extern
 float             for          goto          if
 inline            int          long          register
 restrict          return       short         signed
 sizeof            static       struct        switch
 typedef           union        unsigned      void
 volatile          while        _Bool         _Complex
 _Imaginary

                                                         70
Struttura di un programma C

• Struttura generale:



           Parte dichiarativa globale
           main()
           {
                 Parte dichiarativa locale
                  Parte esecutiva
           }



                                             71
Struttura di un programma C (Cont.)

• Parte dichiarativa globale
  -   Elenco degli oggetti che compongono il programma e specifica
      delle loro caratteristiche
       • Categoria degli oggetti
          -   Tipicamente dati
       • Tipo degli oggetti
          -   Numerici, non numerici



• main
  -   Parola chiave che indica il punto di “inizio” del programma quando
      viene eseguito dal sistema operativo
  -   Contenuto delimitato da parentesi graffe { … }




                                                                           72
Struttura di un programma C (Cont.)

• Parte dichiarativa locale
    -   Elenco degli oggetti che compongono il main e specifica delle
        loro caratteristiche


• Parte esecutiva
    -   Sequenza di istruzioni
    -   Quella che descriviamo con il diagramma di flusso!


•   Nel C99 è possibile alternare parti esecutive e parti
    dichiarative
    -   E` tuttavia consigliato non ricorrere troppo sovente a questa
        pratica



                                                                        73
Struttura di un programma C (Cont.)

• Programma minimo:


         main()                      Start
         {
         }                           Stop




                      file prova.c



                                             74
Notazione

• Per specificare la sintassi di un‟istruzione utilizziamo un
  formalismo particolare

• Simboli utilizzati
  -   <nome>        Un generico nome
       • Esempio: <numero> indica che va specificato un generico valore
                          numerico


  -   [ <op> ]      Un‟operazione opzionale

  -   „ c„          Uno specifico simbolo
       • Esempio: „?‟ indica che comparirà il carattere ? esplicitamente


  -   nome           Una parola chiave
                                                                           75
Pre-processore C

• La compilazione C passa attraverso un passo preliminare
  che precede la vera e propria traduzione in linguaggio
  macchina

• Il programma che realizza questa fase è detto
 pre-processore

• Funzione principale: Espansione delle direttive che
  iniziano con il simbolo „#‟

• Direttive principali:
  - #include
  - #define


                                                            76
Direttiva #include

• Sintassi:
  - #include <file>
    <file> può essere specificato come:
       „<‟<nomefile>„>‟ per includere un file di sistema
        - Esempio:
          #include <stdio.h>
       „“‟<nomefile>„”‟ per includere un file definito dal programmatore
        - Esempio:
          #include “miofile.h”



• Significato:
    <file> viene espanso ed incluso per intero nel file sorgente




                                                                           77
Direttiva #include

• Esempio:
            file.c                      mydef.h
     #include “mydef.h”
                                       int x,y;
     ....
                                       double z;
     int main() {
     ...
     }


                      Pre-processore
                                          int x,y;
                                          double z;
                                          ....
                                          int main() {
                                          ...
                                          }

                                                         78
Dati
Dichiarazione di dati

• In C, tutti i dati devono essere dichiarati prima di essere
  utilizzati!

• La dichiarazione di un dato richiede:
  -   L‟allocazione di uno spazio in memoria atto a contenere il dato
  -   L‟assegnazione di un nome a tale spazio in memoria


• In particolare, occorre specificare:
  -   Nome (identificatore)
  -   Tipo
  -   Modalità di accesso (variabile o costante)



                                                                        80
Tipi base (primitivi)

• Sono quelli forniti direttamente dal C

• Identificati da parole chiave!
  -   char             caratteri ASCII
  -   int              interi (complemento a 2)
  -   float            reali (floating point singola precisione)
  -   double           reali (floating point doppia precisione)
  -   Nel C99: _Bool   booleano (vero o falso)


• La dimensione precisa di questi tipi dipende
  dall‟architettura (non definita dal linguaggio)
  -   |char| = 8 bit = 1 Byte sempre


                                                                   81
Modificatori dei tipi base

• Sono previsti dei modificatori, identificati da parole chiave
  da premettere ai tipi base
  - Segno:
     • signed/unsigned
        -   Applicabili ai tipi char e int
             » signed: Valore numerico con segno
             » unsigned: Valore numerico senza segno
  - Dimensione:
     • short/long
        -   Applicabili al tipo int
        -   Utilizzabili anche senza specificare int


  - Nel C99:
     • Numeri complessi / parte immaginaria:
        - _Complex
        - _Imaginary


                                                                  82
Modificatori dei tipi base (Cont.)

• Interi
  - [signed/unsigned]   short [int]
  - [signed/unsigned]   int
  - [signed/unsigned]   long [int]
  - [signed/unsigned]   long long [int] (nel C99)


• Reali
  - float
  - double
  - long double (nel C99)
  - float _Complex (nel C99)
  - double _Complex (nel C99)
  - long double _Complex (nel C99)

                                                    83
Il sistema dei tipi C


                                          Tipo di dato

                         Tipi Scalari                           Tipi Strutturati               void

Tipi interi               Tipi reali             Enumerazioni                       Vettori

              char                      float                                      Strutture


              int                       double                                      Union


                      short / long                       long                      Puntatori


                     signed/unsigned                                               Funzioni




                                                                                                      84
Variabili

• Locazioni di memoria destinate alla memorizzazione di
  dati il cui valore è modificabile
• Sintassi:

                        <tipo> <variabile> ;

    <variabile>: Identificatore che indica il nome della variabile


• Sintassi alternativa (dichiarazioni multiple):

                    <tipo> <lista di variabili>;

    <lista di variabili>: Lista di identificatori separati da „,‟

                                                                     85
Variabili (Cont.)

• Esempi:
  int x;
  char ch;
  long int x1, x2, x3;
  double pi;
  short int stipendio;
  long y, z;


• Usiamo nomi significativi!
  -   Esempi:
      •   int x0a11;      /* NO */
      •   int valore;     /* SI */
      •   float raggio;   /* SI */




                                              86
Esempi di nomi



      a         b           a1         a2

num        n         N       somma          max

   area         perimetro            perim

n_elementi          Nelementi    risultato

 trovato             nome        risposta

                                                  87
Esempi



                           i   0
int i, j ;
int N ;
int x ;                    j   2
i   =   0 ;
j   =   2 ;                N
N   =   100 ;                  100
x   =   -3124 ;
                           x -3124

                                     88
Esempi

                             a    3.1
float a, b ;
float pigr ;
float Nav, Qe ;              b    2.0
a = 3.1 ;
b = 2.0 ;                  pigr 3.1415
pigr = 3.1415926 ;
Nav = 6.022e23 ;
Qe = 1.6e-19 ;
                           Nav 6.02×1023

                            Qe 1.6×10–19
                                           89
Valore contenuto

• Ogni variabile, in ogni istante di tempo, possiede un certo
  valore
• Le variabili appena definite hanno valore ignoto
     - Variabili non inizializzate
• In momenti diversi il valore può cambiare




a        ?
                                                                t
    definizione
                                                                    90
Valore contenuto

• Ogni variabile, in ogni istante di tempo, possiede un certo
  valore
• Le variabili appena definite hanno valore ignoto
  - Variabili non inizializzate
• In momenti diversi il valore può cambiare




      ?            a      37
                                                                t
 definizione        inizializzazione
                                                                    91
Valore contenuto

• Ogni variabile, in ogni istante di tempo, possiede un certo
  valore
• Le variabili appena definite hanno valore ignoto
  - Variabili non inizializzate
• In momenti diversi il valore può cambiare




      ?                   37           a   -4
                                                                t
 definizione        inizializzazione       altra
                                       assegnazione
                                                                    92
Valore contenuto

• Ogni variabile, in ogni istante di tempo, possiede un certo
  valore
• Le variabili appena definite hanno valore ignoto
  - Variabili non inizializzate
• In momenti diversi il valore può cambiare




      ?                   37               -4         a      -3
                                                                       t
 definizione        inizializzazione       altra          incremento
                                       assegnazione
                                                                           93
Costanti
• Locazioni di memoria destinate alla memorizzazione di dati il cui
  valore non è modificabile

• Sintassi:
                  const <tipo> <costante> = <valore> ;

       <costante> : Identificatore che indica il nome della costante
       <valore> : Valore che la costante deve assumere

• Esempi:
   -   const double PIGRECO = 3.14159;
   -   const char SEPARATORE = „$‟;
   -   const float ALIQUOTA = 0.2;

• Convenzione:
   -   Identificatori delle constanti tipicamente in MAIUSCOLO

                                                                       94
Costanti (Cont.)

• Esempi di valori attribuibili ad una costante:
  -   Costanti di tipo char:
      • „f‟
  -   Costanti di tipo int, short, long
      •   26
      •   0x1a,0X1a
      •   26L
      •   26u
      •   26UL
  -   Costanti di tipo float, double
      • -212.6
      • -2.126e2, -2.126E2, -212.6f




                                                   95
Costanti speciali

• Caratteri ASCII non stampabili e/o “speciali”

• Ottenibili tramite “sequenze di escape”
               <codice ASCII ottale su tre cifre>


• Esempi:
  -   „007‟
  -   „013‟


• Caratteri “predefiniti”
  -   „b‟      backspace
  -   „f‟      form feed
  -   „n‟      line feed
  -   „t‟      tab
                                                     96
Visibilità delle variabili

• Ogni variabile è utilizzabile all‟interno di un preciso
  ambiente di visibilità (scope)

• Variabili globali
   -   Definite all‟esterno del main()


• Variabili locali
   -   Definite all‟interno del main()
   -   Più in generale, definite all‟interno di un blocco




                                                            97
Struttura a blocchi

• In C, è possibile raccogliere istruzioni in blocchi racchiudendole tra
  parentesi graffe

• Significato: Delimitazione di un ambiente di visibilità di “oggetti”
  (variabili, costanti)

• Corrispondente ad una “sequenza” di istruzioni

• Esempio:
      {
          int a=2;
          int b;          a e b sono definite
                          solo all‟interno del blocco!
          b=2*a;
      }


                                                                           98
Visibilità delle variabili: Esempio

    int n;
    double x;
    main() {
       int a,b,c;
       double y;
       {
            int d;
            double z;
       }
    }
-   n,x: Visibili in tutto il file
-   a,b,c,y: Visibili in tutto il main()
-   d,z: Visibili nel blocco delimitato dalle parentesi graffe

                                                                 99
Istruzioni elementari
Istruzioni elementari

• Corrispondono ai blocchi di azione dei diagrammi di
  flusso:

• Due categorie:

  -   Assegnazione



  -   Input/output (I/O)




                                                        101
Assegnazione
• Sintassi:
                          <variabile> = <valore>

• Non è un‟uguaglianza!
   - Significato: <valore> viene assegnato a <variabile>
   - <variabile> e <valore> devono essere di tipi “compatibili”
   - <variabile> deve essere stata dichiarata precedentemente!
   - Esempi:
       int x;
       float y;
       x = 3;
       y = -323.9498;


• Può essere inclusa nella dichiarazione di una variabile
   - Esempi:
       • int x = 3;
       • float y = -323.9498;

                                                                  102
Istruzioni di I/O

• Diverse categorie in base al tipo di informazione letta o
  scritta:
    -   I/O formattato
    -   I/O a caratteri
    -   I/O “per righe”
         •   Richiede la nozione di stringa. Come tale, sarà trattata in seguito


•   Nota:
    In C, le operazioni di I/O non sono gestite tramite vere e
    proprie istruzioni, bensì mediante opportune funzioni.
    -   Il concetto di funzione verrà introdotto successivamente; in
        questa sezione le funzioni di I/O saranno impropriamente
        chiamate istruzioni


                                                                                   103
I/O formattato

• Output
  -   Istruzione printf()


• Input
  -   Istruzione scanf()


• L‟utilizzo di queste istruzioni richiede l‟inserimento di una
  direttiva
                    #include <stdio.h>
 all‟inizio del file sorgente
  -   Significato: “includi il file stdio.h”
  -   Contiene alcune dichiarazioni

                                                                  104
Istruzione printf()

• Sintassi:
                    printf(<formato>,<arg1>,...,<argn>);
       <formato>: Sequenza di caratteri che determina il formato di stampa di
       ognuno dei vari argomenti

        • Può contenere:
           -   Caratteri (stampati come appaiono)
           -   Direttive di formato nella forma %<carattere>
                »   %d           intero
                »   %u           unsigned
                »   %s           stringa
                »   %c           carattere
                »   %x           esadecimale
                »   %o           ottale
                »   %f           float
                »   %g           double

   -   <arg1>,...,<argn>: Le quantità (espressioni) che si vogliono stampare
        • Associati alle direttive di formato nello stesso ordine!




                                                                                105
Istruzione printf(): Esempi


int x=2;
float z=0.5;
char c=„a‟;
                                  output
printf(“%d %f   %cn”,x,z,c);     2   0.5   a


                                  output
printf(“%f***%c***%dn”,z,c,x);
                                  0.5***a***2




                                                106
Istruzione scanf()

• Sintassi:
              scanf(<formato>,<arg1>,...,<argn>);

     <formato>: come per printf
     <arg1>,...,<argn>: le variabili cui si vogliono assegnare valori

     • IMPORTANTE:
       I nomi delle variabili vanno precedute dall‟operatore & che indica
       l‟indirizzo della variabile (vedremo più avanti il perchè)


• Esempio:
  int x;
  float z;
  scanf(“%d %f“, &x, &z);


                                                                            107
Significato di scanf()

• Istruzioni di input vanno viste come assegnazioni
  dinamiche:
  -   L‟assegnazione dei valori alle variabili avviene al tempo di
      esecuzione e viene deciso dall‟utente


• Assegnazioni tradizionali = Assegnazioni statiche
  -   L‟assegnazione dei valori alle variabili è scritta nel codice!




                                                                       108
I/O formattato avanzato

• Le direttive della stringa formato di printf e scanf
  sono in realtà più complesse
  -   printf:
      %[flag][min dim][.precisione][dimensione]<carattere>
      • [flag]: Più usati
             - Giustificazione della stampa a sinistra
             + Premette sempre il segno
      • [min dim]: Dimensione minima di stampa in caratteri
      • [precisione]: Numero di cifre frazionarie (per numeri reali)
      • [dimensione]: Uno tra:
             h      argomento è short
             l      argomento è long
      •   carattere: Visto in precedenza




                                                                       109
I/O formattato avanzato (Cont.)
-   scanf:
    %[*][max dim][dimensione]<carattere>
    • [*]: Non fa effettuare l‟assegnazione (ad es., per “saltare” un dato in input)
    • [max dim]: Dimensione massima in caratteri del campo
    • [dimensione]: Uno tra:
           h    argomento è short
           l    argomento è long
    •   carattere: Visto in precedenza




                                                                                       110
printf() e scanf(): Esempio
#include <stdio.h>
main()
{
    int a;
    float b;
    printf(“Dammi un numero intero (A): ”);
    if(scanf(“%d”,&a) != 1)
    {
       printf(“Errore!n”);
       return 1;
    }
    printf(“Dammi un numero reale (B): ”);
    if(scanf(“%f”,&b) != 1)
    {
       printf(“Errore!n”);
       return 1;
    }
    printf(“A= %dn”,a);
    printf(“B= %fn”,b);
}

                                              111
Espressioni

• Combinazioni di variabili, costanti ed operatori

• Il valore di un‟espressione può essere assegnato ad una variabile:
                             <variabile> = <espressione>
   -   Significato:
       <espressione> è “valutata” ed il valore ottenuto è assegnato a <variabile>
   -   <variabile> e <espressione> devono essere di tipi “compatibili”


• Esistono varie categorie di operatori, applicabili a tipi di dato diversi:
   - Operatori   aritmetici
   - Operatori   relazionali
   - Operatori   logici
   - Operatori   su bit
   - Operatori   di modifica del tipo (cast)
   - Operatori   di calcolo della dimensione di un tipo: sizeof()


                                                                                    112
Operatori aritmetici

• Quattro operatori (per numeri reali e interi):
                     +     -       *      /
• Per numeri interi, esiste l‟operatore % che ritorna il resto
  della divisione intera

• Stesse regole di precedenza dell‟aritmetica ordinaria

• Esempi:
  int   x=5;
  int   y=2;
  int   q, r;
  q =   x / y;    // (q = 2, troncamento)
  r =    x % y;   // (r = 1)

                                                                 113
Divisione tra interi: Esempio
#include <stdio.h>

main()
{
  int a, b;

    printf(“Dammi un numero intero (A): ”);
    scanf(“%d”,&a);
    printf(“n”);
    printf(“Dammi un numero intero (B): ”);
    scanf(“%d”,&b);
    printf(“n”);
    printf(“A div B = %dn”, a/b);
    printf(“A mod B = %dn”, a%b);
}
                                              114
Quesito

• Che operazione svolge il seguente frammento di
  programma?



                      a = b ;
                      b = a ;




                                                   115
Quesito

• Come fare a scambiare tra di loro i valori di due variabili?




          a       7                 b      –12




                                                                 116
Operatori di confronto in C

• Uguaglianza
  - Uguale:                a == b
  - Diverso:               a != b
• Ordine
  -   Maggiore:            a   > b
  -   Minore:              a   < b
  -   Maggiore o uguale:   a   >= b
  -   Minore o uguale:     a   <= b




                                             117
Operatori relazionali

• Operano su quantità numeriche o char e forniscono un
  risultato “booleano”:
            <     <=    > >=     ==    !=

• Il risultato è sempre di tipo int
  -   risultato = 0           FALSO
  -   risultato  0           VERO




                                                         118
Istruzione if

• Sintassi:
  if (<condizione>)
    <blocco1>                                          condizione
  [else
                                          blocco1                    blocco2
    <blocco2>]

  <condizione>: Espressione booleana
  <blocco1>: Sequenza di istruzioni
     • Se la sequenza contiene più di una istruzione, è necessario
       racchiuderle tra parentesi graffe


• Significato:
  - Se è vera <condizione>, esegui le istruzioni di <blocco1>,
    altrimenti esegui quelle di <blocco2>
                                                                               119
Notazione grafica


Ramo “vero”           Condizione

              V       F            Ramo “falso”
                  C


        A                 B
                                     Termine della
                                       alternativa
                                   (ricongiunzione)

                                                  120
Istruzione if : Esempio

• Leggere due valori A e B, calcolarne la differenza in
  valore assoluto D = |A-B| e stamparne il risultato

     main()
     {
       int A,B,D;

         scanf(“%d %d”,&A,&B);
         if (A > B)
           D = A-B;
         else
           D = B-A;
         printf(“%dn”,D);
     }


                                                          121
Settimana n.3


Obiettivi                   Contenuti
• Condizioni complesse      • Operatori logici
• Costrutti condizionali    • Costrutto if ed if-else con
  annidati                    annidamento
• Concetto di ciclo         • Costrutto switch
                            • Funzioni <math.h>
                            • Costrutto while




                                                            122
Operatori logici

• Operano su espressioni “booleane” e forniscono un risultato
  “booleano”:
                           !     &&      ||
                               NOT      AND      OR
• Equivalenti agli operatori booleani di base
     -   Stesse regole di precedenza
          • NOT > AND > OR
• Esempi:
     -   (x>0) && (x<10)               (x compreso tra 0 e 10)
     -   (x1>x2) || (x1 == 3)


•   Le espressioni “logiche” sono valutate da sinistra a destra

•   La valutazione viene interrotta non appena il risultato è
    univocamente determinato
                                                                  123
Operatori booleani in C



Operatore   Sintassi
                            Esempio
booleano      in C


  AND         &&        (x>=a)&&(x<=b)

   OR         ||       (v1>=18)||(v2>=18)

  NOT          !            !(a>b)


                                            124
Scelte annidate

• Nelle istruzioni del
  blocco “vero” o del                    V            F
                                                 C1
  blocco “else”, è possibile
  inserire altri blocchi di         A1
  scelta                       V             F
                                    C2                    B
• In tal caso la seconda
  scelta risulta annidata
  all‟interno della prima      A2        A3


                                    A4



                                                              125
Istruzione switch

• Sintassi:
   switch (<espressione>)
   {
     case <costante1>:
                                                   espressione
          <blocco1>
         break;
       case <costante2>:
             <blocco2>
             break;
                                   blocco1 blocco2           blocco default
       ...
       default:
             <blocco default>
   }
   <espressione>: Espressione a valore numerico
   <blocco1>, <blocco2>, … : Sequenza di istruzioni (no parentesi graffe!)

                                                                              126
Istruzione switch (Cont.)

• Significato:
  - In base al valore di <espressione>, esegui le istruzioni del case
    corrispondenti
  - Nel caso nessun case venga intercettato, esegui le istruzioni
    corrispondenti al caso default


• NOTE:
  - I vari case devono rappresentare condizioni mutualmente
    ESCLUSIVE!
  - I vari case vengono eseguiti in sequenza
     • Per evitare questo, si usa l‟istruzione break all‟interno di un blocco




                                                                                127
Sintassi istruzione switch
switch ( e )
{
    case v1:
        A1 ;                          e=...
    break ;         e=v1    e=v2




                                                  altrimenti
                                    e=v3
    case v2:           A1
        A2 ;                   A2
    break ;
                                     A3
    case v3:                               ...
        A3 ;
    break ;                                      An
    ...........
    default:
        An ;
}
                                                               128
Istruzione switch: Esempio

int x;
...
switch (x) {
  case 1:
     printf(“Sono nel caso 1n”);
     break;
  case 2:
     printf(“Sono nel caso 2n”);
     break;
  default:
     printf(“Né caso 1 né caso 2n”);
     break;
}


                                        129
Operatori di incremento

• Per le assegnazioni composte più comuni sono previsti
  degli operatori espliciti:
                           ++   --

• Casi particolari degli operatori composti dei precedenti

• Significato:
  -   Operatore ++   -> +=1
  -   Operatore --   -> -=1


• Esempi:
  -   x++;
  -   valore--;

                                                             130
Operatore di auto-incremento


a++ ;
                          a = a + 1 ;
++a ;



a-- ;
                          a = a - 1 ;
--a ;



                                        131
Flusso di esecuzione ciclico

Prima del              A
ciclo

Istruzioni             B
che vengono
ripetute               C

Condizione                  V
                      D?
di ripetizione
                        F
Dopo il ciclo          E

                                           132
Istruzione while

• Sintassi:
  while (<condizione>)
     <blocco>

  <condizione>: Una condizione Booleana
  <blocco>: Sequenza di istruzioni
     • Se più di una istruzione, va racchiuso tra graffe


• Realizza la struttura di tipo while                      condizione
                                                                        F
                                                                V
• Significato:
  - Ripeti <blocco> finché                                  blocco
    <condizione> è vera

                                                                            133
Notazione grafica (while)


                      A
  Ingresso
                               Condizione

                  V        F
                      C              Corpo

                      B


Ritorno                            Uscita
                      D
                                             134
Istruzione while: Esempio

• Leggere un valore N, calcolare la somma S dei primi N
  numeri interi e stamparla

  #include <stdio.h>
  main() {
     int N, i, S;
     i = 1; S = 0;          /* inizializzazioni */
    scanf (“%d”, &N);
     while (i <= N) {
         S += i;            /* operazione iterativa */
         i++;               /* aggiornamento condizione */
     }
     printf (“Somma = %dn”, S); /* output */
  }


                                                             135
Anatomia di un ciclo

• Conviene concepire il ciclo come 4 fasi
  -   Inizializzazione
  -   Condizione di ripetizione
  -   Corpo
  -   Aggiornamento




                                            136
Settimana n.4


Obiettivi                 Contenuti
• Cicli semplici          • Ciclo Do-while
• Cicli annidati          • Ciclo for
                          • Istruzioni break e continue
                            (brevemente)
                          • Concetto di ciclo annidato
                            ed esempio
                          • Problem solving su dati
                            scalari



                                                          137
Istruzione for

• Sintassi:
  for (<inizializzazioni>; <condizione>; <incremento>)
     <blocco>

  <inizializzazioni>: Le condizioni iniziali prima del ciclo
  <condizione>: Una condizione booleana
  <incremento>: Incremento della variabile diconteggio
  <blocco>: Sequenza di istruzioni
     • Se contiene più di una istruzione, va racchiuso tra graffe


• Tutti i campi possono essere vuoti!



                                                                    138
Istruzione for (Cont.)

• Significato:
  - Equivalente a:

    <inizializzazioni>
    while (<condizione>) {
      <blocco>
      <incremento>
    }


• Realizza un ciclo basato su conteggio
     • Tipicamente contiene una variabile indice che serve da iteratore:
        - Parte da un valore iniziale (inizializzazione)
        - Arriva ad un valore finale (condizione)
        - Attraverso uno specifico incremento (incremento)


                                                                           139
Istruzione for (Cont.)

• Esempio:
  - Leggere un carattere ch ed un intero N, e stampare una riga di N
    caratteri ch
     • Esempio: N=10, ch=„*‟               output = **********
  - Formulazione iterativa:
     • Ripeti N volte l‟operazione “stampa ch”
  - Soluzione:

     #include <stdio.h>
     main() {
        int N, i;
        char ch;

         scanf(“%d %c”, &N, &ch);
         for (i=0; i<N; i++)
           printf(“%c”, ch); /*senza „n‟ !!!!*/
         printf(“n”);
     }

                                                                       140
Istruzione for

         Istruzione di
        inizializzazione               I


                                   V       F
for ( I; C; A )                        C
{
  B ;            Istruzione di
}               aggiornamento          B

                                       A

Corpo            Condizione
                                               141
Esercizio

• Introdurre da tastiera 100 numeri interi, e calcolarne la
  media. Si controlli che ogni numero inserito sia compreso
  tra 0 e 30; in caso contrario, il numero deve essere
 ignorato

• Analisi:
  - Problema iterativo
  - Media=?
  - Controllo del valore inserito




                                                              142
Esercizio: Soluzione
#include <stdio.h>
main() {
   int valore, i, Totale=0, M=0;
   const int N = 100;
   for (i=0; i<N; i++)       /* per ogni valore introdotto */
   {
       scanf(“%d”, &valore);
       if (valore < 0 || valore > 30) /* controllo validità */
          printf(“Valore non valido”);
       else
       { /* caso normale */
         Totale += valore; /* accumula nuovo valore in Totale */
         M ++;     /* ho letto un dato in più */
        }
   }
   printf(“La media è: %fn”, (float)Totale/M);
}




                                                                   143
for e while

• Il ciclo for può essere considerato un caso particolare
  del ciclo while

• In generale si usa:
  - for per cicli di conteggio
     • Numero di iterazioni note a priori
     • Condizione di fine ciclo tipo “conteggio”
  - while per cicli “generali”
     • Numero di iterazioni non note a priori
     • Condizione di fine ciclo tipo “evento”




                                                            144
Cicli for con iterazioni note

int i ;                   int i ;

for ( i=0; i<N; i=i+1 )   for ( i=1; i<=N; i=i+1 )
{                         {
   .......                   .......
}                         }


int i ;                   int i ;

for ( i=N; i>0; i=i-1 )   for ( i=N-1; i>=0; i=i-1)
{                         {
   .......                   .......
}                         }

                                                 145
Cicli annidati

• Alcuni problemi presentano una struttura
  “bidimensionale”
  - L‟operazione iterativa stessa può essere espressa come un‟altra
    iterazione


• Realizzazione: Un ciclo che contiene un altro ciclo

• Struttura:
        for (...)
        {
          for (...)
          {
            ...
          }
        }

                                                                      146
Cicli while annidati


V       F               V            F
    C                           C


                            V        F
                                C2

    B
                                B2




                                         147
Cicli while annidati


                          V            F
                                  C
while( C )
{
                              V        F
   while( C2 )                    C2
   {
      B2 ;
   }                              B2
}


                                           148
Esempio

i = 0 ;
while( i<N )
{
    j = 0 ;
    while( j<N )
    {
        printf("i=%d - j=%dn", i, j);

        j = j + 1 ;
    }

    i = i + 1 ;
}

                                         149
Istruzione do

• Sintassi:
  do
    <blocco>
  while (<condizione>);

  <condizione>: Una condizione booleana
  <blocco>: Sequenza di istruzioni
       • Se più di una istruzione, va racchiuso tra graffe


• Realizza la struttura di tipo repeat
                                                              blocco


• Significato:
  - Ripeti <blocco> finché                        V          condizione

    <condizione> è vera                                            F
                                                                          150
Notazione grafica (do-while)


            A



            B

        V        F
            C



            D
                               151
Istruzione do (Cont.)

• Esempio:
  - Leggere un valore N controllando che il valore sia positivo.
    In caso contrario, ripetere la lettura

     #include <stdio.h>
     main() {
       int n;
       do
          scanf (“%d“, &n);
       while (n <= 0);
     }




                                                                   152
Istruzione do (Cont.)

• È sempre possibile trasformare un ciclo di tipo do in un
  ciclo di tipo while semplice, anticipando e/o duplicando
  una parte delle istruzioni

• Esempio:
     #include <stdio.h>
     main() {
       int n;
       scanf (“%d”, &n);
       while (n <= 0)
           scanf (“%d“, &n);
     }


                                                             153
Interruzione dei cicli

• Il linguaggio C mette a disposizione due istruzioni per
  modificare il normale flusso di esecuzione di un ciclo:
  - break:
     • Termina il ciclo
     • L‟esecuzione continua dalla prima istruzione dopo la fine del ciclo


  - continue:
     • Termina l‟iterazione corrente
     • L‟esecuzione continua con la prossima iterazione del ciclo




                                                                             154
Interruzione dei cicli (Cont.)

• Trasformano i cicli in blocchi non strutturati
  - Usare con cautela (e possibilmente non usare…)
  - Si può sempre evitare l‟uso di break/continue!


• Usabili in ogni tipo di ciclo (while, for, do)




                                                     155
break e continue

• In termini di diagrammi di flusso (esempio: ciclo while):


                      F                             F
         condizione                    condizione

              V                             V
         break                        continue

          blocco                         blocco




                                                              156
break : Esempio

• Acquisire una sequenza di numeri interi da tastiera;
  terminare l‟operazione quando si legge il valore 0.

• Versione con break
 int valore;
  while (scanf("%d", &valore))
 {
       if (valore == 0)
       {
         printf("Valore non consentiton");
         break;     /* esce dal ciclo */
       }
       /* resto delle istruzioni del ciclo */
  }


                                                         157
break : Esempio (Cont.)

• Versione senza break (strutturata)
int valore, finito = 0;
 while (scanf("%d", &valore) && !finito)
{
      if (valore == 0)
      {
         printf("Valore non consentiton");
         finito = 1;
      }
      else
      {
      /* resto delle istruzioni del ciclo */
      }
 }



                                               158
continue : Esempio

• Acquisire una sequenza di numeri interi da tastiera;
  ignorare i numeri pari al valore 0.

• Versione con continue
 int valore;
 while (scanf("%d", &valore))
 {
      if (valore == 0)
      {
        printf("Valore non consentiton");
        continue;   /* va a leggere un nuovo valore */
      }
      /* resto delle istruzioni del ciclo */
 }


                                                         159
continue : Esempio (Cont.)

• Versione senza continue (strutturata)

int valore;
 while (scanf("%d", &valore))
{
      if (valore == 0)
      {
        printf("Valore non consentiton");
      }
      else {
      /* resto delle istruzioni del ciclo */
      }
 }




                                               160
Settimana n.5


Obiettivi          Contenuti
• Vettori          • Definizione di vettori
                   • Dimensionamento statico
                     dei vettori
                   • Operazioni elementari:
                     lettura, stampa, copia,
                     confronto di vettori




                                               161
Variabili e vettori

dato1
            dato2
 35                                       35
                7                           7   dato
  dato3
                 dato4
                                           14
      14                                  32
dato5               32                     -9
 -9        dato6                           2
dato7        2            dato8           631
                                          -18
631        dato9         -18               4
            4            dato10            7
                          7
                                                  162
Da evitare...
int main(void)
{
   int dato1, dato2, dato3, dato4, dato5 ;
   int dato6, dato7, dato8, dato9, dato10 ;
   . . . . .
   scanf("%d", &dato1) ;
   scanf("%d", &dato2) ;
   scanf("%d", &dato3) ;
   . . .
   scanf("%d", &dato10) ;

    printf("%dn",   dato10) ;
    printf("%dn",   dato9) ;
    printf("%dn",   dato8) ;
    . . .
    printf("%dn",   dato1) ;
}
                                              163
...così è meglio!



int main(void)
{
   int dato[10] ;
   . . . . .
   for( i=0; i<10; i++)
      scanf("%d", &dato[i]) ;

    for( i=9; i>=0; i--)
       printf("%dn", dato[i]) ;
}




                                   164
Vettori

• Insiemi di variabili dello stesso tipo aggregate in un‟unica entità
  - Identificate globalmente da un nome
  - Singole variabili (elementi) individuate da un indice, corrispondente
    alla loro posizione rispetto al primo elemento
  - L‟indice degli elementi parte da 0
  - Gli elementi di un vettore sono memorizzati in celle di memoria
    contigue!

     a      a                 a      a0     a1     a2    a3     a4




                                                                            165
Dichiarazione di un vettore

• Sintassi:
  <tipo>      <nome vettore> [<dimensione>];


• Accesso ad un elemento:
  <nome vettore> [<posizione>]


• Esempio:
  int      v[10];

  - Definisce un insieme di 10 variabili intere
    v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9]




                                                        166
Definizione di vettori in C


               int dato[10] ;


Tipo di dato       Nome del     Numero di
   base             vettore      elementi




                                            167
Inizializzazione di un vettore

• E‟ possibile assegnare un valore iniziale ad un vettore (solo) al
  momento della sua dichiarazione

• Equivalente ad assegnare OGNI elemento del vettore

• Sintassi (vettore di N elementi):
              {<valore 0>, <valore 1>, ... ,<valore N-1>};
• Esempio:
   int lista[4] = {2, 0, -1, 5};


• NOTA: Se vengono specificati meno di N elementi, l‟inizializzazione
  assegna a partire dal primo valore. I successivi vengono posti a zero.
   - Esempio:
     int s[4] = {2, 0, -1};
     /* s[0]=2, s[1]=0, s[2]=-1, s[3]=0 */

                                                                           168
Vettori e indici

• L‟indice che definisce la posizione di un elemento di un
  vettore DEVE essere intero!
  -   Non necessariamente costante!
      • Può essere un‟espressione complessa (purché intera)


• Esempi:
  double a[100]; /* a vettore di double */
  double x;
  int i, j, k;
  … … …
  x = a[2*i+j-k]; /* è corretto! */




                                                              169
Uso di una cella di un vettore

• L‟elemento di un vettore è utilizzabile come una qualsiasi
  variabile:
  - utilizzabile all‟interno di un‟espressione
     • tot = tot + dato[i] ;
  - utilizzabile in istruzioni di assegnazione
     • dato[0] = 0 ;
  - utilizzabile per stampare il valore
     • printf("%dn", dato[k]) ;
  - utilizzabile per leggere un valore
     • scanf("%dn", &dato[k]) ;




                                                               170
Vettori e cicli

• I cicli sono particolarmente utili per “scandire” un vettore

• Utilizzo tipico: Applicazione iterativa di un‟operazione sugli
  elementi di un vettore

• Schema:
  …
  int data[10];
  for (i=0; i<10; i++)
  {
    // operazione su data[i]
  }
  …
                                                                   171
Direttiva #define

• Sintassi:
                     #define <costante> <valore>

    <costante>: Identificatore della costante simbolica
     • Convenzionalmente indicato tutto in maiuscolo
    <valore>: Un valore da assegnare alla costante


• Utilizzo:
  - Definizione di costanti simboliche
  - Maggiore leggibilità
  - Maggiore flessibiltà
     • Il cambiamento del valore della costante si applica a tutto il file!



                                                                              172
Direttiva #define

• Esempio:
  - #define PI    3.1415
  - #define N     80
  - ...
  - double z = PI * x;
  - int vect[N];




                                   173
Costrutto #define



#define N 10               Definizione
                              della
                            costante
int main(void)
{                          Uso della
   int dato[N] ;           costante
   . . .
}




                                       174
Modificatore const



int main(void)               Definizione
{                               della
   const int N = 10 ;         costante

    int dato[N] ;            Uso della
                             costante
    . . .
}



                                         175
Sintassi

•   Stessa sintassi per dichiarare una variabile
•   Parola chiave const
•   Valore della costante specificato dal segno =
•   Definizione terminata da segno ;
•   Necessario specificare il tipo (es. int)
•   Il valore di N non si può più cambiare



             const int N = 10 ;



                                                    176
Stampa vettore di interi




printf("Vettore di %d interin", N) ;

for( i=0; i<N; i++ )
{
    printf("Elemento %d: ", i+1) ;
    printf("%dn", v[i]) ;
}




                                        177
Lettura vettore di interi




printf("Lettura di %d interin", N) ;

for( i=0; i<N; i++ )
{
    printf("Elemento %d: ", i+1) ;
    scanf("%d", &v[i]) ;
}




                                        178
Copia di un vettore


35    12                   35    35
 7     2                     7    7
14    73                    14   14
32    -12                  32    32
 -9    0                    -9    -9
 2     0    Copia v in w     2     2
631   -17                  631   631
-18   44                   -18   -18
 4     1                     4     4
 7    17                     7     7
 v     w                    v     w
                                       179
Copia di un vettore




/* copia il contenuto di v[] in w[] */

for( i=0; i<N; i++ )
{
    w[i] = v[i] ;
}




                                         180
Esercizio 1

• Leggere 10 valori interi da tastiera, memorizzarli in un
  vettore e calcolarne il minimo ed il massimo

• Analisi:
  - Il calcolo del minimo e del massimo richiedono la scansione
    dell‟intero vettore
  - Il generico elemento viene confrontato con il minimo corrente ed
    il massimo corrente
     • Se minore del minimo, aggiorno il minimo
     • Se maggiore del massimo, aggiorno il massimo
  - Importante l‟inizializzazione del minimo/massimo corrente!




                                                                       181
Esercizio 1: Soluzione
#include <stdio.h>
main()
{
    int v[10];
    int i, max, min;

    for (i=0; i<10; i++)
         scanf(“%d”, &v[i]);

    /* uso il primo elemento per inizializzare min e max*/
    max = v[0];
    min = v[0];

    for (i=1; i<10; i++) {
        if (v[i] > max)
            max = v[i];
        if (v[i] < min)
            min = v[i];
    }
    printf("Il massimo e': %3dn", max);
    printf("Il minimo e' : %3dn", min);
}

                                                             182
Esercizio 2

• Scrivere un programma che legga un valore decimale
  minore di 1000 e lo converta nella corrispondente
  codifica binaria

• Analisi:
  - Usiamo l‟algoritmo di conversione binaria visto a lezione
     • Divisioni sucessive per 2
     • Si memorizzano i resti nella posizione del vettore di peso
       corrispondente
        - La cifra meno significativa è l‟ultima posizione del vettore!
  - Essenziale determinare la dimensione massima del vettore
     • Per codificare un numero < 1000 servono 10 bit (210=1024)




                                                                          183
Esercizio 2: Soluzione
#include <stdio.h>
main()
{
    int v[10] = {0};
    int i=9;    /* ultima posizione del vettore */
    unsigned N; /* unsigned perchè positivo */

    printf("Inserire un numero positivo (<1000): ");
    scanf("%d", &N);

    if (N > 1000)
         printf("Errore: il numero deve essere < 1000n");
    else {
       while(N != 0) {
            v[i] = (N % 2);    /* resto della divisione per 2! */
            N = N/2;   /* divido N per 2 */
            i--;
       }

    for (i=0; i<10; i++)
        printf("%d", v[i]);
    printf("n");
    }
}

                                                                    184
Settimana n.6


Obiettivi                      Contenuti
• Ricerche in Vettori          • Ricerca di esistenza
• Flag                         • Ricerca di universalità
• Funzioni                     • Ricerca di duplicati
                               • Problem solving su dati
                                 vettoriali
                               • Definizione di Funzioni
                               • Passaggio di parametri e
                                 valore di ritorno



                                                            185
Ricerca di un elemento

• Dato un valore numerico, verificare
  - se almeno uno degli elementi del vettore è uguale al valore
    numerico
  - in caso affermativo, dire dove si trova
  - in caso negativo, dire che non esiste
• Si tratta di una classica istanza del problema di “ricerca di
  esistenza”




                                                                  186
Ricerca di un elemento: Esempio (1/3)




int dato ; /* dato da ricercare */
int trovato ; /* flag per ricerca */
int pos ;     /* posizione elemento */

...

printf("Elemento da ricercare? ");
scanf("%d", &dato) ;




                                         187
Ricerca di un elemento: Esempio (2/3)


trovato = 0 ;
pos = -1 ;

for( i=0 ; i<N ; i++ )
{
    if( v[i] == dato )
    {
        trovato = 1 ;
        pos = i ;
    }
}



                                        188
Ricerca di un elemento: Esempio (3/3)



if( trovato==1 )
{
     printf("Elemento trovato "
        "alla posizione %dn", pos+1) ;
}
else
{
     printf("Elemento non trovaton");
}




                                          189
Varianti

• Altri tipi di ricerche
   - Contare quante volte è presente l‟elemento cercato
   - Cercare se esiste almeno un elemento maggiore (o minore) del
     valore specificato
   - Cercare se esiste un elemento approssimativamente uguale a
     quello specificato
   - ...




                                                                    190
Ricerca del massimo

• Dato un vettore (di interi o reali), determinare
  - quale sia l‟elemento di valore massimo
  - quale sia la posizione in cui si trova tale elemento
• Conviene applicare la stessa tecnica per l‟identificazione
  del massimo già vista in precedenza
  - Conviene inizializzare il max al valore del primo elemento




                                                                 191
Ricerca del massimo: Esempio (1/2)

float max ; /* valore del massimo */
int posmax ; /* posizione del max */

...
max = r[0] ;
posmax = 0 ;

for( i=1 ; i<N ; i++ )
{
    if( r[i]>max )
    {
        max = r[i] ;
        posmax = i ;
    }
}
                                       192
Ricerca del massimo: Esempio (2/2)




printf("Il max vale %f e si ", max) ;
printf("trova in posiz. %dn", posmax) ;




                                           193
Ricerca di esistenza o universalità

• L‟utilizzo dei flag è può essere utile quando si desiderino
  verificare delle proprietà su un certo insieme di dati
  -   È   vero   che   tutti i dati verificano la proprietà?
  -   È   vero   che   almeno un dato verifica la proprietà?
  -   È   vero   che   nessun dato verifica la proprietà?
  -   È   vero   che   almeno un dato non verifica la proprietà?




                                                                   194
Esempi

• Verificare che tutti i dati inseriti dall‟utente siano positivi
• Determinare se una sequenza di dati inseriti dall‟utente è
  crescente
• Due numeri non sono primi tra loro se hanno almeno un
  divisore comune
  - esiste almeno un numero che sia divisore dei due numeri dati
• Un poligono regolare ha tutti i lati di lunghezza uguale
  - ogni coppia di lati consecutivi ha uguale lunghezza




                                                                    195
Formalizzazione

• È vero che tutti i dati verificano la proprietà?
  - x : P(x)
• È vero che almeno un dato verifica la proprietà?
  - x : P(x)
• È vero che nessun dato verifica la proprietà?
  - x : not P(x)
• È vero che almeno un dato non verifica la proprietà?
  - x : not P(x)




                                                         196
Realizzazione (1/2)

• Esistenza: x : P(x)        • Universalità: x : P(x)
  - Inizializzo flag F = 0      - Inizializzo flag F = 1

  - Ciclo su tutte le x         - Ciclo su tutte le x
    • Se P(x) è vera              • Se P(x) è falsa
       - Pongo F = 1                 - Pongo F = 0


  - Se F = 1, l‟esistenza è     - Se F = 1, l‟universalità è
    dimostrata                    dimostrata
  - Se F = 0, l‟esistenza è     - Se F = 0, l‟universalità è
    negata                        negata


                                                               197
Realizzazione (2/2)

• Esistenza: x : not P(x)    • Universalità: x : not P(x)
  - Inizializzo flag F = 0      - Inizializzo flag F = 1

  - Ciclo su tutte le x         - Ciclo su tutte le x
    • Se P(x) è falsa             • Se P(x) è vera
       - Pongo F = 1                 - Pongo F = 0


  - Se F = 1, l‟esistenza è     - Se F = 1, l‟universalità è
    dimostrata                    dimostrata
  - Se F = 0, l‟esistenza è     - Se F = 0, l‟universalità è
    negata                        negata


                                                               198
Esempio 1

• Verificare che tutti i dati inseriti dall‟utente siano positivi

           int positivi ;
           ...
           positivi = 1 ;
           i = 0 ;
           while( i<n )
           {
               ...
               if( dato <= 0 )
                   positivi = 0 ;
               ....
               i = i + 1 ;
           }
           if( positivi == 1 )
               printf("Tutti positivin");


                                                                    199
Esempio 2

• Determinare se una sequenza di dati inseriti dall‟utente è
  crescente
            int crescente ;
            ...
            crescente = 1 ;
            precedente = INT_MIN ;
            i = 0 ;
            while( i<n )
            {
                ...
                if( dato < precedente )
                    crescente = 0 ;
                precedente = dato ;
                ....
                i = i + 1 ;
            }

                                                               200
Esempio 3

• Due numeri non sono primi tra loro se hanno almeno un
  divisore comune

            int A, B ;
            int noprimi ;
            ...
            noprimi = 0 ;
            i = 2 ;
            while( i<=A )
            {
                ...
                if( (A%i==0) && (B%i==0) )
                    noprimi = 1 ;
                ....
                i = i + 1 ;
            }

                                                          201
Esempio 4

• Un poligono regolare ha tutti i lati di lunghezza uguale

             int rego ;
             ...
             rego = 1 ;
             precedente = INT_MIN ;
             i = 0 ;
             while( i<n )
             {
                 ...
                 if( lato != precedente )
                     rego = 0 ;
                 precedente = lato ;
                 ....
                 i = i + 1 ;
             }


                                                             202
Occupazione variabile

• La principale limitazione dei vettori è la loro dimensione
  fissa, definita come costante al tempo di compilazione del
  programma
• Molto spesso non si conosce l‟effettivo numero di
  elementi necessari fino a quando il programma non andrà
  in esecuzione
• Occorre identificare delle tecniche che ci permettano di
  lavorare con vettori di dimensione fissa, ma occupazione
  variabile




                                                               203
Tecnica adottata



0                     N-1     N                          MAXN-1        MAXN
3 1 7 12 -3 1 21 43 -8 0 12 3 2 11 3 4 8 76 56 23 4 5 90 15 72 -4 -2 22 73




        Elementi                              Elementi
     effettivamente                          inutilizzati
        utilizzati




                                                                             204
Esempio


/* dimensione massima */
const int MAXN = 100 ;

int v[MAXN] ; /* vettore di dim. max. */

int N ; /* occupazione effettiva
           del vettore */

...

N = 0 ; /* inizialmente “vuoto” */



                                           205
Crescita del vettore

• Un vettore ad occupazione variabile può facilmente
  crescere, aggiungendo elementi “in coda”



          v[N] = nuovo_elemento ;
          N++ ;




                                                       206
Sottoprogrammi

• Un programma realistico può consistere di migliaia di
  istruzioni

• Sebbene fattibile, una soluzione “monolitica” del
  problema:
  -   Non è molto produttiva:
       • Riuso del codice?
       • Comprensione del codice?
  -   Non è intuitiva:
       • Tendenza ad “organizzare” in modo strutturato
       • Struttura gerarchica a partire dal problema complesso fino a
         sottoproblemi sempre più semplici


• Approccio top-down

                                                                        207
Approccio top-down

• Decomposizione del problema in sottoproblemi più
  semplici

• Ripetibile su più livelli

• Sottoproblemi “terminali” = Risolvibili in modo “semplice”




                                                               208
Approccio top-down (Cont.)

• Esempio: Pulizia di una casa



                                       Pulizia
                                        casa


          Pulizia                      Pulizia                      Pulizia
          bagno                        cucina                       camera

 Togli                        Togli                        Togli
          Lava      Lucida             Lava      Lucida              Lava     Lucida
polvere                      polvere                      polvere




                                                                                       209
Approccio top-down (Cont.)

• I linguaggi di programmazione permettono di suddividere
  le operazioni in modo simile tramite sottoprogrammi
  -   Detti anche funzioni o procedure


• La gerarchia delle operazioni si traduce in una gerarchia
  di sottoprogrammi

• main() è una funzione!




                                                              210
Funzioni e procedure

• Procedure:
  -   Sottoprogrammi che NON ritornano un risultato


• Funzioni:
  -   Sottoprogrammi che ritornano un risultato (di qualche tipo
      primitivo o non)


• In generale, procedure e funzioni hanno dei parametri
  (o argomenti)
  -   Vista funzionale:


        parametri                  f                risultato

                                                                   211
Funzioni e procedure in C

• Nel C K&R:
  - Esistono solo funzioni (tutto ritorna un valore)
  - Si può ignorare il valore ritornato dalle funzioni


• Dal C89 (ANSI) in poi:
  -   Funzioni il cui valore di ritorno deve essere ignorato (void)
  -   Funzioni void  procedure




                                                                      212
Definizione di una funzione

• Stabilisce un “nome” per un insieme di operazioni

• Sintassi:
       <tipo risultato> <nome funzione> (<parametri formali >)
       {
         <istruzioni>
       }
  -   Se la funzione non ha un risultato, <tipo risultato> deve essere
      void
  -   Per ritornare il controllo alla funzione chiamante, nelle
      <istruzioni> deve comparire una istruzione
       • return <valore>;         se non void
       • return;                  se void



                                                                         213
Definizione di una funzione (Cont.)

• Tutte le funzioni sono definite allo stesso livello del
  main()
  -   NON si può definire una funzione dentro un‟altra


• main() è una funzione!
  -   Tipo del valore di ritorno: int
  -   Parametri: Vedremo più avanti!




                                                            214
Prototipi

• Così come per le variabili, è buona pratica dichiarare
  all‟inizio del programma le funzioni prima del loro uso
  (prototipi)

• Sintassi:
  -   Come per la definizione, ma si omette il contenuto (istruzioni)
      della funzione




                                                                        215
Prototipi: Esempio
#include <stdio.h>

int func1(int a);
int func2(float b);
...

main ()
{
…
}

int func1(int a)
{
…
}

int func2(float b)
{
…
}

                                        216
Funzioni e parametri

• Parametri e risultato sono sempre associati ad un tipo

• Esempio:
  float media(int a, int b)

       int a
                       media()               float
       int b
• I tipi di parametri e risultato devono essere rispettati
  quando la funzione viene utilizzata!

• Esempio:
  float x; int a,b;
  x = media(a, b);
                                                             217
Utilizzo di una funzione

• Deve rispettare l‟interfaccia della definizione

• Utilizzata come una normale istruzione
       <variabile> = <nome funzione> (<parametri attuali>);


• Può essere usata ovunque
  -   Una funzione può anche invocare se stessa (funzione ricorsiva)




                                                                       218
Utilizzo di una funzione: Esempio
#include <stdio.h>

int modabs(int v1, int v2);   //prototipo

main() {
  int x,y,d;
  scanf(“%d %d”,&x,&y);
  d = modabs(x,y);            // utilizzo
  printf(“%dn”,d);
}

int modabs (int v1, int v2)   // definizione
{
  int v;
  if (v1>=v2) {
        v = v1-v2;
  } else {
        v = v2-v1;
  }
  return v;
}

                                               219
Parametri formali e attuali

• E‟ importante distinguere tra:
  -   Parametri formali:
      Specificati nella definizione di una funzione
  -   Parametri attuali:
      Specificati durante il suo utilizzo


• Esempio:
  -   funzione Func
       • Definizione: double Func(int x,double y)
          - Parametri formali: (x,y)

       • Utilizzo: double z = Func(a*2, 1.34);
          -   Parametri attuali: (Risultato di a*2, 1.34)




                                                            220
Parametri formali e attuali (Cont.)

• Vista funzionale:
  -   Definizione:

                     int   x
                               Func    double
                  double   y

  -   Utilizzo:


                  a*2 => x
                               Func    double
                  1.34 => y


                                                 221
Passaggio dei parametri

• In C, il passaggio dei parametri avviene per valore
  -   Significato: Il valore dei parametri attuali viene copiato in variabili
      locali della funzione


• Implicazione:
  -   I parametri attuali non vengono MAI modificati dalle istruzioni
      della funzione




                                                                                222
Passaggio dei parametri: Esempio
#include <stdio.h>

void swap(int a, int b);

main() {
  int x,y;
  scanf(“%d %d”,&x,&y);
  printf(“%d %dn”,x,y);
  swap(x,y);
  /* x e y NON VENGONO MODIFICATI */

    printf(“%d %dn”,x,y);
}

void swap(int a, int b)
{
  int tmp;
  tmp = a;
  a = b;
  b = tmp;
  return;
}
                                             223
Passaggio dei parametri (Cont.)

• E‟ possibile modificare lo schema di passaggio per valore
  in modo che i parametri attuali vengano modificati dalle
  istruzioni della funzione

• Passaggio per indirizzo (by reference)
  -   Parametri attuali = indirizzi di variabili
  -   Parametri formali = puntatori al tipo corrispondente dei
      parametri attuali
  -   Concetto:
       • Passando gli indirizzi dei parametri formali posso modificarne
         il valore
  - La teoria dei puntatori verrà ripresa in dettaglio più avanti
       • Per il momento è sufficiente sapere che:
          - „&‟<variabile> fornisce l‟indirizzo di memoria di <variabile>
          - „*‟<puntatore> fornisce il dato contenuto nella variabile puntata da <puntatore>

                                                                                               224
Passaggio dei parametri: Esempio
#include <stdio.h>

void swap(int *a, int *b);

main() {
  int x,y;
  scanf(“%d %d”,&x,&y);
  printf(“%d %dn”,x,y);
  swap(&x,&y);                      Passo l‟indirizzo
  /* x e y SONO ORA MODIFICATI */   di x e y
  printf(“%d %dn”,x,y);
}

void swap(int *a, int *b)
{
  int tmp;
  tmp = *a;
  *a = *b;                   Uso *a e *b
  *b = tmp;                  come “interi”
  return;
}

                                                        225
Passaggio dei parametri (Cont.)

• Il passaggio dei parametri per indirizzo è indispensabile
  quando la funzione deve ritornare più di un risultato




       Parametri            F              Risultati




                                                              226
Vettori e funzioni

• Le funzioni possono avere come parametri dei vettori o
  matrici:
  - Parametri formali
     • Si indica il nome del vettore, con “[ ]” senza dimensione
  - Parametri attuali
     • Il nome del vettore SENZA “[ ]”


• Il nome del vettore indica l‟indirizzo del primo elemento,
  quindi il vettore è passato per indirizzo!




                                                                   227
Vettori e funzioni (Cont.)

• Conseguenza:
  - Gli elementi di un vettore passato come argomento vengono
    SEMPRE modificati!


• ATTENZIONE: Dato che il vettore è passato per
  indirizzo, la funzione che riceve il vettore come
  argomento non ne conosce la lunghezza!!!!

• Occorre quindi passare alla funzione anche la dimensione
  del vettore!




                                                                228
Esercizio

• Scrivere una funzione nonnull() che ritorni il numero di
  elementi non nulli di un vettore di interi passato come
  parametro

• Soluzione:
  int nonnull(int v[], int dim)
  {
                                       All‟interno della funzione
    int i, n=0;
                                       bisogna sapere la dimensione
    for (i=0; i<dim; i++) {
                                       del vettore
       if (v[i] != 0)
              n++;
    }                        Se v[ ] fosse modificato dentro la
                             funzione, il valore sarebbe
    return n;
                             modificato anche nella funzione
  }
                               chiamante
                                                                  229
Funzioni matematiche

• Utilizzabili includendo in testa al programma

                  #include <math.h>

• NOTA: Le funzioni trigonometriche (sia dirette sia
  inverse) operano su angoli espressi in radianti




                                                       230
math.h
funzione                            definizione
double sin (double x)                  sin (x)
double cos (double x)                  cos (x)
double tan (double x)                  tan (x)
double asin (double x)                asin (x)
double acos (double x)                acos (x)
double atan (double x)                atan (x)
double atan2 (double y, double x)   atan ( y / x )
double sinh (double x)                sinh (x)
double cosh (double x)                cosh (x)
double tanh (double x)                tanh (x)
                                                     231
math.h (Cont.)



funzione                          definizione
double pow (double x, double y)   xY
double sqrt (double x)            radice quadrata
double log (double x)             logaritmo naturale
double log10 (double x)           logaritmo decimale

double exp (double x)             eX




                                                       232
math.h (Cont.)

funzione                             definizione
double ceil (double x)                   ceil (x)

double floor (double x)                 floor (x)

double fabs (double x)              valore assoluto

double fmod (double x, double y)        modulo
                                   restituisce la parte
double modf (double x, double       frazionaria di x e
*ipart)                            memorizza la parte
                                   intera di x in ipart




                                                          233
Funzioni matematiche: Esempio
#include <stdio.h>
#include <math.h>

double log2(double x);

main()
{
   int nogg, nbit;

    printf(“Dammi il numero di oggetti: ”);
    scanf(“%d”, &nogg);
    nbit=ceil(log2((double)nogg));
    printf(“Per rappresentare %d oggetti servono %d
             bitn”, nogg, nbit);
}

double log2(double x)
{
   return log(x)/log((double)2);
}


                                                      234
Settimana n.7


Obiettivi                       Contenuti
• Caratteri                     • Il tipo char
• Vettori di caratteri          • Input/output di caratteri
• Stringhe                      • Operazioni su variabili char
                                • Funzioni <ctype.h>
                                • Stringhe come vettori di char
                                • Il terminatore nullo
                                • Stringhe come tipo gestito
                                  dalla libreria
                                • Funzioni di I/O sulle stringhe


                                                                   235
Codice ASCII




Source: www.lookuptables.com

                                              236
Dualità caratteri - numeri

• Ogni carattere è rappresentato dal suo codice ASCII

               y             7               W              !           %
               121           55              87             33          37

• Ogni stringa è rappresentata dai codici ASCII dei caratteri
  di cui è composta

     F u l v i o                                        0 6 A Z N
     70   117 108 118 105         111                  48    54   65   90    78


     0 1 1 - 5 6 4 6 3 3 2
     48   49     49    45   53    54    52   54   51   51   50



                                                                                  237
I/O a caratteri

• Acquisizione/stampa di un carattere alla volta

• Istruzioni:
  - int getchar()
     • Legge un carattere da tastiera
     • Il carattere viene fornito come “risultato” di getchar (valore intero)
     • In caso di errore il risultato è la costante EOF (dichiarata in stdio.h)


  - int putchar(<carattere>)
     • Stampa <carattere> su schermo
     • <carattere>: Un dato di tipo char




                                                                                  238
EOF

• EOF = End-of-File

• Rappresenta in realtà un valore fittizio corrispondente
  alla fine dell‟input

• Indica che non ci sono più dati in input

• EOF può essere prodotto in diversi modi:
  - Automaticamente, se si sta leggendo un file
  - Premendo CTRL+‟Z‟ in MS-DOS o VMS
  - Premendo CTRL+‟D‟ in Unix



                                                            239
I/O a caratteri: Esempio
#include <stdio.h>

main()
{
     int tasto;

    printf(“Premi un tasto...n”);
    tasto = getchar();
    if (tasto != EOF)   /* errore ? */
    {
      printf(“Hai premuto %cn”, tasto);
      printf(“Codice ASCII = %dn”, tasto);
    }
}
                                              240
scanf/printf e getchar/putchar

• scanf e printf sono “costruite” a partire da
  getchar/putchar

• scanf/printf sono utili quando è noto il formato (tipo)
  del dato che viene letto
  - Esempio: Serie di dati con formato fisso


• getchar/putchar sono utili quando non è noto tale
  formato
  - Esempio: Un testo




                                                            241
Funzioni di utilità

 • Classificazione caratteri (<ctype.h>)
funzione                                         definizione
int   isalnum (char c)                       Se c è lettera o cifra
int   isalpha (char c)                           Se c è lettera
int   isascii(char c)                        Se c è lettera o cifra
int   isdigit (char c)                         Se c è una cifra
int   islower(char c)                          Se c è minuscola
int   isupper (char c)                         Se c è maiuscola
int isspace(char c)                          Se c è spazio,tab,n
int iscntrl(char c)                           Se c è di controllo
                                            Se c è stampabile, non
int isgraph(char c)
                                                     spazio
int isprint(char c)                           Se c è stampabile
int ispunct(char c)                          Se c è di interpunzione
int toupper(char c)                          Converte in maiuscolo
int tolower(char c)                          Converte in minuscolo
                                                                       242
Vista d‟insieme



      A...F           G...Z
                         isupper             !"#$%&'()
                                             *+,-./:
      a...f           g...z                  ;<=>?@[]
                         islower
                           isalpha
                                             ^_`{|}~
                                                  ispunct

      0...9
        isdigit
         isxdigit
                                isalnum              isgraph

                          Spazio                       isprint


Caratteri di          Tab
 controllo          Newline        isspace
                      iscntrl
                                                                 243
Stringhe in C

• Nel linguaggio C non è supportato esplicitamente alcun
  tipo di dato “stringa”
• Le informazioni di tipo stringa vengono memorizzate ed
  elaborate ricorrendo a semplici vettori di caratteri



              char saluto[10] ;


           B u o n g i o r n o


                                                           244
Stringhe (Cont.)

• Definizione:
  Sequenze di caratteri terminate dal carattere „0‟ (NULL)

• Tecnicamente:
  Vettori di caratteri terminati da un carattere aggiuntivo „0‟ (NULL)

• Memorizzate come i vettori

• La lunghezza della stringa può essere definita implicitamente
  mediante l‟assegnazione di una costante stringa, rappresentata da
  una sequenza di caratteri racchiusa tra doppi apici

• Esempio:
                                     „c‟ „i‟ „a‟ „o‟ „!‟ „0‟
  char s[] = “ciao!”;
                                    s[0] s[1] s[2] s[3] s[4] s[5]
                                                                          245
Stringhe (Cont.)
• NOTA: La stringa vuota non è un vettore “vuoto”!
   - Esempio: char s[] = “”;
                                            „0‟
                                            s[0]
• Attenzione: „a‟ è diverso da “a”

• Infatti „a‟ indica il carattere a, mentre “a” rappresenta la stringa a
  (quindi con „0‟ finale).

• Graficamente:

   - “Ciao” ---->    „C‟ „i‟ „a‟ „o‟ „0‟

   - “a”     ---->   „a‟ „0‟

   - „a‟    ---->    „a‟
                                                                           246
Formattazione di stringhe

• Le operazioni di I/O formattato possono essere
  effettuate anche da/su stringhe

• Funzioni
   int sscanf(char* <stringa>,char* <formato>,<espressioni>);
   -   Restituisce EOF in caso di errore, altrimenti il numero di campi
       letti con successo
   int sprintf(char* <stringa>,char* <formato>,<variabili>));
   -   Restituisce il numero di caratteri scritti


• Utili in casi molto particolari per costruire/analizzare
  stringhe con un formato fisso


                                                                          247
I/O di stringhe

• Diamo per scontato di utilizzare la convenzione del
  terminatore nullo
• Si possono utilizzare
  - Funzioni di lettura e scrittura carattere per carattere
     • Come nell‟esercizio precedente
  - Funzioni di lettura e scrittura di stringhe intere
     • scanf e printf
     • gets e puts




                                                              248
Esempio




const int MAX = 20 ;
char nome[MAX+1] ;

printf("Come ti chiami? ") ;

scanf("%s", nome) ;




                               249
Esempio




const int MAX = 20 ;
char nome[MAX+1] ;

printf("Come ti chiami? ") ;

gets(nome) ;




                               250
Esempio




printf("Buongiorno, ") ;
printf("%s", nome) ;
printf("!n") ;



printf("Buongiorno, %s!n", nome) ;




                                      251
Esempio




printf("Buongiorno, ") ;
puts(nome) ;

/* No!! printf("!n") ; */




                             252
Settimana n.8


Obiettivi                      Contenuti
• Stringhe                     • Approfondimento printf
• Matrici                      • Conversioni stringa-intero,
                                 stringa-reale e v/v
• Vettori di Stringhe
                               • Funzioni <string.h>
                               • Matrice come estensione
                                 dei vettori (veloce)
                               • Dualità matrici di caratteri
                                 = vettori di stringhe
                               • Problem solving su dati
                                 testuali


                                                                253
Manipolazione di stringhe

• Data la loro natura di tipo “aggregato”, le stringhe non
  possono essere usate come variabili qualunque

• Esempi di operazioni non lecite:
  char   s1[20], s2[10], s3[50];
  ...
  s1 =   “abcdefg”;
  s2 =
  s3 =
         “hijklmno”;
         s1 + s2;
                           NO!

• A questo scopo esistono apposite funzioni per la
  manipolazione delle stringhe


                                                             254
Funzioni di libreria per stringhe

 • Utilizzabili includendo in testa al programma
                     #include <string.h>
funzione                                              definizione
                                                      definizione
char* strcat (char* s1, char* s2);                   concatenazione
                                                   concatenazione s1+s2
                                                          s1+s2
char* strchr (char* s, int c);                      ricerca di c in s
int   strcmp (char* s1, char* s2);                     confronto
                                                       confronto
char* strcpy (char* s1, char* s2);                     s1 <= s2
                                                        s1 <= s2
int   strlen (char* s);                              lunghezza di s
                                                      lunghezza di s
char* strncat (char* s1,char* s2,int n);           concat. n car. max
                                                    concat. n car. max
char* strncpy (char* s1,char* s2,int n);             copia n car. max
                                                     copia n car. max
char* strncmp(char* dest,char* src,int n);            cfr. n car. max
                                                      cfr. n car. max

                                                                        255
Funzioni di libreria per stringhe (Cont.)

• NOTE:
  - Non è possibile usare vettori come valori di ritorno delle funzioni
    di libreria
     • Esempio:
        char s[20]
        ...
        s = strcat(stringa1, stringa2);                /* NO! */
  - Alcune funzioni possono essere usate “senza risultato”
     • Esempio:
        strcpy(<stringa destinazione>, <stringa origine>)
        strcat(<stringa destinazione>, <stringa origine>)

        - Il valore di ritorno coincide con la stringa destinazione




                                                                          256
Esercizio 1

• Realizzare un meccanismo di “cifratura” di un testo che
  consiste nell‟invertire le righe del testo stesso

• Esempio:



C’era una volta                   atlov anu are’C
un re che ...                     ehc er nu




                                                            257
Esercizio 1: Soluzione
#include <stdio.h>
main()
{
  int i,j, len;
  char s[80], dest[80];    /* una riga */

    while (gets(s) != NULL) {
        len = strlen(s); j = 0;
        for (i=len-1;i>=0;i--) {
              dest[j] = s[i];
              j++;
        }
        dest[j]='0';
        puts(dest);
    }
}

                                            258
Esercizio 2

• Si scriva un programma che legga da tastiera due
  stringhe e cancelli dalla prima stringa i caratteri contenuti
  nella seconda stringa

• Esempio:
  - str1: “Olimpico”
  - str2: “Oio”
  - risultato: “lmpc”




                                                                  259
Esercizio 2: Soluzione
#include <stdio.h>
#define MAXCAR 128

char *elimina(char s1[], char s2[]);

main()
{
   char str1[MAXCAR], str2[MAXCAR];
   printf(“Dammi la stringa str1: ”);
   scanf(“%s”, str1);
   printf(“Dammi la stringa str2: ”);
   scanf(“%s”, str2);
   printf(“str1-str2= %sn”, elimina(str1,str2));
}
                                                    260
Esercizio 2: Soluzione (Cont.)
char *elimina(char s1[], char s2[])
{
   int i, j, k;

    for(i=j=0;str1[i]!= „0‟;i++)
    {
      for(k=0;(str2[k]!= „0‟) && (str1[i]!=str2[k]);k++);
      if(str2[k]== „0‟)
         str1[j++]=str1[i];
    }
    str1[j]=„0‟;
    return str1;
}


                                                             261
I/O a righe

• Acquisizione/stampa di una riga alla volta
  - Riga = Serie di caratteri terminata da „n‟


• Istruzioni:
  - char *gets(<stringa>)
     • Legge una riga da tastiera (fino al „n‟)
     • La riga viene fornita come stringa (<stringa>), senza il carattere „n‟
     • In caso di errore, il risultato è la costante NULL (definita in stdio.h)


  - int puts(<stringa>)
     • Stampa <stringa> su schermo
     • Aggiunge sempre „n‟ alla stringa




                                                                                  262
I/O a righe (Cont.)

• L‟argomento di gets/puts è di tipo “puntatore”
  (discussione più avanti), definito come segue:
                              char*

• Significato: Il puntatore ad una stringa contiene l‟indirizzo
  di memoria in cui il primo carattere della stringa è
  memorizzato

• Esempio:                         s
  - char*    s;




                                                                  263
I/O a righe (Cont.)

• NOTE:
  - puts/gets sono “costruite” a partire da getchar/putchar
  - Uso di gets richiede l‟allocazione dello spazio di memoria per la
    riga letta in input
     • Gestione dei puntatori che vedremo più avanti
  - puts(s) è identica a printf(“%sn”,s);


• Usate meno di frequente delle altre istruzioni di I/O




                                                                        264
I/O a righe: Esempio

• Programma che replica su video una riga di testo scritta
  dall‟utente

#include <stdio.h>

main()
{
  char *s, *res;
  printf(“Scrivi qualcosan”);
  res = gets(s);
  if (res != NULL)   /* errore ? */
  {
       puts(“Hai inserito”);
       puts(s);
  }
}

                                                             265
Matrice bidimensionale

                   colonne
          0    1      2 ...   M-1
       0 1    2      3    4    5
       1 2    4      6    8   10
righe  2 3    6      9 12     15
          4   8      12 16    20
      ...




          5   10     15 20    25
      N-1 6   12     18 24    30

              pitagora

                                    266
Vettori multidimensionali

• E‟ possibile estendere il concetto di variabile indicizzata a
  più dimensioni
  - Utilizzo tipico:
    Vettori bidimensionali per realizzare tabelle (matrici)


• Implementazione: Vettore di vettori
             a[0][0] a[0][1] a[0][2] a[0][3] a[0][4]          a[0]

      a      a[1][0] a[1][1] a[1][2] a[1][3] a[1][4]          a[1]

             a[2][0] a[2][1] a[2][2] a[2][3] a[2][4]          a[2]



                       int a[3][5];

                                                                     267
Vettori multidimensionali (Cont.)

• Sintassi:
  <tipo> <nome vettore> [<dim1>][<dim2>] … [<dimN>];


• Accesso ad un elemento:
  <nome vettore> [<pos1>] [<pos2>] … [<posN>]

• Esempio:
  int       v[3][2];

• Inizializzazione:
  -   Inizializzazione per righe!
       • Esempio:
       int v[3][2] = {{8,1},{1,9},{0,3}}; // vettore 3x2
       int w[3][2] = { 8,1, 1,9, 0,3 }; // equivalente

                                                           268
Vettori multidimensionali e cicli

• Per vettori a più dimensioni, la scansione va applicata a
  tutte le dimensioni
  -   Cicli “annidati”

• Esempio:
  Accesso agli elementi di una matrice 3x5

  int x[3][5];
  …
  for (i=0;i < 3; i++) { /* per ogni riga i */
    for (j=0; j < 5; j++) { /* per ogni colonna j */
      ... // operazione su x[i][j]
    }
  }


                                                              269
Stampa per righe matrice di reali



printf("Matrice: %d x %dn", N, M);

for(i=0; i<N; i++)
{                    /* Stampa la riga i-esima */
    for(j=0; j<M; j++)
    {
        printf("%f ", mat[i][j]) ;
    }
    printf("n");
}



                                                    270
Lettura per righe matrice di reali

printf("Immetti matrice %d x %dn",
        N, M) ;

for(i=0; i<N; i++)
{
    printf("Riga %d:n", i+1) ;
    for(j=0; j<M; j++)
    {
        printf("Elemento (%d,%d): ",
               i+1, j+1) ;
        scanf("%f", &mat[i][j]) ;
    }
}


                                        271
Somma per righe


for(i=0 ; i<N ; i++)
{
    somma = 0.0 ;
    for(j=0; j<M; j++)
        somma = somma + mat[i][j] ;
    sr[i] = somma ;
}

for(i=0; i<N; i++)
    printf("Somma riga %d = %fn",
           i+1, sr[i]) ;



                                      272
Esercizio 1

• Scrivere un programma che acquisisca da tastiera gli
  elementi di una matrice quadrata 5x5 e che stampi su
  video la matrice trasposta

• Analisi:
  - Per il caricamento dei dati nella matrice, utilzziamo due cicli for
    annidati
     • Il più interno scandisce la matrice per colonne, utilizzando l‟indice j
     • Il più esterno scandisce la matrice per righe, utilizzando l‟indice i
  - Per la stampa della matrice trasposta, utilizziamo due cicli for
    annidati, ma con gli indici di riga (i) e colonna (j) scambiati
    rispetto al caso dell‟acquisizione dei dati




                                                                                 273
Esercizio 1: Soluzione
#include <stdio.h>

main()
{
  int matrice[5][5], i, j;

    printf("Inserire gli elementi per righe:n");
    for (i=0; i<5; i++)
         for (j=0; j<5; j++)
                scanf("%d", &matrice[i][j]);
    printf("nn");

    /* stampa della matrice trasposta */
    for (j=0; j<5; j++) {
         for (i=0; i<5; i++)
                printf("%5d", matrice[i][j]);
         printf("n");
    }
}
                                                    274
Esercizio 2

• Scrivere un programma che legga da tastiera una matrice
  quadrata di dimensioni massime 32x32 e stampi su video
  la matrice stessa con accanto a destra la somma di
  ciascuna riga ed in basso la somma di ciascuna colonna
  - Le dimensioni della matrice devono essere inserite da tastiera


• Esempio:
               4    3   1   2 10
               1    7   2   2 12
               3    3   5   0 11
               8   13   8   4


                                                                     275
Esercizio 2 (Cont.)

• Analisi:
  - Il caricamento dei valori nella matrice avviene con un doppio ciclo
    for annidato
  - Le somme delle varie righe sono memorizzate in un vettore
    vet_righe avente un numero di elementi pari al numero di righe
    della matrice
  - Le somme delle varie colonne sono memorizzate in un vettore
    vet_col avente un numero di elementi pari al numero di colonne
    della matrice
  - Il calcolo delle somme delle righe viene eseguito tramite un
    doppio ciclo for annidato che scandisce la matrice per righe
  - Il calcolo delle somme delle colonne viene eseguito tramite un
    doppio ciclo for annidato che scandisce la matrice per colonne
  - La stampa della matrice e del vettore vet_righe avviene con un
    doppio ciclo for annidato
  - La stampa del vettore col avviene con un singolo ciclo for

                                                                          276
Esercizio 2: Soluzione
#include <stdio.h>
#define MAXDIM 32

main()
{

         int matrice[MAXDIM][MAXDIM],
             vet_righe[MAXDIM],
             vet_col[MAXDIM],
             nrighe, ncol, somma, i, j;

         printf("Inserire le dimensioni della matrice: ");
         scanf("%d %d", &nrighe, &ncol);
         /* caricamento elementi della matrice per righe */
         printf("Inserire gli elementi per righe:n");
         for (i=0; i<nrighe; i++)
                for (j=0; j<ncol; j++)
                       scanf("%d", &matrice[i][j]);

                                                              277
Esercizio 2: Soluzione (Cont.)

/* calcolo della somma delle righe */
for (i=0; i<nrighe; i++) {
       somma = 0;
       for (j=0; j<ncol; j++)
              somma = somma + matrice[i][j];
       vet_righe[i] = somma;
}

/* calcolo della somma delle colonne */
for (j=0; j<ncol; j++) {
       somma = 0;
       for (i=0; i<nrighe; i++)
              somma = somma + matrice[i][j];
       vet_col[j] = somma;
}

                                               278
Esercizio 2: Soluzione (Cont.)
    /* stampa matrice e vettore somma delle righe*/
    printf("nn");
    for (i=0; i<nrighe; i++) {
           for (j=0; j<ncol; j++)
                  printf("%4d", matrice[i][j]);
           printf("%7dn", vet_righe[i]);
    }
    /* stampa vettore somma delle colonne    */
    printf("n");
    for (j=0; j<ncol; j++)
           printf("%4d", vet_col[j]);
    printf("nn");

}



                                                      279
Settimana n.9


Obiettivi                    Contenuti
• Esercizi aggiuntivi su     • Strutture dati complesse
  vettori di stringhe          gestite come “vettori
• Vettori “paralleli”          paralleli”
• Tipi di dato scalari       • Il sistema dei tipi scalari in
  (completi)                   C (completo)
• Argomenti sulla linea di   • Attivazione di programmi
  comando                      da command line
                             • Argc, argv



                                                                280
Il sistema dei tipi C



                                        Tipo di dato

                        Tipi Scalari                          Tipi Strutturati              void

Tipi interi               Tipi reali        Enumerazioni                         Vettori

              char                     float                                 Strutture

              int                      double                                     Union

                      short / long                     long                  Puntatori

                     signed/unsigned                                             Funzioni




                                                                                                   281
I tipi interi in C


       Tipo           Descrizione        Esempi
char                 Caratteri ASCII   'a' '7' '!'
int                  Interi…           +2 -18 0
                                       +24221
short int            … con meno bit
long int             … con più bit
unsigned int         Interi senza      0 1 423
                     segno…            23234
unsigned short int   … con meno bit
unsigned long int    … con più bit

                                                     282
Specifiche del C

                                                =
                          sizeof(char)                 1

                      ≤          <        ≤

sizeof(short int)         sizeof(int)         sizeof(long int)


         =                        =                    =


sizeof(unsigned           sizeof(             sizeof(unsigned
short int)                unsigned int)       long int)

                  ≤                       ≤
                                                             283
Intervallo di rappresentazione


         Tipo            Min        Max
char                  CHAR_MIN    CHAR_MAX
int                    INT_MIN     INT_MAX
short int             SHRT_MIN    SHRT_MAX
long int              LONG_MIN    LONG_MAX
unsigned int              0       UINT_MAX
unsigned short int        0       USHRT_MAX
unsigned long int         0       ULONG_MAX


                     #include <limits.h>

                                              284
Compilatori a 32 bit

      Tipo    N. Bit       Min          Max
char            8         -128          127
int            32      -2147483648   2147483647
short int      16        -32768        32767
long int       32      -2147483648   2147483647
unsigned       32           0        4294967295
int
unsigned       16           0          65536
short int
unsigned       32           0        4294967295
long int

                                                  285
I tipi reali in C


         Tipo                        Descrizione
float                     Numeri reali in singola precisione
double                    Numeri reali in doppia precisione
long double               Numeri reali in massima precisione



               segno                     esponente
                                         
                                           
                                          eeeeee
         A   1.mmmmm 2
                
                  
                        mantissa


                                                               286
Numero di bit


    Tipo       Dimensione      Mantissa        Esponente
float              32 bit        23 bit               8 bit
double             64 bit        53 bit               10 bit
long double                     double



            
           segno                      esp o n en te
                                     
                                       
                                      eeeeee
        A   1.mmmmm 2
               
                 
                    mantissa


                                                               287
Intervallo di rappresentazione


                                 float
               0


        ±1.17549435E-38
        ±3.40282347E+38

                                 double
               0


    ±2.2250738585072014E-308
    ±1.7976931348623157E+308

                                          288
Specificatori di formato

         Tipo               scanf     printf
char                   %c           %c %d
int                    %d           %d
short int              %hd          %hd %d
long int               %ld          %ld
unsigned int           %u %o %x     %u %o %x
unsigned short int     %hu          %hu
unsigned long int      %lu          %lu
float                  %f           %f %g
double                 %lf          %f %g

                                               289
Funzioni di conversione


char line[80] ;         char line[80] ;
int x ;                 float x ;

gets(line) ;            gets(line) ;
x = atoi(line) ;        x = atof(line) ;



char line[80] ;         char line[80] ;
long int x ;            double x ;

gets(line) ;            gets(line) ;
x = atol(line) ;        x = atof(line) ;



                                           290
Argomenti sulla linea
    di comando
Il modello “console”


    Sistema Operativo

   Finestra di comando

 Argomenti   Codice di uscita


    Programma utente

      int main()




                                292
Argomenti sulla linea di comando

• In C, è possibile passare informazioni ad un programma
  specificando degli argomenti sulla linea di comando
   -   Esempio:
             C:> myprog <arg1> <arg2> ... <argN>


• Comuni in molti comandi “interattivi”
   -   Esempio: MS-DOS
                 C:> copy   file1.txt dest.txt


• Automaticamente memorizzati negli argomenti del
  main()



                                                           293
Argomenti del main()

• Prototipo:

          main (int argc, char* argv[])

   - argc: Numero di argomenti specificati
      • Esiste sempre almeno un argomento (il nome del programma)


   - argv: Vettore di stringhe
      • argv[0] = primo argomento
      • argv[i] = generico argomento
      • argv[argc-1] = ultimo argomento



                                                                    294
Esempi



C:progr>quadrato          Numero argomenti = 0



                           Numero argomenti = 1
C:progr>quadrato 5
                           Argomento 1 = “5”


                           Numero argomenti = 2
C:progr>quadrato 5 K      Argomento 1 = “5”
                           Argomento 2 = “K”
                                                  295
argc e argv

• Struttura:
   - Esempio: c:> prog.exe 3 file.dat 3.2


 argv[0]                “prog.exe0”

 argv[1]              “30”

 argv[2]               “file.dat0”     argc=4

 argv[3]              “3.20”
               NULL


                                                 296
argc e argv (Cont.)

• Ciclo per l‟elaborazione degli argomenti
   for (i=0; i<argc; i++) {
         /*
         elabora argv[i] come stringa
         */
   }

• NOTA:
   - Qualunque sia la natura dell‟argomento, è sempre una stringa
   - Necessario quindi uno strumento per “convertire” in modo
     efficiente stringhe in tipi numerici



                                                                    297
Conversione degli argomenti

• Il C mette a disposizione tre funzioni per la conversione
  di una stringa in valori numerici
   int atoi(char *s);
   long atol(char *s);
   double atof(char *s);

• Esempio:
   int x = atoi(“2”) ;         // x=2
   long y = atol(“23L”);       // y=23
   double z = atof(“2.35e-2”); // z=0.0235

• Definite in stdlib.h
                                                              298
Conversione degli argomenti (Cont.)

• NOTA: Si assume che la stringa rappresenti l‟equivalente
  di un valore numerico:
   - cifre, „+‟,‟-‟                               per interi
   - cifre, „+‟,‟-‟,‟l‟,‟L‟                       per long
   - cifre, „+‟,‟-‟,‟e‟,„E‟,‟.‟                   per reali


• In caso di conversione errata o non possibile le funzioni
  restituiscono il valore 0
   - Necessario in certi casi controllare il valore della conversione!


• NOTA: Importante controllare il valore di ogni argv[i]!



                                                                         299
Conversione degli argomenti (Cont.)

• Esempio:
  Programma C che prevede due argomenti sulla linea di
  comando:
   - Primo argomento: Un intero
   - Secondo argomento: Una stringa


• Schema:
   int x;
   char s[80];
   x = atoi(argv[1]);
   strcpy(s,argv[2]);       /* s=argv[2] è errato! */
   ...



                                                         300
Programmi e opzioni

• Alcuni argomenti sulla linea di comando indicano
  tipicamente delle modalità di funzionamento “alternative”
  di un programma

• Queste “opzioni” (dette flag o switch) sono
  convenzionalmente specificate come
                      -<carattere>
  per distinguerle dagli argomenti veri e propri

• Esempio
   C:> myprog -x -u file.txt
                opzioni argomento

                                                              301
La funzione exit

• Esiste inoltre la funzione di libreria exit, dichiarata in
  <stdlib.h>, che assolve alla stessa funzione
   - Interrompe l‟esecuzione del programma
   - Ritorna il valore specificato
• Il vantaggio rispetto all‟istruzione return è che può
  essere usata all‟interno di qualsiasi funzione, non solo
  del main


           void exit(int value) ;



                                                               302
Esercizio 1

• Scrivere un programma che legga sulla linea di
  comando due interi N e D, e stampi tutti i numeri minori
  o uguali ad N divisibili per D




                                                             303
Esercizio 1: Soluzione
#include <stdio.h>
main(int argc, char* argv[]) {
  int N, D, i;
  if (argc != 3) {
    fprintf(stderr,”Numero argomenti non validon”);
    return 1;
  }
  if (argv[1] != NULL) N = atoi(argv[1]);
  if (argv[2] != NULL) D = atoi(argv[2]);

    for (i=1;i<=N;i++) {
                                   Altrimenti le operazioni
        if ((i % D) == 0) {
                                   successive operano su
           printf(”%dn”,i);
                                   stringhe = NULL
        }
    }
}

                                                              304
Esercizio 2

• Scrivere un programma m2m che legga da input un
  testo e converta tutte le lettere maiuscole in minuscole e
  viceversa, a seconda dei flag specificati sulla linea di
  comando
     -l, -L         conversione in minuscolo
     -u, -U         conversione in maiuscolo
   Un ulteriore flag -h permette di stampare un help

• Utilizzo:
   m2m   –l
   m2m   -L
   m2m   –u
   m2m   -U
   m2m   -h

                                                               305
Esercizio 2: Soluzione
#include <stdio.h>

main(int argc, char* argv[]) {
  int lowercase = 0, uppercase = 0;

    for (i=1; i<argc; i++)
    {
          switch (argv[i][1]) {
             case „l‟:
             case „L‟:
               lowercase = 1;
               break;
             case „u‟:
             case „U‟:
               uppercase = 1;
               break;
             case „h‟:
               printf(“Uso: m2m [-luh]n”);
           }
     }
    ...
}
                                              306
Esercizio 3

• Scrivere un frammento di codice che gestisca gli
  argomenti sulla linea di comando per un programma
  TEST.EXE il cui comando ha la seguente sintassi:
              TEST.EXE [-a][-b] <nome file>
   - I flag –a e –b sono opzionali (e possono essere in un ordine
     qualunque)
   - L‟ultimo argomento (<nome file>) è obbligatorio (ed è sempre
     l‟ultimo)

   - Esempi validi di invocazione:
      TEST.EXE <nome file>
      TEST.EXE –a <nome file>
      TEST.EXE –b <nome file>
      TEST.EXE –a -b <nome file>
      TEST.EXE –b -a <nome file>


                                                                    307
Esercizio 3: Soluzione
main(int argc, char* argv[]) {
   int i, aflag=0, bflag=0;
   char filename[80];

  if (argc >= 2) { /* almeno due argomenti */
      /* copiamo in una stringa, verra‟ aperto dopo */
      strcpy (filename, argv[argc-1]);

       /* processiamo gli altri (eventuali argomenti) */
      for (i=1; i<= argc-1; i++) {
          if (argv[i][0] == '-') {/* e‟ un flag */
            switch (argv[i][1]) {
               case 'a':
                   aflag = 1; break;
               case 'b':
                   bflag = 1; break;
               default:
                   fprintf(stderr,"Opzione non corretta.n");
             }
          }

                                                                308
Esercizio 3: Soluzione (Cont.)

            }
            else {
              /* Non e‟ un flag. Esce dal programma */
              fprintf(stderr,"Errore di sintassi.n");
              return;
            }
        }
    }
    else {
        /* sintassi errata. Esce dal programma */
        fprintf(stderr,"Errore di sintassi.n");
        return;
    }
}




                                                         309
Settimana n.10


Obiettivi                   Contenuti
• Strutture                 • Struct. Operatore “.”
• Vettori di strutture      • Definizione vettori di struct
                            • Definizione di struct
                              contenenti vettori (es.
                              stringhe)




                                                              310
Tipi aggregati
Tipi aggregati

• In C, è possibile definire dati composti da elementi
  eterogenei (detti record), aggregandoli in una singola
  variabile
   - Individuata dalla keyword struct


• Sintassi (definizione di tipo):

                   struct <identificatore> {
                       campi
                   };


   I campi sono nel formato:
                     <tipo> <nome campo>;

                                                           312
Aggregato di dati eterogenei

• Più informazioni eterogenee possono essere unite come
  parti (campi) di uno stesso dato dato (aggregato)




           studente

           cognome: Rossi
           nome:      Mario
           matricola: 123456   media: 27.25



                                                          313
struct

• Una definizione di struct equivale ad una definizione di
  tipo

• Successivamente, una struttura può essere usata come
  un tipo per dichiarare variabili

• Esempio:
      struct complex {
         double re;
         double im;
      }
      ...
      struct complex num1, num2;


                                                             314
struct: Esempi

struct complex {
  double re;
  double im;
}

struct identity {
  char nome[30];
  char cognome[30];
  char codicefiscale[15];
  int altezza;
  char statocivile;
}
                              315
Accesso ai campi di una struct

• Una struttura permette di accedere ai singoli campi
  tramite l‟operatore „.‟, applicato a variabili del
  corrispondente tipo struct
                    <variabile>.<campo>
• Esempio:
      struct complex {
         double re;
         double im;
      }
      ...
      struct complex num1, num2;
      num1.re = 0.33; num1.im = -0.43943;
      num2.re = -0.133; num2.im = -0.49;

                                                        316
Definizione di struct come tipo

• E‟ possibile definire un nuovo tipo a partire da una
  struct tramite la direttiva typedef
   - Passabile come parametro
   - Indicizzabile in vettori


• Sintassi:
              typedef <tipo> <nome nuovo tipo>;


• Esempio:
      typedef struct complex {
          double re;
          double im;                     compl z1,z2;
      } compl;


                                                         317
Definizione di struct come tipo (Cont.)

• Passaggio di struct come argomenti
    int f1 (compl z1, compl z2)


• struct come risultato di funzioni
    compl f2(.....)


• Vettore di struct
    compl lista[10];


• Nota:
  La direttiva typedef è applicabile anche non alle strutture per
  definire nuovi tipi
    - Esempio: typedef unsigned char BIT8;




                                                                    318
Operazioni su struct

• Confronto:
   - Non è possibile confrontare due variabili dello stesso tipo di struct
     usando il loro nome
      • Esempio:
          compl s1, s2  s1==s2     o s1!=s2 è un errore di sintassi
   - Il confronto deve avvenire confrontando i campi uno ad uno
      • Esempio:
         compl s1, s2 (s1.re == s2.re) && (s1.im == s2.im)

• Inizializzazione:
   - Come per i vettori, tramite una lista di valori tra {}
      • Esempio:
          compl s1 = {0.1213, 2.655};


   - L‟associazione è posizionale: In caso di valori mancanti, questi vengono
     inizializzati a:
      • 0, per valori “numerici”
      • NULL per puntatori


                                                                                319
Esercizio 1

• Data la seguente struct:
  struct stud {
     char nome[40];
     unsigned int matricola;
     unsigned int voto;
  }
  - Si definisca un corrispondente tipo studente
  - Si scriva un main() che allochi un vettore di 10 elementi e che
    invochi la funzione descritta di seguito
  - Si scriva una funzione ContaInsufficienti() che riceva come
    argomento il vettore sopracitato e ritorni il numero di studenti che
    sono insufficienti




                                                                           320
Esercizio 1: Soluzione
#include <stdio.h>

#define NSTUD 10

typedef struct stud {
  char nome[40];
  unsigned int matricola;
  unsigned int voto;
}studente;


int ContaInsufficienti(studente vett[], int dim); /*
  prototipo */




                                                       321
Esercizio 1: Soluzione (Cont.)
main()
{
  int i, NumIns;
  studente Lista[NSTUD];
    /* assumiamo che il programma riempia
       con valori opportuni la lista */
    NumIns = ContaInsufficienti(Lista, NSTUD);
    printf("Il numero di insufficienti e': %d.n", NumIns);
}
int ContaInsufficienti(studente s[], int numstud)
{
  int i, n=0;
    for (i=0; i<numstud; i++) {
         if (s[i].voto < 18)
             n++;
    }
    return n;
}


                                                              322
Esercizio 2

• Data una struct che rappresenta un punto nel piano
  cartesiano a due dimensioni:
  struct point {
     double x;
     double y;
  };
  ed il relativo tipo typedef struct point Point; scrivere le
  seguenti funzioni che operano su oggetti di tipo Point:
  - double DistanzaDaOrigine (Point p);
  - double Distanza (Point p1, Point p2);
  - int Quadrante (Point p); /* in quale quadrante */
  - int Allineati(Point p1, Point p2, Point p3);
    /* se sono allineati */
  - int Insterseca(Point p1, Point p2);
    /* se il segmento che ha per estremi p1 e p2
    interseca un qualunque asse*/


                                                                323
Esercizio 2: Soluzione
double DistanzaDaOrigine (Point p)
{
   return sqrt(p.x*p.x + p.y*p.y);
}

double Distanza (Point p1, Point p2)
{
   return sqrt((p1.x-p2.x)*(p1.x-p2.x) +
                (p1.y-p2.y)*(p1.y-p2.y));
}

int Quadrante (Point   p)
{
     if (p.x >= 0 &&   p.y   >=   0)   return   1;
     if (p.x <= 0 &&   p.y   >=   0)   return   2;
     if (p.x <= 0 &&   p.y   <=   0)   return   3;
     if (p.x >= 0 &&   p.y   <=   0)   return   4;
}

                                                     324
Esercizio 2: Soluzione (Cont.)
int Allineati (Point p1, Point p2, Point p3)
{
     double r1, r2;
     /* verifichiamo che il rapporto tra y e x
        delle due coppie di punti sia identico */
     r1 = (p2.y-p1.y)/(p2.x-p1.x);
     r2 = (p3.y-p2.y)/(p3.x-p2.x);
     if (r1 == r2)
         return 1;
     else
         return 0;
}
int Interseca(Point p1, Point p2)
{
     /* verifichiamo se sono in quadranti diversi */
     if (Quadrante(p1) == Quadrante(p2))
          return 0;
     else
          return 1;
}

                                                       325
Settimana n.11


Obiettivi                Contenuti
• File di testo          • Concetto di file e funzioni
• Input/output robusto     fopen/fclose
                         • Funzioni fgets+sscanf
                         • Approfondimenti su scanf
                           (inclusi tutti i tipi scalari)
                         • La funzione sscanf e
                           lettura “robusta” da file
                         • Elaborazione di file “on the
                           fly” (senza acquisirli in
                           memoria)


                                                            326
Rango delle espressioni aritmetiche
• In C, è possibile lavorare con operandi non dello stesso tipo

• Le operazioni aritmetiche avvengono dopo aver promosso tutti gli
  operandi al tipo di rango più alto:

            _Bool
             char
             short
             unsigned short
             int
             unsigned int
             long
             unsigned long
             long long
             unsigned long long
             float
             double
             long double




                                                                     327
Operatori di cast

• In alcuni casi, può essere necessario convertire esplicitamente
  un‟espressione in uno specifico tipo
   - Quando le regole di conversione automatica non si applicano
   - Esempio: int i; double d;
     l‟assegnazione i = d; fa perdere informazione


• Sintassi:
  „(‟ <tipo> „)‟ <espressione>;
   - Significato: Forza <espressione> ad essere interpretata come se fosse
     di tipo <tipo>


• Esempio:
     ...
     double f;
     f = (double) 10;

                                                                             328
Operatori di cast: Esempio
#include <stdio.h>

main()
{
    int a, b;

    printf(“Dammi un numero intero (A): ”);
    scanf(“%d”,&a);
    printf(“Dammi un numero intero (B): ”);
    scanf(“%d”,&b);
    if(b==0)
       printf(“Errore: divisione per zero!!n”);
    else
       printf(“A / B = %fn”, ((float)a)/b);
}
                                                   329
Files
Vista d‟insieme dei formati di file



                                                      File


                   File binario                                           File ASCII


   Formato                Formato             Testo                    Testo             Linguaggio
“proprietario”           “standard”           puro                  formattato             formale

                 .doc                 .pdf                   .txt                .html                 .c


                 .psd                 .zip                                        .csv                .xml


                 .xls                 .jpeg                                       .rtf                .java




                                                                                                              331
File sequenziali

• Il modo più comune per realizzare I/O da file consiste
  nell‟utilizzo del cosiddetto accesso bufferizzato
  -   Informazioni prelevate dal file attraverso una memoria interna al
      sistema (detta buffer)


• Vantaggi:
  -   Livello di astrazione più elevato
  -   Possibilità di I/O formattato


• I/O non bufferizzato:
  -   Accesso diretto a livello binario un carattere per volta



                                                                          332
File sequenziali (Cont.)

• Il C vede i file come un flusso (stream) sequenziale di
    byte
    - Nessuna struttura particolare:
      La strutturazione del contenuto è a carico del programmatore
    - Carattere terminatore alla fine del file: EOF

             Byte 0     1    2       ….           N-1
                                          …             EOF




•   NOTA: L‟accesso sequenziale implica l‟impossibilità di:
    -   Leggere all‟indietro
    -   Saltare ad uno specifico punto del file

                                                                     333
File sequenziali (Cont.)
• Accesso tramite una variabile di tipo FILE*

• Definita in stdio.h


• Dichiarazione:
       FILE* <file>;
       FILE* contiene un insieme di variabili che permettono l‟accesso per
       “tipi”


• Al momento dell‟attivazione di un programma vengono
  automaticamente attivati tre file:
   -   stdin
   -   stdout
   -   stderr


                                                                             334
File sequenziali (Cont.)

• La struttura dati FILE contiene vari campi:

  -   short           level;     /*   Fill/empty level of buffer   */
  -   unsigned        flags;     /*   File status flags            */
  -   char            fd;        /*   File descriptor              */
  -   unsigned char   hold;      /*   Ungetc char if no buffer     */
  -   short           bsize;     /*   Buffer size                  */
  -   unsigned char   *buffer;   /*   Data transfer buffer         */
  -   unsigned char   *curp;     /*   Current active pointer       */
  -   unsigned        istemp;    /*   Temporary file indicator     */
  -   short           token;     /*   Used for validity checking   */




                                                                        335
File sequenziali (Cont.)

• stdin è automaticamente associato allo standard input
  (tastiera)

• stdout e stderr sono automaticamente associati allo
  standard output (video)

• stdin,stdout,stderr sono direttamente utilizzabili
  nelle istruzioni per l‟accesso a file
  - In altre parole, sono delle variabili predefinite di tipo FILE*




                                                                      336
File: Operazioni

•       L‟uso di un file passa attraverso tre fasi fondamentali
    -     Apertura del file
    -     Accesso al file
    -     Chiusura del file


•       Prima di aprire un file occorre dichiararlo!




                                                                  337
Stati di un file

 Directory           Apertura del file                    Stream
 Nome file                                           Posizione attuale
                      Lettura / Scrittura
                       Testo / Binario
                                              File aperto
  File chiuso
                                            Risiede su disco,
 Risiede su disco,                          il programma ha
il programma non                              accesso al suo
ha accesso al suo                               contenuto
     contenuto                                 attraverso lo
                                            stream associato
                     Chiusura del file


                                                                   338
Apertura di un file

• Per accedere ad un file è necessario aprirlo:

    -   Apertura:
        Connessione di un file fisico (su disco) ad un file logico (interno al
        programma)


•   Funzione:
           FILE* fopen(char* <nomefile>, char* <modo>);


        <nomefile>: Nome del file fisico




                                                                                 339
Apertura di un file (Cont.)

-   <modo>: Tipo di accesso al file
     • “r”:       sola lettura
     • “w”:       sola scrittura (cancella il file se esiste)
     • “a”:       append (aggiunge in coda ad un file)
     • “r+”:      lettura/scrittura su file esistente
     • “w+”:      lettura/scrittura su nuovo file
     • “a+”:      lettura/scrittura in coda o su nuovo file


-   Ritorna:
     •   Il puntatore al file in caso di successo
     •   NULL in caso di errore




                                                                340
Chiusura di un file

• Quando l‟utilizzo del file fisico è terminato, è consigliabile
  chiudere il file:
  -   Chiusura:
      Cancellazione della connessione di un file fisico (su disco) ad un
      file logico (interno al programma)


• Funzione:
                        int    fclose(FILE* <file>);


      <file>: File aperto in precedenza con fopen()
  -   Ritorna:
       • 0 se l‟operazione si chiude correttamente
       • EOF in caso di errore


                                                                           341
Apertura e chiusura di un file: Esempio
FILE *fp;   /* variabile di tipo file */
...

/* apro file „testo.dat‟ in lettura *
fp = fopen(“testo.dat”,“r”);

if (fp == NULL)
      printf(“Errore nell‟aperturan”);
else
{
   /* qui posso accedere a „testo.dat‟ usando fp */
}
...
fclose(fp);
                                                      342
Lettura di un file

   Apertura del file                            Leggi riga /
                                              Leggi carattere


        File aperto in                        File aperto in
            lettura                               lettura

       Posizione iniziale                Posizione intermedia
       (primo carattere)                  (n-esimo carattere)


                            File aperto in
   Condizione
   end-of-file                  lettura
                                                                  Leggi riga /
                          Posizione finale                      Leggi carattere
Chiusura del file        (ultimo carattere)
                                                                             343
Scrittura di un file

Apertura del file                                Scrivi riga /
                                               Scrivi carattere



          File aperto in                                           Scrivi riga /
                                                                  Scrivi carattere
             scrittura

         Posizione iniziale
         (primo carattere)                     File aperto in
                                                  scrittura

La posizione intermedia                   Posizione intermedia
diviene posizione finale                   (n-esimo carattere)

                           Chiusura del file
                                                                                344
Aggiunta ad un file

Apertura del file                                Scrivi riga /
                                               Scrivi carattere



          File aperto in                                           Scrivi riga /
                                                                  Scrivi carattere
             aggiunta

         Posizione finale                      File aperto in
        (ultimo carattere)                        aggiunta

                                          Posizione intermedia
La posizione intermedia                    (n-esimo carattere
diviene posizione finale                     dopo l‟ultimo)

                           Chiusura del file
                                                                                345
Lettura a caratteri

• Lettura:
    -   int getc (FILE* <file>);
    -   int fgetc (FILE* <file>);
        • Legge un carattere alla volta dal file
        • Restituisce il carattere letto o EOF in caso di fine file o errore


•   NOTA: getchar() equivale a getc(stdin)




                                                                               346
Scrittura a caratteri

• Scrittura:
    -   int putc (int c, FILE* <file>);
    -   int fputc (int c, FILE* <file>);
        • Scrive un carattere alla volta nel file
        • Restituisce il carattere scritto o EOF in caso di errore


•   NOTA: putchar(…) equivale a putc(…,stdout)




                                                                     347
Lettura a righe

• Lettura:
    char* fgets(char* <s>,int <n>,FILE* <file>);
    -   Legge una stringa dal file fermandosi al più dopo n-1 caratteri
    -   L‟eventuale „n‟ NON viene eliminato (diverso da gets !)
    -   Restituisce il puntatore alla stringa letta o NULL in caso di fine file
        o errore


•   NOTA: gets(…) “equivale” a fgets(…,stdin)




                                                                                  348
Scrittura a righe

• Scrittura:
    int fputs(char* <s>, FILE* <file>);
    - Scrive la stringa <s> nel senza aggiungere „n‟
      (diverso da puts !)
    - Restituisce l‟ultimo carattere scritto, oppure EOF in caso di errore



•   NOTA: puts(…) “equivale” a fputs(…,stdout)




                                                                             349
Lettura formattata

• Lettura:
    int fscanf(FILE* <file>,char* <formato>,...);
    - Come scanf(), con un parametro addizionale che rappresenta
      un file
    - Restituisce il numero di campi convertiti, oppure EOF in caso di
      fine file


•   NOTA: scanf(…) “equivale” a fscanf(stdin,…)




                                                                         350
Scrittura formattata

• Scrittura:
    int fprintf(FILE* <file>,char* <formato>,...);
    - Come printf(), con un parametro addizionale che rappresenta
      un file
    - Restituisce il numero di byte scritti, oppure EOF in caso di errore



•   NOTA: printf(…) “equivale” a
    fprintf(stdout,…)




                                                                            351
Altre funzioni

• FILE* freopen(char* <nomefile>,char* <modo>);
  -   Come fopen, ma si applica ad un file già esistente
  -   Restituisce il puntatore al file oppure NULL


• int fflush(FILE* <file>);
  -   “Cancella” il contenuto di un file
  -   Restituisce 0 se termina correttamente oppure EOF


• int feof(FILE* <file>);
  -   Restituisce falso (0) se il puntatore NON è posizionato alla fine del
      file
  -   Restituisce vero (!0) se il puntatore è posizionato alla fine del file

                                                                               352
Posizionamento in un file

• Ad ogni file è associato un buffer ed un “puntatore”
  all‟interno di questo buffer

• La posizione del puntatore può essere manipolata con
  alcune funzioni

• Più utile:
                     void rewind (FILE* <file>)
  -   Posiziona il puntatore all‟inizio del file
  -   Utile per “ripartire” dall‟inizio nella scansione di un file




                                                                     353
Schema generale di lettura da file


 leggi un dato dal file;
 finchè (non è finito il file)
 {
    elabora il dato;
    leggi un dato dal file;
 }

• La condizione “non è finito il file” può essere
  realizzata in vari modi:
  -   Usando i valori restituiti dalle funzioni di input (consigliato)
  -   Usando la funzione feof()

                                                                         354
Esempio 1

• Lettura di un file formattato (esempio: Un intero per riga)
  -   Uso dei valori restituiti dalle funzioni di input (fscanf)


res = fscanf (fp, “%d”, &val);
while (res != EOF)
{
  elabora val;
  res = fscanf (fp, “%d”, &val);
}




                                                                   355
Esempio 1 (Cont.)

•   Versione “compatta” senza memorizzare il risultato di
    fscanf()
    -   Usiamo fscanf() direttamente nella condizione di fine input


while (fscanf (fp,“%d”,&val) != EOF)
{
  elabora val;
}




                                                                      356
Esempio 2

• Lettura di un file formattato (esempio: Un intero per riga)
  - Uso di feof()


fscanf (fp, “%d”, &val);
while (!feof(fp))
{
  elabora val;
  fscanf (fp, “%d”, &val);
}




                                                                357
Esempio 3

• Lettura di un file non formattato
  - Uso dei valori restituiti dalle funzioni di input (getc)

  c = getc(fp);
  while (c != EOF)
  {
    elabora c;                                         Versione 1
    c = getc(fp);
  }



  while ((c=getc(fp))!= EOF)
  {
     elabora c;                                        Versione 2
  }

                                                                    358
Esempio 4

• Lettura di un file non formattato
  - Uso dei valori restituiti dalle funzioni di input (fgets)

  s = fgets(s,80,fp);
  while (s != NULL)
  {                                                   Versione 1
    elabora s;
      s = fgets(s,80,fp);
  }



 while ((s = fgets(s,80,fp))!= NULL)
 {
    elabora s;                                        Versione 2
 }

                                                                   359
Esercizio

• Leggere un file “estremi.dat” contenente coppie di
  numeri interi (x,y), una per riga e scrivere un secondo file
  “diff.dat” che contenga le differenze x-y, una per riga

• Esempio:

             File 1                    File 2

             23       32               -9
             2        11               -9
             19       6                13
             23       5                18
             3        2                1
             …        …                …

                                                                 360
Esercizio: Soluzione
#include <stdio.h>

main() {
  FILE *fpin, *fpout;
  int x,y;
  /* apertura del primo file */
  if ((fpin = fopen(“estremi.dat”,”r”)) == NULL)
 {
      fprintf(stderr,”Errore nell‟aperturan”);
      return 1;
  }




                                                   361
Esercizio: Soluzione (Cont.)
  /* apertura del secondo file */
  if ((fpout = fopen(“diff.dat”,”w”)) == NULL)
  {
      fprintf(stderr,”Errore nell‟aperturan”);
      return 1;
  }
  /* input */
  while (fscanf(fpin,”%d %d”,&x,&y) != EOF)
 {
      /* ora ho a disposizione x e y */
      fprintf(fpout,”%dn”,x-y);
  }
  fclose (fpin);
  fclose (fpout);
}

                                                  362
Avvertenza

• In generale, è errato tentare di memorizzare il contenuto
  di un file in un vettore
  -   La dimensione (numero di righe o di dati) di un file non è quasi
      mai nota a priori
  -   Se la dimensione è nota, tipicamente è molto grande!




                                                                         363
Formattazione dell‟output

• L‟output (su schermo o su file) viene formattato
  solitamente mediante la funzione printf (o fprintf)
• Ogni dato viene stampato attraverso un opportuno
  specificatore di formato (codici %)
• Ciascuno di questi codici dispone di ulteriori opzioni per
  meglio controllare la formattazione
  -   Stampa incolonnata
  -   Numero di cifre decimali
  -   Spazi di riempimento
  -   ...




                                                               364
Specificatori di formato

           Tipo                printf
char                     %c %d
int                      %d
short int                %hd %d
long int                 %ld
unsigned int             %u %o %x
unsigned short int       %hu
unsigned long int        %lu
float                    %f %e %g
double                   %f %e %g
char []                  %s
                                        365
Forma completa degli specificatori (1)

      -
                            precision
      +
                        .
              width            *

%                                        format

      #        *

      0




                                                  366
Forma completa degli specificatori (2)

       -
                                        precision
       +
                                 .
                 width                     *

%                                                         format

       #          *

       0

                                               Specificatore di
% obbligatorio                                    formato
                         Modificatori           obbligatorio
                          opzionali
                                                                   367
Forma completa degli specificatori (3)

      -
                            precision
      +
                        .
              width            *

%                                                format

      #        *

      0

                                        Specificatori già
                                              noti



                                                          368
Forma completa degli specificatori (4)

      -
                              precision
      +
                        .
              width              *

%                                           format

      #        *

      0                Lunghezza totale:
                      numero minimo di
                       caratteri stampati



                                                     369
Esempi


Istruzione                      Risultato
printf("%d",   13) ;            13
printf("%1d", 13) ;             13
printf("%3d", 13) ;             ␣13
printf("%f",   13.14) ;         13.140000
printf("%6f", 13.14) ;          13.140000
printf("%12f", 13.14) ;         ␣␣␣13.140000
printf("%6s", "ciao") ;         ␣␣ciao




                                               370
Forma completa degli specificatori

           -
                                   precision
           +
                            .
                   width              *

%                                                    format

           #        *           Minimo numero di caratteri
                           %d   totali (eventualmente
           0                    aggiunge 0 a sinistra)
                                Numero massimo di cifre
     Precisione            %f
                                dopo la virgola
    (dipende...)
                                Massimo numero di caratteri
                           %s   (stringhe più lunghe vengono
                                troncate)
                                                               371
Esempi (1/2)


Istruzione                      Risultato
printf("%.1d",   13) ;          13
printf("%.4d", 13) ;            0013
printf("%6.4d", 13) ;           ␣␣0013
printf("%4.6d", 13) ;           000013

printf("%.2s", "ciao") ;        ci
printf("%.6s", "ciao") ;        ciao
printf("%6.3s", "ciao") ;       ␣␣␣cia



                                            372
Esempi (2/2)


Istruzione                      Risultato
printf("%.2f",   13.14) ;       13.14
printf("%.4f", 13.14) ;         13.1400
printf("%6.4f", 13.14) ;        13.1400
printf("%9.4f", 13.14) ;        ␣␣13.1400




                                            373
Forma completa degli specificatori

         -
                                        precision
         +
                                 .
                    width                  *

%                                                          format

         #           *
                            - Allinea a sinistra anziché a destra
                              Aggiungi il segno anche davanti ai
         0                  + numeri positivi
                              Aggiungi spazio davanti ai numeri
                            _ positivi
    Riempimento e           0 Aggiungi 0 iniziali fino a width
     allineamento
                            # Formato alternativo (dipende...)
                                                                    374
Esempi (1/2)


Istruzione                     Risultato
printf("%6d",   13) ;          ␣␣␣␣13
printf("%-6d", 13) ;           13␣␣␣␣
printf("%06d", 13) ;           000013

printf("%6s", "ciao") ;        ␣␣ciao
printf("%-6s", "ciao") ;       ciao␣␣




                                           375
Esempi (2/2)


Istruzione                    Risultato
printf("%d", 13) ;            13
printf("%d", -13) ;           -13
printf("%+d", 13) ;           +13
printf("%+d", -13) ;          -13
printf("% d", 13) ;           ␣13
printf("% d", -13) ;          -13




                                          376
Approfondimenti su scanf

•   Tipologie di caratteri nella stringa di formato
•   Modificatori degli specificatori di formato
•   Valore di ritorno
•   Specificatore %[]




                                                      377
Stringa di formato (1/2)

• Caratteri stampabili:
  - scanf si aspetta che tali caratteri compaiano esattamente
    nell‟input
  - Se no, interrompe la lettura
• Spaziatura (“whitespace”):
  - Spazio, tab, a capo
  - scanf “salta” ogni (eventuale) sequenza di caratteri di spaziatura
  - Si ferma al primo carattere non di spaziatura (o End-of-File)




                                                                         378
Stringa di formato (2/2)

• Specificatori di formato (%-codice):
  - Se il codice non è %c, innanzitutto scanf “salta” ogni eventuale
    sequenza di caratteri di spaziatura
  - scanf legge i caratteri successivi e cerca di convertirli secondo il
    formato specificato
  - La lettura si interrompe al primo carattere che non può essere
    interpretato come parte del campo




                                                                           379
Specificatori di formato

            Tipo               scanf
char                     %c
int                      %d
short int                %hd
long int                 %ld
unsigned int             %u %o %x
unsigned short int       %hu
unsigned long int        %lu
float                    %f
double                   %lf
char []                  %s %[...]
                                       380
Forma completa degli specificatori




                 *             width

           %                              format




                                       Specificatore di
% obbligatorio       Modificatori         formato
                      opzionali         obbligatorio


                                                          381
Forma completa degli specificatori


                 *         width

           %                         format




                                   Specificatori già
                                         noti
% obbligatorio




                                                   382
Forma completa degli specificatori



       *            width

%                                  format




              Numero massimo di
             caratteri letti per questa
                   conversione



                                            383
Esempi


Istruzione           Input    Risultato
scanf("%d", &x) ;    134xyz   x = 134
scanf("%2d", &x) ;   134xyz   x = 13
scanf("%s", v) ;     134xyz   v = "134xyz"
scanf("%2s", v) ;    134xyz   v = "13"




                                             384
Forma completa degli specificatori




           *            width

   %                            format




 Leggi questo campo,
 ma non memorizzarlo
  in alcuna variabile

                                         385
Esempi


Istruzione                 Input      Risultato
scanf("%d %s", &x, v) ;    10 Pippo   x = 10
                                      v = "Pippo"
scanf("%s", v) ;           10 Pippo   x immutato
                                      v = "10"
scanf("%*d %s", v) ;       10 Pippo   x immutato
                                      v = "Pippo"




                                                    386
Valore di ritorno

• La funzione scanf ritorna un valore intero:
  - Numero di elementi (%) effettivamente letti
     • Non conta quelli “saltati” con %*
     • Non conta quelli non letti perché l‟input non conteneva i caratteri
       desiderati
     • Non conta quelli non letti perché l‟input è finito troppo presto
        - End-of-File per fscanf
        - Fine stringa per sscanf
  - EOF se l‟input era già in condizione End-of-File all‟inizio della
    lettura




                                                                             387
Lettura di stringhe

• La lettura di stringhe avviene solitamente con lo
  specificatore di formato %s
  - Salta tutti i caratteri di spaziatura
  - Acquisisci tutti i caratteri seguenti, fermandosi al primo carattere
    di spaziatura (senza leggerlo)
• Qualora l‟input dei separatori diversi da spazio, è possibile
  istruire scanf su quali siano i caratteri leciti, mediante lo
  specificatore %[pattern]




                                                                           388
Struttura di un pattern



        ^                   -   carattere



%   [           carattere                   ]




                                                389
Esempi

Pattern        Effetto
%[r]           Legge solo sequenze di 'r'
%[abcABC]      Legge sequenze composte da a, b, c, A, B, C, in
               qualsiasi ordine e di qualsiasi lunghezza
%[a-cA-C]      Idem come sopra
%[a-zA-Z]      Sequenze di lettere alfabetiche
%[0-9]         Sequenze di cifre numeriche
%[a-zA-Z0-9]   Sequenze alfanumeriche
%[^x]          Qualunque sequenza che non contiene 'x'
%[^n]         Legge fino a file riga
%[^,;.!? ]     Si ferma alla punteggiatura o spazio

                                                                 390
Settimana n.12


Obiettivi                     Contenuti
• Uso più avanzato dei File   • Elaborazione di file
                                acquisendone il contenuto in
                                una serie di vettori paralleli o
                                in un vettore di struct
                              • Lettura/scrittura di più file
                                aperti contemporaneamente
                              • Programmi che operano
                                come “filtri” su file
                              • Cenno alla allocazione
                                dinamica di un vettore



                                                                   391
Allocazione dinamica
    della memoria
Allocazione statica

• Il C permette di allocare esclusivamente variabili in un
  numero predefinito in fase di definizione (allocazione
  statica della memoria):

  - Variabili scalari: Una variabile alla volta

  - Vettori: N variabili alla volta (con N valore costante)




                                                              393
Allocazione statica: Esempio

#define MAX 1000
                         vett è dimensionato in eccesso, in
                         modo da soddisfare in ogni caso le
struct scheda {          esigenze del programma, anche se
     int codice;         questo usa un numero minore di
                         elementi. Quindi in ogni caso vett
     char nome[20];      sarà composto da 1000 elementi da
     char cognome[20];   42 byte ciascuno, occupando cioè
                         42.000 byte
};

struct scheda vett[MAX];




                                                          394
Memoria dinamica

• Questa limitazione può essere superata allocando
  esplicitamente la memoria (allocazione dinamica della
  memoria):

  - Su richiesta:
     • Il programma è in grado di determinare, ogni volta che è lanciato, di
       quanta memoria ha bisogno


  - Per quantità definite al tempo di esecuzione:
     • Il programma usa ad ogni istante soltanto la memoria di cui ha
       bisogno, provvedendo periodicamente ad allocare la quantità di
       memoria da usare e a liberare (deallocare) quella non più utilizzata
     • In tal modo si permette ad eventuali altri processi che lavorano in
       parallelo sullo stesso sistema di meglio utilizzare la memoria
       disponibile

                                                                               395
Memoria dinamica (Cont.)

• L‟allocazione dinamica assegna memoria ad una variabile
  in un‟area apposita, fisicamente separata da quella in cui
  vengono posizionate le variabili dichiarate staticamente

• Concettualmente:
  - Mappa di memoria di     Istruzioni e dati
    un programma                 allocati
                              staticamente

          Memoria

                              Dati allocati Memoria
                            dinamicamente dinamica



                                                               396
Memoria dinamica: malloc

• La memoria viene allocata dinamicamente tramite la
  funzione malloc()

• Sintassi:
               void*       malloc(<dimensione>)

    <dimensione>: Numero (intero) di byte da allocare

  - Valore di ritorno:
    Puntatore a cui viene assegnata la memoria allocata
     • In caso di errore (esempio, memoria non disponibile), ritorna NULL
     • NOTA:
       Dato che viene ritornato un puntatore void*, è obbligatorio
       forzare il risultato al tipo del puntatore desiderato

                                                                            397
Memoria dinamica: malloc (Cont.)

• Esempio:
  char *p;
  p = (char*)malloc(10); // Alloca 10 caratteri a p

• L‟allocazione dinamica permette di superare la limitazione
  del caso statico

• Esempio:
  int n;
  char p[n];   // Errore!!

  int n;
  char *p = (char*) malloc (n);   // OK!!!



                                                               398
malloc: Esempio

int *punt;               Richiede l‟allocazione di una
int n;                   zona di memoria di n byte.
…
punt = (int *)malloc(n);
                                Trasforma il puntatore generico
if (punt == NULL)               ritornato da malloc in un
                                puntatore a int.
{
   printf (“Errore di allocazionen”);
   exit();
}                        Verifica che l‟allocazione sia
                         avvenuta regolarmente.
…

                                                                  399
Settimana n.13


Obiettivi                  Contenuti
• Preparazione all‟esame   • Svolgimento temi d‟esame




                                                        400
Settimana n.14


Obiettivi                  Contenuti
• Preparazione all‟esame   • Svolgimento temi d‟esame




                                                        401

More Related Content

PDF
Corso Java 1 - BASE
PDF
9. chapter 8 np hard and np complete problems
PPT
32 dynamic linking nd overlays
PPTX
Goal Stack Planning follows a top-down approach
DOCX
Preguntas de examen
PPTX
Multi port memory
PDF
Semaphores
PPTX
System call (Fork +Exec)
Corso Java 1 - BASE
9. chapter 8 np hard and np complete problems
32 dynamic linking nd overlays
Goal Stack Planning follows a top-down approach
Preguntas de examen
Multi port memory
Semaphores
System call (Fork +Exec)

What's hot (20)

PPTX
System software - macro expansion,nested macro calls
PPTX
Introduction to Simplified instruction computer or SIC/XE
PDF
Virtual machine and javascript engine
PDF
Syntax directed translation
PPTX
LR(1) and SLR(1) parsing
PPT
Intermediate code generation
PPT
Virtual Memory
PPTX
PDF
የስራ ላይ ደህንነት እና የድንገተኛ አደጋ ምላሽ አተገባብር22.pdf
PDF
COA-QUESTION-BANK.pdf
PDF
Python Flavors
PPT
Intermediate code generation (Compiler Design)
PPT
Interrupt
DOCX
Beyond syllabus for web technology
PPTX
Lexical Analysis - Compiler Design
PDF
Compiler design-lab-manual v-cse
PPTX
Circular wait - Operating Systems
System software - macro expansion,nested macro calls
Introduction to Simplified instruction computer or SIC/XE
Virtual machine and javascript engine
Syntax directed translation
LR(1) and SLR(1) parsing
Intermediate code generation
Virtual Memory
የስራ ላይ ደህንነት እና የድንገተኛ አደጋ ምላሽ አተገባብር22.pdf
COA-QUESTION-BANK.pdf
Python Flavors
Intermediate code generation (Compiler Design)
Interrupt
Beyond syllabus for web technology
Lexical Analysis - Compiler Design
Compiler design-lab-manual v-cse
Circular wait - Operating Systems
Ad

Viewers also liked (11)

PDF
Esercizi di programmazione in C (v. 2.01)
PDF
Alfabeto di Arduino - lezione 3
PDF
Alfabeto di Arduino - lezione 1
PDF
Internet of Things - Cos'è e cosa ci posso fare?
PPT
Arduino, quando un aperitivo avvicina elettronica ed informatica, by Filippo ...
PDF
Alfabeto di Arduino - lezione 2
PDF
Alfabeto di arduino - lezione 4
PDF
Alfabeto di Arduino - lezione 5
PDF
Alfabeto di Arduino - lezione 6
PDF
Arduino lezione 01 - a.s 2010-2011
PDF
Starter kit del docente hi tech - v03
Esercizi di programmazione in C (v. 2.01)
Alfabeto di Arduino - lezione 3
Alfabeto di Arduino - lezione 1
Internet of Things - Cos'è e cosa ci posso fare?
Arduino, quando un aperitivo avvicina elettronica ed informatica, by Filippo ...
Alfabeto di Arduino - lezione 2
Alfabeto di arduino - lezione 4
Alfabeto di Arduino - lezione 5
Alfabeto di Arduino - lezione 6
Arduino lezione 01 - a.s 2010-2011
Starter kit del docente hi tech - v03
Ad

Similar to Programmazione in C (corso 12BHD Informatica) (20)

PPT
1 Programmazione
PPT
02 algo programmi
PDF
Presentazione corretta algoritmi
PDF
Algoritmi
PDF
Cosa sono gli algoritmi?
PPTX
L'algoritmo
PDF
Lezione 3 (29 febbraio 2012)
PDF
Flow chart
PDF
15 - Programmazione: Algoritmi
PDF
01 - Programmazione: Dai Problemi ai Programmi
PPTX
Pensiero computazionale, cos'è e come formare gli studenti
PPTX
Presentazione
PPTX
Presentazione,
PDF
Ecdl modulo 1 -Fondamenti
PPTX
Algoritmi
PPTX
Guida del perfetto Algoritmista I
PPT
Algoritmi
PDF
Modulo 1 concetti di base dell'ict
PPT
Diagrammiblocchi 1228237260540857-9[2]
PDF
concetti chiave coding.pdf
1 Programmazione
02 algo programmi
Presentazione corretta algoritmi
Algoritmi
Cosa sono gli algoritmi?
L'algoritmo
Lezione 3 (29 febbraio 2012)
Flow chart
15 - Programmazione: Algoritmi
01 - Programmazione: Dai Problemi ai Programmi
Pensiero computazionale, cos'è e come formare gli studenti
Presentazione
Presentazione,
Ecdl modulo 1 -Fondamenti
Algoritmi
Guida del perfetto Algoritmista I
Algoritmi
Modulo 1 concetti di base dell'ict
Diagrammiblocchi 1228237260540857-9[2]
concetti chiave coding.pdf

Recently uploaded (9)

PDF
GIÁO ÁN CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512 (2 CỘT) NĂM HỌC ...
PPTX
Copia di PROGETTO VIOLENZA sulle donne PCTO
PDF
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 EXPLORE NEW WORLDS - CẢ NĂM...
PDF
CHUYÊN ĐỀ BỔ TRỢ NGỮ ÂM, TỪ VỰNG NÂNG CAO - TIẾNG ANH 9 VÀ ÔN THI VÀO LỚP 10 ...
PDF
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 FRIENDS GLOBAL - CẢ NĂM (24...
PDF
Mazzoni-Reggi-2012-Effetto-Lucifero-Su-Wikipedia.pdf
PDF
16 CHUYÊN ĐỀ BÀI TẬP ÔN THI TUYỂN SINH VÀO 10 - MÔN TIẾNG ANH - THEO FORM ĐỀ ...
PPTX
SLIDE-DE-CURSOS-OssssFICIAL-DA-EGEPI-.pptx
PDF
GIÁO ÁN KẾ HOẠCH BÀI DẠY CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512...
GIÁO ÁN CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512 (2 CỘT) NĂM HỌC ...
Copia di PROGETTO VIOLENZA sulle donne PCTO
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 EXPLORE NEW WORLDS - CẢ NĂM...
CHUYÊN ĐỀ BỔ TRỢ NGỮ ÂM, TỪ VỰNG NÂNG CAO - TIẾNG ANH 9 VÀ ÔN THI VÀO LỚP 10 ...
BÀI TẬP TEST BỔ TRỢ THEO TỪNG UNIT - TIẾNG ANH 10 FRIENDS GLOBAL - CẢ NĂM (24...
Mazzoni-Reggi-2012-Effetto-Lucifero-Su-Wikipedia.pdf
16 CHUYÊN ĐỀ BÀI TẬP ÔN THI TUYỂN SINH VÀO 10 - MÔN TIẾNG ANH - THEO FORM ĐỀ ...
SLIDE-DE-CURSOS-OssssFICIAL-DA-EGEPI-.pptx
GIÁO ÁN KẾ HOẠCH BÀI DẠY CHÍNH KHÓA TIẾNG ANH 9 - CẢ NĂM - THEO CÔNG VĂN 5512...

Programmazione in C (corso 12BHD Informatica)

  • 1. 12BHDxx Informatica Programmazione in C
  • 2. Settimana n.1 Obiettivi Contenuti • Problem solving • Concetto di programma • Diagrammi di flusso e • Diagrammi di flusso pseudo codice • Pseudo codice • Alcuni problemi di esempio 2
  • 3. Cosa impariamo in questo corso? Dalla specifica di un problema alla sua realizzazione come programma da eseguire su un elaboratore Costruzione di un programma 3
  • 4. Progettare Problema Soluzione Soluzione formale Realizzazione 4
  • 5. Difficoltà • I punti critici nello sviluppo di un progetto risiedono essenzialmente in: - Sviluppo di una soluzione “informale” - Formalizzazione di una soluzione • Permette una più semplice “traduzione” nelle regole di realizzazione • La soluzione di un problema passa generalmente attraverso lo sviluppo di un algoritmo ??????? 5
  • 6. Algoritmo Con il termine di algoritmo si intende la descrizione precisa (formale) di una sequenza finita di azioni che devono essere eseguite per giungere alla soluzione di un problema 6
  • 7. Algoritmo Il termine deriva dal tardo latino ”algorismus” che a sua volta deriva dal nome del matematico persiano Muhammad ibn Mūsa 'l-Khwārizmī (780-850), che scrisse un noto trattato di algebra 7
  • 8. Algoritmi e vita quotidiana 1. metti l’acqua 2. accendi il fuoco 3. aspetta 4. se l’acqua non bolle torna a 3 5. butta la pasta 6. aspetta un po’ 7. assaggia 8. se è cruda torna a 6 9. scola la pasta 8
  • 9. Algoritmo • Algoritmo: Sequenza di operazioni atte a risolvere un dato problema - Esempi: • Una ricetta di cucina • Istruzioni di installazione di un elettrodomestico • Spesso non è banale! - Esempio: • MCD? • Quale algoritmo seguiamo per ordinare un mazzo di carte? 9
  • 10. Esempio di flusso • Problema: Calcolo del massimo Problema tra due valori A e B • Soluzione: Il massimo è il più grande tra A e B... Soluzione • Soluzione formale: Soluzione 1. inizialmente: max = 0 formale 2. se A >B allora max = A; stop 3. altrimenti max = B; stop 10
  • 11. Difficoltà • I punti critici nello sviluppo di un programma risiedono essenzialmente in: - Sviluppo di una soluzione “informale” - Formalizzazione di una soluzione • Permette una più semplice “traduzione” nelle regole del linguaggio di programmazione • La soluzione di un problema passa generalmente attraverso lo sviluppo di un algoritmo 11
  • 12. Altro esempio di flusso • Problema: Calcolo del massimo comun divisore (MCD) fra due Problema valori A e B • Soluzione: Usiamo la definizione di Soluzione MCD... • Soluzione formale: ??? Soluzione formale 12
  • 13. Stadi di sviluppo di un programma 1. Scrittura di un programma - File “sorgente” Scrittura del programma - Scritto utilizzando un linguaggio di programmazione 2. Traduzione di un programma in un Traduzione formato comprensibile al calcolatore del programma • Articolato in più fasi • Gestito automaticamente da un programma chiamato traduttore • In questo corso ci occuperemo del primo punto • Ma è importante sapere cosa succede nella fase successiva! 13
  • 14. Stadi di sviluppo di un programma • Problema • Idea - Soluzione • Algoritmo - Soluzione formale • Programma - Traduzione dell‟algoritmo in una forma comprensibile ad un elaboratore elettronico • Test • Documentazione 14
  • 15. Formalizzazione della soluzione • La differenza tra una soluzione informale ed una formale sta nel modo di rappresentare un algoritmo: - Informale: Descrizione a parole - Formale: Descrizione in termini di sequenza di operazioni elementari • Esistono vari strumenti per rappresentare una soluzione in modo formale - Più usati: • Pseudo-codice • Diagrammi di flusso 15
  • 16. Formalizzazione della soluzione (Cont.) • Pseudo-codice - Vantaggi • Immediato - Svantaggi • Descrizione dell‟algoritmo poco astratta • Interpretazione più complicata • Diagrammi di flusso - Vantaggi • Più intuitivi perchè utilizzano un formalismo grafico • Descrizione dell‟algoritmo più astratta - Svantaggi • Richiedono l‟apprendimento della funzione dei vari tipi di blocco 16
  • 17. Traduzione di un programma File Compilatore sorgente Librerie Linker Librerie Librerie File oggetto Questo file può essere File direttamente caricato eseguibile in memoria ed eseguito 17
  • 18. Cosa vuol dire “programmare”? • La programmazione consiste nella scrittura di un “documento” (file sorgente) che descrive la soluzione del problema in oggetto - Esempio: Massimo comun divisore tra due numeri • In generale non esiste “la” soluzione ad un certo problema - La programmazione consiste nel trovare la soluzione più efficiente, secondo una certa metrica, al problema di interesse 18
  • 19. Cosa vuol dire “programmare”? (Cont.) • Programmare è un‟operazione “creativa”! - Ogni problema è diverso da ogni altro - Non esistono soluzioni analitiche o “universali”! • Programmare è un‟operazione complessa - Impensabile un approccio “diretto” (dal problema al programma sorgente definitivo) - Tipicamente organizzata per stadi successivi 19
  • 20. Stadi di sviluppo di un programma (Cont.) Problema Esperienza Soluzione Strumenti automatici e metodi formali Soluzione formale Tecniche di programmazione automatica Programma 20
  • 21. Stadi di sviluppo di un programma (Cont.) • La costruzione di un programma è generalmente un‟operazione iterativa • Sono previsti passi a ritroso che rappresentano le reazioni a risultati non rispondenti alle esigenze nelle diverse fasi • La suddivisione in più fasi permette di mantenere i passi a ritroso più brevi possibile (e quindi meno dispendiosi) • E' necessario quindi effettuare dei test tra una fase e la successiva affinché i ricicli siano i più corti possibili 21
  • 22. Stadi di sviluppo di un programma (Cont.) • Una volta scritto e collaudato il programma, possono verificarsi le seguenti situazioni: - Il programma è stato scritto non correttamente: Torno indietro di un livello - Il programma è descritto male in termini formali, ma corretto concettualmente: Torno indietro di due livelli - Il programma è errato concettualmente, e necessita di una differente soluzione: Torno all'inizio 22
  • 24. Diagrammi di flusso (flow-chart) • Sono strumenti grafici che rappresentano l‟evoluzione logica della risoluzione del problema • Sono composti da: - Blocchi elementari per descrivere azioni e decisioni (esclusivamente di tipo binario) - Archi orientati per collegare i vari blocchi e per descrivere la sequenza di svolgimento delle azioni 24
  • 25. Diagrammi di flusso: Blocchi di inizio/fine Start Stop 25
  • 26. Diagrammi di flusso: Blocchi di azione azione azione generica di I/O 26
  • 27. Diagrammi di flusso: Blocco di decisione V condizione F 27
  • 28. Diagrammi di flusso: Blocco di connessione 28
  • 29. Diagramma di flusso : Esempio Start 1 F 2 5 V 3 Stop 4 29
  • 30. Diagramma di flusso : Esempio Start Stop 30
  • 31. Costruzione di diagrammi di flusso • Per mezzo dei diagrammi di flusso si possono rappresentare flussi logici complicati a piacere • E‟ però preferibile scrivere diagrammi di flusso strutturati, che seguano cioè le regole della programmazione strutturata • Così facendo si ottiene: - Maggiore formalizzazione dei problemi - Riusabilità del codice - Maggiore leggibilità 31
  • 32. Diagrammi di flusso strutturati • Definizione formale: - Diagrammi di flusso strutturati: Composti da strutture elementari indipendenti tra loro - Struttura elementare = Composizione particolare di blocchi elementari - Sempre riducibili ad un diagramma di flusso elementare costituito da un'unica azione • Rispetto a diagrammi di flusso non strutturati questo implica l‟assenza di salti incondizionati all'interno del flusso logico del diagramma 32
  • 33. Diagrammi di flusso strutturati (Cont.) • Un diagramma di flusso è detto strutturato se contiene solo un insieme predefinito di strutture elementari: - Uno ed uno solo blocco Start - Uno ed uno solo blocco Stop - Sequenza di blocchi (di azione e/o di input-output) - If - Then - ( Else ) - While - Do - Repeat - Until 33
  • 34. Sequenza struttura-1 . . . struttura struttura-2 34
  • 35. If-Then-Else V condizione F struttura-1 struttura-2 35
  • 36. If-Then V condizione F struttura 36
  • 37. While-Do condizione F V struttura 37
  • 38. do - while struttura condizione F V 38
  • 39. Teorema di Böhm - Jacopini Qualunque diagramma di flusso è sempre trasformabile in un diagramma di flusso strutturato equivalente a quello dato • Quindi, qualunque flusso logico può essere realizzato utilizzando solamente due strutture di controllo: - Meccanismo di decisione - Meccanismo di ripetizione (loop) 39
  • 40. Settimana n.2 Obiettivi Contenuti • Utilizzo del compilatore e • Uso del compilatore ciclo scrittura- • Variabili (tipo int, float) compilazione-esecuzione. • Scheletro base di un • Struttura base di un programma C programma in C. • Espressioni aritmetiche ed • Costrutti condizionali operatori base (+ - * / %) semplici • Scanf e printf a livello elementarie • Costrutto if e if-else • Operatori relazionali 40
  • 41. Dalla soluzione al programma • La scrittura del programma vero e proprio è praticamente immediata a partire dalla soluzione formale • I linguaggi di programmazione forniscono infatti costrutti di diversa complessità a seconda del tipo di linguaggio 41
  • 42. Quali linguaggi? • Diversi livelli (di astrazione) - Linguaggi ad alto livello • Elementi del linguaggio hanno complessità equivalente ai blocchi dei diagrammi di flusso strutturati (condizionali, cicli,…) - Esempio: C, C++, Basic, Pascal, Fortran, Java, etc. - Indipendenti dall‟hardware - Linguaggi “assembler” • Elementi del linguaggio sono istruzioni microarchitetturali - Dipendenti dall‟hardware - Esempio: Assembler del microprocessore Intel Pentium 42
  • 43. Quali linguaggi? (Cont.) • Esempi: - Linguaggi ad alto livello … if (x > 3) then x = x+1; … - Linguaggi assembler … LOAD Reg1, Mem[1000] Specifico per una specifica ADD Reg1, 10 architettura (microprocessore) … 43
  • 44. Elementi del linguaggio • Essendo il linguaggio un‟astrazione, esistono alcuni fondamentali elementi sintattici essenziali per l‟uso del linguaggio stesso: - Parole chiave (keyword) - Dati - Identificatori - Istruzioni • Gli elementi sintattici definiscono la struttura formale di tutti i linguaggi di programmazione 44
  • 45. Parole chiave (keyword) • Vocaboli “riservati” al traduttore per riconoscere altri elementi del linguaggio - Le istruzioni sono tutte identificate da una keyword - Esempio: La keyword PRINT in alcuni linguaggi identifica il comando di visualizzazione su schermo • Non possono essere usate per altri scopi • Costituiscono i “mattoni” della sintassi del linguaggio 45
  • 46. Dati • Vista calcolatore: - Dato = Insieme di bit memorizzato in memoria centrale • Vista utente: - Dato = Quantità associata ad un certo significato • Il linguaggio di programmazione supporta la vista utente • Dato individuato da: - Un nome (identificatore) - Una interpretazione (tipo) - Una modalità di accesso (costante o variabile) 46
  • 47. Identificatore • Indica il nome di un dato (e di altre entità) in un programma • Permette di dare nomi intuitivi ai dati • Esempio: - X, raggio, dimensione, … • Nome unico all‟interno di un preciso “ambiente di visibilità” - Dati diversi = Nomi diversi! 47
  • 48. Tipo • Indica l‟intepretazione dei dati in memoria • Legato allo spazio occupato da un dato • Permette di definire tipi “primitivi” (numeri, simboli) indipendentemente dal tipo di memorizzazione del sistema 48
  • 49. Tipo di accesso • Indica la modalità di accesso ai dati: - Variabili • Dati modificabili • Valore modificabile in qualunque punto del programma - Costanti • Dati a sola lettura • Valore assegnato una volta per tutte 49
  • 50. Astrazione dei dati 100 101 X; intero; 3 102 valore=3 103 „a‟ 104 Indirizzi c; carattere; valore=„a‟ 105 106 t; reale; 107 -11.564 valore=-11.564 108 Memoria 50
  • 51. Istruzioni • Indicano le operazioni che il linguaggio permette di eseguire (traducendole) a livello macchina: - Pseudo-istruzioni • Direttive non eseguibili - Istruzioni elementari • Operazioni direttamente corrispondenti ad operazioni hardware • Esempio: Interazione con i dispositivi di I/O, modifica/accesso a dati - Istruzioni di controllo del flusso • Permettono di eseguire delle combinazioni di operazioni complesse 51
  • 52. Esempio di programma PROGRAM prova; Identificatori // programma di prova Pseudo-istruzione PAROLE CHIAVE CONSTANTS pi = 3.14159 coeff = 0.19 Specifica di celle di memoria VARIABLES x: INTEGER Specifica di tipo Istruzione y: REAL di controllo c: CHARACTER del flusso BEGIN PROGRAM x = 2; Istruzioni elementari Parte IF (y > 2) THEN y = x * pi; “operativa” PRINT x, y; END PROGRAM 52
  • 53. Linguaggio di programmazione • Imparare un linguaggio significa conoscere: - Le parole chiave - I tipi predefiniti - Le istruzioni e la loro sintassi • In questo corso: - Linguaggio C • Estensione dei concetti a linguaggi analoghi è immediata 53
  • 55. Genesi del linguaggio C • Sviluppato tra il 1969 ed il 1973 presso gli AT&T Bell Laboratories - B. Kernighan e D. Ritchie - Per uso interno - Legato allo sviluppo del sistema operativo Unix Brian Kernighan Dennis Ritchie • Nel 1978 viene pubblicato “The C Programming Language”, prima specifica ufficiale del linguaggio - Detto “K&R” 55
  • 56. Caratteristiche generali del linguaggio C • Il C è un linguaggio: - Imperativo ad alto livello • ... ma anche poco astratto - Strutturato • ... ma con eccezioni - Tipizzato • Ogni oggetto ha un tipo - Elementare • Poche keyword - Case sensitive • Maiuscolo diverso da minuscolo negli identificatori! - Portabile - Standard ANSI 56
  • 57. Storia • Sviluppo - 1969-1973 - Ken Thompson e Dennis Ritchie - AT&T Bell Labs • Versioni del C e Standard - K&R (1978) - C89 (ANSI X3.159:1989) - C90 (ISO/IEC 9899:1990) - C99 (ANSI/ISO/IEC 9899:1999, INCITS/ISO/IEC 9899:1999) • Non tutti i compilatori sono standard! - GCC: Quasi C99, con alcune mancanze ed estensioni - Borland & Microsoft: Abbastanza C89/C90 57
  • 58. Diffusione attuale • I linguaggi attualmente più diffusi al mondo sono: - C - C++, un‟evoluzione del C - Java, la cui sintassi è tratta da C++ - C#, estremamente simile a Java e C++ • Il linguaggio C è uno dei linguaggi più diffusi • La sintassi del linguaggio C è ripresa da tutti gli altri linguaggi principali 58
  • 59. Un esempio #include <stdio.h> int main(void) { printf("hello, worldn"); return 0; } 59
  • 60. Applicazioni “console” • Interazione utente limitata a due casi - Stampa di messaggi, informazioni e dati a video - Immissione di un dato via tastiera • L‟insieme tastiera+video viene detto terminale • Nessuna caratteristica grafica • Elaborazione - Sequenziale - Interattiva - Mono-utente 60
  • 61. Modello di applicazioni “console” Scrittura somma.c programma Programma sorgente in C Compilatore C somma.exe Programma eseguibile Visualizzazione Immissione dati risultati 61
  • 62. Compilatore C Compilatore C • Traduce i programmi sorgenti scritti in linguaggio C in programmi eseguibili • È a sua volta un programma eseguibile, a disposizione del programmatore • Controlla l‟assenza di errori di sintassi del linguaggio • Non serve all‟utente finale del programma • Ne esistono diversi, sia gratuiti che commerciali 62
  • 63. Scrittura programma Scrittura del programma • Un sorgente C è un normale file di testo • Si utilizza un editor di testi - Blocco Note - Editor specializzati per programmatori 63
  • 64. Editor per programmatori • Colorazione ed evidenziazione della sintassi • Indentazione automatica • Attivazione automatica della compilazione • Identificazione delle parentesi corrispondenti • Molti disponibili, sia gratuiti che commerciali 64
  • 65. Scrittura programma Compilatore C Ambienti integrati • Applicazioni software integrate che contengono al loro interno - Un editor di testi per programmatori - Un compilatore C - Un ambiente di verifica dei programmi (debugger) • IDE: Integrated Development Environment 65
  • 66. Identificatori • Si riferiscono ad una delle seguenti entità: - Costanti - Variabili - Tipi - Sottoprogrammi - File - Etichette • Regole: - Iniziano con carattere alfabetico o “_” - Contengono caratteri alfanumerici o “_” 66
  • 67. Identificatori (Cont.) • Caratteristiche: - Esterni: Gli oggetti del sistema • Case insensitive • Significativi almeno i primi 6 caratteri - Interni: Le entità del programma • Case sensitive • Significativi almeno i primi 31 caratteri - Riservati: • Parole chiave del linguaggio • Elementi della libreria C standard 67
  • 68. Commenti • Testo libero inserito all‟interno del programma • Non viene considerato dal compilatore • Serve al programmatore, non al sistema! • Formato: - Racchiuso tra /* */ - Non è possibile annidarli - Da // fino alla fine della linea • Esempi: /* Questo è un commento ! */ /* Questo /* risulterà in un */ errore */ // Questo è un altro commento 68
  • 69. Parole chiave • Riservate! • Nel C standard sono 32 auto double int struct break else long switch case enum register typedef char extern return union const float short unsigned continue for signed void default goto sizeof volatile do if static while 69
  • 70. Parole chiave (Cont.) • Riservate! • Nel C99 sono 37 (in neretto quelle aggiunte nel C99) auto break case char const continue default do double else enum extern float for goto if inline int long register restrict return short signed sizeof static struct switch typedef union unsigned void volatile while _Bool _Complex _Imaginary 70
  • 71. Struttura di un programma C • Struttura generale: Parte dichiarativa globale main() { Parte dichiarativa locale Parte esecutiva } 71
  • 72. Struttura di un programma C (Cont.) • Parte dichiarativa globale - Elenco degli oggetti che compongono il programma e specifica delle loro caratteristiche • Categoria degli oggetti - Tipicamente dati • Tipo degli oggetti - Numerici, non numerici • main - Parola chiave che indica il punto di “inizio” del programma quando viene eseguito dal sistema operativo - Contenuto delimitato da parentesi graffe { … } 72
  • 73. Struttura di un programma C (Cont.) • Parte dichiarativa locale - Elenco degli oggetti che compongono il main e specifica delle loro caratteristiche • Parte esecutiva - Sequenza di istruzioni - Quella che descriviamo con il diagramma di flusso! • Nel C99 è possibile alternare parti esecutive e parti dichiarative - E` tuttavia consigliato non ricorrere troppo sovente a questa pratica 73
  • 74. Struttura di un programma C (Cont.) • Programma minimo: main() Start { } Stop file prova.c 74
  • 75. Notazione • Per specificare la sintassi di un‟istruzione utilizziamo un formalismo particolare • Simboli utilizzati - <nome> Un generico nome • Esempio: <numero> indica che va specificato un generico valore numerico - [ <op> ] Un‟operazione opzionale - „ c„ Uno specifico simbolo • Esempio: „?‟ indica che comparirà il carattere ? esplicitamente - nome Una parola chiave 75
  • 76. Pre-processore C • La compilazione C passa attraverso un passo preliminare che precede la vera e propria traduzione in linguaggio macchina • Il programma che realizza questa fase è detto pre-processore • Funzione principale: Espansione delle direttive che iniziano con il simbolo „#‟ • Direttive principali: - #include - #define 76
  • 77. Direttiva #include • Sintassi: - #include <file> <file> può essere specificato come: „<‟<nomefile>„>‟ per includere un file di sistema - Esempio: #include <stdio.h> „“‟<nomefile>„”‟ per includere un file definito dal programmatore - Esempio: #include “miofile.h” • Significato: <file> viene espanso ed incluso per intero nel file sorgente 77
  • 78. Direttiva #include • Esempio: file.c mydef.h #include “mydef.h” int x,y; .... double z; int main() { ... } Pre-processore int x,y; double z; .... int main() { ... } 78
  • 79. Dati
  • 80. Dichiarazione di dati • In C, tutti i dati devono essere dichiarati prima di essere utilizzati! • La dichiarazione di un dato richiede: - L‟allocazione di uno spazio in memoria atto a contenere il dato - L‟assegnazione di un nome a tale spazio in memoria • In particolare, occorre specificare: - Nome (identificatore) - Tipo - Modalità di accesso (variabile o costante) 80
  • 81. Tipi base (primitivi) • Sono quelli forniti direttamente dal C • Identificati da parole chiave! - char caratteri ASCII - int interi (complemento a 2) - float reali (floating point singola precisione) - double reali (floating point doppia precisione) - Nel C99: _Bool booleano (vero o falso) • La dimensione precisa di questi tipi dipende dall‟architettura (non definita dal linguaggio) - |char| = 8 bit = 1 Byte sempre 81
  • 82. Modificatori dei tipi base • Sono previsti dei modificatori, identificati da parole chiave da premettere ai tipi base - Segno: • signed/unsigned - Applicabili ai tipi char e int » signed: Valore numerico con segno » unsigned: Valore numerico senza segno - Dimensione: • short/long - Applicabili al tipo int - Utilizzabili anche senza specificare int - Nel C99: • Numeri complessi / parte immaginaria: - _Complex - _Imaginary 82
  • 83. Modificatori dei tipi base (Cont.) • Interi - [signed/unsigned] short [int] - [signed/unsigned] int - [signed/unsigned] long [int] - [signed/unsigned] long long [int] (nel C99) • Reali - float - double - long double (nel C99) - float _Complex (nel C99) - double _Complex (nel C99) - long double _Complex (nel C99) 83
  • 84. Il sistema dei tipi C Tipo di dato Tipi Scalari Tipi Strutturati void Tipi interi Tipi reali Enumerazioni Vettori char float Strutture int double Union short / long long Puntatori signed/unsigned Funzioni 84
  • 85. Variabili • Locazioni di memoria destinate alla memorizzazione di dati il cui valore è modificabile • Sintassi: <tipo> <variabile> ; <variabile>: Identificatore che indica il nome della variabile • Sintassi alternativa (dichiarazioni multiple): <tipo> <lista di variabili>; <lista di variabili>: Lista di identificatori separati da „,‟ 85
  • 86. Variabili (Cont.) • Esempi: int x; char ch; long int x1, x2, x3; double pi; short int stipendio; long y, z; • Usiamo nomi significativi! - Esempi: • int x0a11; /* NO */ • int valore; /* SI */ • float raggio; /* SI */ 86
  • 87. Esempi di nomi a b a1 a2 num n N somma max area perimetro perim n_elementi Nelementi risultato trovato nome risposta 87
  • 88. Esempi i 0 int i, j ; int N ; int x ; j 2 i = 0 ; j = 2 ; N N = 100 ; 100 x = -3124 ; x -3124 88
  • 89. Esempi a 3.1 float a, b ; float pigr ; float Nav, Qe ; b 2.0 a = 3.1 ; b = 2.0 ; pigr 3.1415 pigr = 3.1415926 ; Nav = 6.022e23 ; Qe = 1.6e-19 ; Nav 6.02×1023 Qe 1.6×10–19 89
  • 90. Valore contenuto • Ogni variabile, in ogni istante di tempo, possiede un certo valore • Le variabili appena definite hanno valore ignoto - Variabili non inizializzate • In momenti diversi il valore può cambiare a ? t definizione 90
  • 91. Valore contenuto • Ogni variabile, in ogni istante di tempo, possiede un certo valore • Le variabili appena definite hanno valore ignoto - Variabili non inizializzate • In momenti diversi il valore può cambiare ? a 37 t definizione inizializzazione 91
  • 92. Valore contenuto • Ogni variabile, in ogni istante di tempo, possiede un certo valore • Le variabili appena definite hanno valore ignoto - Variabili non inizializzate • In momenti diversi il valore può cambiare ? 37 a -4 t definizione inizializzazione altra assegnazione 92
  • 93. Valore contenuto • Ogni variabile, in ogni istante di tempo, possiede un certo valore • Le variabili appena definite hanno valore ignoto - Variabili non inizializzate • In momenti diversi il valore può cambiare ? 37 -4 a -3 t definizione inizializzazione altra incremento assegnazione 93
  • 94. Costanti • Locazioni di memoria destinate alla memorizzazione di dati il cui valore non è modificabile • Sintassi: const <tipo> <costante> = <valore> ; <costante> : Identificatore che indica il nome della costante <valore> : Valore che la costante deve assumere • Esempi: - const double PIGRECO = 3.14159; - const char SEPARATORE = „$‟; - const float ALIQUOTA = 0.2; • Convenzione: - Identificatori delle constanti tipicamente in MAIUSCOLO 94
  • 95. Costanti (Cont.) • Esempi di valori attribuibili ad una costante: - Costanti di tipo char: • „f‟ - Costanti di tipo int, short, long • 26 • 0x1a,0X1a • 26L • 26u • 26UL - Costanti di tipo float, double • -212.6 • -2.126e2, -2.126E2, -212.6f 95
  • 96. Costanti speciali • Caratteri ASCII non stampabili e/o “speciali” • Ottenibili tramite “sequenze di escape” <codice ASCII ottale su tre cifre> • Esempi: - „007‟ - „013‟ • Caratteri “predefiniti” - „b‟ backspace - „f‟ form feed - „n‟ line feed - „t‟ tab 96
  • 97. Visibilità delle variabili • Ogni variabile è utilizzabile all‟interno di un preciso ambiente di visibilità (scope) • Variabili globali - Definite all‟esterno del main() • Variabili locali - Definite all‟interno del main() - Più in generale, definite all‟interno di un blocco 97
  • 98. Struttura a blocchi • In C, è possibile raccogliere istruzioni in blocchi racchiudendole tra parentesi graffe • Significato: Delimitazione di un ambiente di visibilità di “oggetti” (variabili, costanti) • Corrispondente ad una “sequenza” di istruzioni • Esempio: { int a=2; int b; a e b sono definite solo all‟interno del blocco! b=2*a; } 98
  • 99. Visibilità delle variabili: Esempio int n; double x; main() { int a,b,c; double y; { int d; double z; } } - n,x: Visibili in tutto il file - a,b,c,y: Visibili in tutto il main() - d,z: Visibili nel blocco delimitato dalle parentesi graffe 99
  • 101. Istruzioni elementari • Corrispondono ai blocchi di azione dei diagrammi di flusso: • Due categorie: - Assegnazione - Input/output (I/O) 101
  • 102. Assegnazione • Sintassi: <variabile> = <valore> • Non è un‟uguaglianza! - Significato: <valore> viene assegnato a <variabile> - <variabile> e <valore> devono essere di tipi “compatibili” - <variabile> deve essere stata dichiarata precedentemente! - Esempi: int x; float y; x = 3; y = -323.9498; • Può essere inclusa nella dichiarazione di una variabile - Esempi: • int x = 3; • float y = -323.9498; 102
  • 103. Istruzioni di I/O • Diverse categorie in base al tipo di informazione letta o scritta: - I/O formattato - I/O a caratteri - I/O “per righe” • Richiede la nozione di stringa. Come tale, sarà trattata in seguito • Nota: In C, le operazioni di I/O non sono gestite tramite vere e proprie istruzioni, bensì mediante opportune funzioni. - Il concetto di funzione verrà introdotto successivamente; in questa sezione le funzioni di I/O saranno impropriamente chiamate istruzioni 103
  • 104. I/O formattato • Output - Istruzione printf() • Input - Istruzione scanf() • L‟utilizzo di queste istruzioni richiede l‟inserimento di una direttiva #include <stdio.h> all‟inizio del file sorgente - Significato: “includi il file stdio.h” - Contiene alcune dichiarazioni 104
  • 105. Istruzione printf() • Sintassi: printf(<formato>,<arg1>,...,<argn>); <formato>: Sequenza di caratteri che determina il formato di stampa di ognuno dei vari argomenti • Può contenere: - Caratteri (stampati come appaiono) - Direttive di formato nella forma %<carattere> » %d intero » %u unsigned » %s stringa » %c carattere » %x esadecimale » %o ottale » %f float » %g double - <arg1>,...,<argn>: Le quantità (espressioni) che si vogliono stampare • Associati alle direttive di formato nello stesso ordine! 105
  • 106. Istruzione printf(): Esempi int x=2; float z=0.5; char c=„a‟; output printf(“%d %f %cn”,x,z,c); 2 0.5 a output printf(“%f***%c***%dn”,z,c,x); 0.5***a***2 106
  • 107. Istruzione scanf() • Sintassi: scanf(<formato>,<arg1>,...,<argn>); <formato>: come per printf <arg1>,...,<argn>: le variabili cui si vogliono assegnare valori • IMPORTANTE: I nomi delle variabili vanno precedute dall‟operatore & che indica l‟indirizzo della variabile (vedremo più avanti il perchè) • Esempio: int x; float z; scanf(“%d %f“, &x, &z); 107
  • 108. Significato di scanf() • Istruzioni di input vanno viste come assegnazioni dinamiche: - L‟assegnazione dei valori alle variabili avviene al tempo di esecuzione e viene deciso dall‟utente • Assegnazioni tradizionali = Assegnazioni statiche - L‟assegnazione dei valori alle variabili è scritta nel codice! 108
  • 109. I/O formattato avanzato • Le direttive della stringa formato di printf e scanf sono in realtà più complesse - printf: %[flag][min dim][.precisione][dimensione]<carattere> • [flag]: Più usati - Giustificazione della stampa a sinistra + Premette sempre il segno • [min dim]: Dimensione minima di stampa in caratteri • [precisione]: Numero di cifre frazionarie (per numeri reali) • [dimensione]: Uno tra: h argomento è short l argomento è long • carattere: Visto in precedenza 109
  • 110. I/O formattato avanzato (Cont.) - scanf: %[*][max dim][dimensione]<carattere> • [*]: Non fa effettuare l‟assegnazione (ad es., per “saltare” un dato in input) • [max dim]: Dimensione massima in caratteri del campo • [dimensione]: Uno tra: h argomento è short l argomento è long • carattere: Visto in precedenza 110
  • 111. printf() e scanf(): Esempio #include <stdio.h> main() { int a; float b; printf(“Dammi un numero intero (A): ”); if(scanf(“%d”,&a) != 1) { printf(“Errore!n”); return 1; } printf(“Dammi un numero reale (B): ”); if(scanf(“%f”,&b) != 1) { printf(“Errore!n”); return 1; } printf(“A= %dn”,a); printf(“B= %fn”,b); } 111
  • 112. Espressioni • Combinazioni di variabili, costanti ed operatori • Il valore di un‟espressione può essere assegnato ad una variabile: <variabile> = <espressione> - Significato: <espressione> è “valutata” ed il valore ottenuto è assegnato a <variabile> - <variabile> e <espressione> devono essere di tipi “compatibili” • Esistono varie categorie di operatori, applicabili a tipi di dato diversi: - Operatori aritmetici - Operatori relazionali - Operatori logici - Operatori su bit - Operatori di modifica del tipo (cast) - Operatori di calcolo della dimensione di un tipo: sizeof() 112
  • 113. Operatori aritmetici • Quattro operatori (per numeri reali e interi): + - * / • Per numeri interi, esiste l‟operatore % che ritorna il resto della divisione intera • Stesse regole di precedenza dell‟aritmetica ordinaria • Esempi: int x=5; int y=2; int q, r; q = x / y; // (q = 2, troncamento) r = x % y; // (r = 1) 113
  • 114. Divisione tra interi: Esempio #include <stdio.h> main() { int a, b; printf(“Dammi un numero intero (A): ”); scanf(“%d”,&a); printf(“n”); printf(“Dammi un numero intero (B): ”); scanf(“%d”,&b); printf(“n”); printf(“A div B = %dn”, a/b); printf(“A mod B = %dn”, a%b); } 114
  • 115. Quesito • Che operazione svolge il seguente frammento di programma? a = b ; b = a ; 115
  • 116. Quesito • Come fare a scambiare tra di loro i valori di due variabili? a 7 b –12 116
  • 117. Operatori di confronto in C • Uguaglianza - Uguale: a == b - Diverso: a != b • Ordine - Maggiore: a > b - Minore: a < b - Maggiore o uguale: a >= b - Minore o uguale: a <= b 117
  • 118. Operatori relazionali • Operano su quantità numeriche o char e forniscono un risultato “booleano”: < <= > >= == != • Il risultato è sempre di tipo int - risultato = 0 FALSO - risultato  0 VERO 118
  • 119. Istruzione if • Sintassi: if (<condizione>) <blocco1> condizione [else blocco1 blocco2 <blocco2>] <condizione>: Espressione booleana <blocco1>: Sequenza di istruzioni • Se la sequenza contiene più di una istruzione, è necessario racchiuderle tra parentesi graffe • Significato: - Se è vera <condizione>, esegui le istruzioni di <blocco1>, altrimenti esegui quelle di <blocco2> 119
  • 120. Notazione grafica Ramo “vero” Condizione V F Ramo “falso” C A B Termine della alternativa (ricongiunzione) 120
  • 121. Istruzione if : Esempio • Leggere due valori A e B, calcolarne la differenza in valore assoluto D = |A-B| e stamparne il risultato main() { int A,B,D; scanf(“%d %d”,&A,&B); if (A > B) D = A-B; else D = B-A; printf(“%dn”,D); } 121
  • 122. Settimana n.3 Obiettivi Contenuti • Condizioni complesse • Operatori logici • Costrutti condizionali • Costrutto if ed if-else con annidati annidamento • Concetto di ciclo • Costrutto switch • Funzioni <math.h> • Costrutto while 122
  • 123. Operatori logici • Operano su espressioni “booleane” e forniscono un risultato “booleano”: ! && || NOT AND OR • Equivalenti agli operatori booleani di base - Stesse regole di precedenza • NOT > AND > OR • Esempi: - (x>0) && (x<10) (x compreso tra 0 e 10) - (x1>x2) || (x1 == 3) • Le espressioni “logiche” sono valutate da sinistra a destra • La valutazione viene interrotta non appena il risultato è univocamente determinato 123
  • 124. Operatori booleani in C Operatore Sintassi Esempio booleano in C AND && (x>=a)&&(x<=b) OR || (v1>=18)||(v2>=18) NOT ! !(a>b) 124
  • 125. Scelte annidate • Nelle istruzioni del blocco “vero” o del V F C1 blocco “else”, è possibile inserire altri blocchi di A1 scelta V F C2 B • In tal caso la seconda scelta risulta annidata all‟interno della prima A2 A3 A4 125
  • 126. Istruzione switch • Sintassi: switch (<espressione>) { case <costante1>: espressione <blocco1> break; case <costante2>: <blocco2> break; blocco1 blocco2 blocco default ... default: <blocco default> } <espressione>: Espressione a valore numerico <blocco1>, <blocco2>, … : Sequenza di istruzioni (no parentesi graffe!) 126
  • 127. Istruzione switch (Cont.) • Significato: - In base al valore di <espressione>, esegui le istruzioni del case corrispondenti - Nel caso nessun case venga intercettato, esegui le istruzioni corrispondenti al caso default • NOTE: - I vari case devono rappresentare condizioni mutualmente ESCLUSIVE! - I vari case vengono eseguiti in sequenza • Per evitare questo, si usa l‟istruzione break all‟interno di un blocco 127
  • 128. Sintassi istruzione switch switch ( e ) { case v1: A1 ; e=... break ; e=v1 e=v2 altrimenti e=v3 case v2: A1 A2 ; A2 break ; A3 case v3: ... A3 ; break ; An ........... default: An ; } 128
  • 129. Istruzione switch: Esempio int x; ... switch (x) { case 1: printf(“Sono nel caso 1n”); break; case 2: printf(“Sono nel caso 2n”); break; default: printf(“Né caso 1 né caso 2n”); break; } 129
  • 130. Operatori di incremento • Per le assegnazioni composte più comuni sono previsti degli operatori espliciti: ++ -- • Casi particolari degli operatori composti dei precedenti • Significato: - Operatore ++ -> +=1 - Operatore -- -> -=1 • Esempi: - x++; - valore--; 130
  • 131. Operatore di auto-incremento a++ ; a = a + 1 ; ++a ; a-- ; a = a - 1 ; --a ; 131
  • 132. Flusso di esecuzione ciclico Prima del A ciclo Istruzioni B che vengono ripetute C Condizione V D? di ripetizione F Dopo il ciclo E 132
  • 133. Istruzione while • Sintassi: while (<condizione>) <blocco> <condizione>: Una condizione Booleana <blocco>: Sequenza di istruzioni • Se più di una istruzione, va racchiuso tra graffe • Realizza la struttura di tipo while condizione F V • Significato: - Ripeti <blocco> finché blocco <condizione> è vera 133
  • 134. Notazione grafica (while) A Ingresso Condizione V F C Corpo B Ritorno Uscita D 134
  • 135. Istruzione while: Esempio • Leggere un valore N, calcolare la somma S dei primi N numeri interi e stamparla #include <stdio.h> main() { int N, i, S; i = 1; S = 0; /* inizializzazioni */ scanf (“%d”, &N); while (i <= N) { S += i; /* operazione iterativa */ i++; /* aggiornamento condizione */ } printf (“Somma = %dn”, S); /* output */ } 135
  • 136. Anatomia di un ciclo • Conviene concepire il ciclo come 4 fasi - Inizializzazione - Condizione di ripetizione - Corpo - Aggiornamento 136
  • 137. Settimana n.4 Obiettivi Contenuti • Cicli semplici • Ciclo Do-while • Cicli annidati • Ciclo for • Istruzioni break e continue (brevemente) • Concetto di ciclo annidato ed esempio • Problem solving su dati scalari 137
  • 138. Istruzione for • Sintassi: for (<inizializzazioni>; <condizione>; <incremento>) <blocco> <inizializzazioni>: Le condizioni iniziali prima del ciclo <condizione>: Una condizione booleana <incremento>: Incremento della variabile diconteggio <blocco>: Sequenza di istruzioni • Se contiene più di una istruzione, va racchiuso tra graffe • Tutti i campi possono essere vuoti! 138
  • 139. Istruzione for (Cont.) • Significato: - Equivalente a: <inizializzazioni> while (<condizione>) { <blocco> <incremento> } • Realizza un ciclo basato su conteggio • Tipicamente contiene una variabile indice che serve da iteratore: - Parte da un valore iniziale (inizializzazione) - Arriva ad un valore finale (condizione) - Attraverso uno specifico incremento (incremento) 139
  • 140. Istruzione for (Cont.) • Esempio: - Leggere un carattere ch ed un intero N, e stampare una riga di N caratteri ch • Esempio: N=10, ch=„*‟ output = ********** - Formulazione iterativa: • Ripeti N volte l‟operazione “stampa ch” - Soluzione: #include <stdio.h> main() { int N, i; char ch; scanf(“%d %c”, &N, &ch); for (i=0; i<N; i++) printf(“%c”, ch); /*senza „n‟ !!!!*/ printf(“n”); } 140
  • 141. Istruzione for Istruzione di inizializzazione I V F for ( I; C; A ) C { B ; Istruzione di } aggiornamento B A Corpo Condizione 141
  • 142. Esercizio • Introdurre da tastiera 100 numeri interi, e calcolarne la media. Si controlli che ogni numero inserito sia compreso tra 0 e 30; in caso contrario, il numero deve essere ignorato • Analisi: - Problema iterativo - Media=? - Controllo del valore inserito 142
  • 143. Esercizio: Soluzione #include <stdio.h> main() { int valore, i, Totale=0, M=0; const int N = 100; for (i=0; i<N; i++) /* per ogni valore introdotto */ { scanf(“%d”, &valore); if (valore < 0 || valore > 30) /* controllo validità */ printf(“Valore non valido”); else { /* caso normale */ Totale += valore; /* accumula nuovo valore in Totale */ M ++; /* ho letto un dato in più */ } } printf(“La media è: %fn”, (float)Totale/M); } 143
  • 144. for e while • Il ciclo for può essere considerato un caso particolare del ciclo while • In generale si usa: - for per cicli di conteggio • Numero di iterazioni note a priori • Condizione di fine ciclo tipo “conteggio” - while per cicli “generali” • Numero di iterazioni non note a priori • Condizione di fine ciclo tipo “evento” 144
  • 145. Cicli for con iterazioni note int i ; int i ; for ( i=0; i<N; i=i+1 ) for ( i=1; i<=N; i=i+1 ) { { ....... ....... } } int i ; int i ; for ( i=N; i>0; i=i-1 ) for ( i=N-1; i>=0; i=i-1) { { ....... ....... } } 145
  • 146. Cicli annidati • Alcuni problemi presentano una struttura “bidimensionale” - L‟operazione iterativa stessa può essere espressa come un‟altra iterazione • Realizzazione: Un ciclo che contiene un altro ciclo • Struttura: for (...) { for (...) { ... } } 146
  • 147. Cicli while annidati V F V F C C V F C2 B B2 147
  • 148. Cicli while annidati V F C while( C ) { V F while( C2 ) C2 { B2 ; } B2 } 148
  • 149. Esempio i = 0 ; while( i<N ) { j = 0 ; while( j<N ) { printf("i=%d - j=%dn", i, j); j = j + 1 ; } i = i + 1 ; } 149
  • 150. Istruzione do • Sintassi: do <blocco> while (<condizione>); <condizione>: Una condizione booleana <blocco>: Sequenza di istruzioni • Se più di una istruzione, va racchiuso tra graffe • Realizza la struttura di tipo repeat blocco • Significato: - Ripeti <blocco> finché V condizione <condizione> è vera F 150
  • 151. Notazione grafica (do-while) A B V F C D 151
  • 152. Istruzione do (Cont.) • Esempio: - Leggere un valore N controllando che il valore sia positivo. In caso contrario, ripetere la lettura #include <stdio.h> main() { int n; do scanf (“%d“, &n); while (n <= 0); } 152
  • 153. Istruzione do (Cont.) • È sempre possibile trasformare un ciclo di tipo do in un ciclo di tipo while semplice, anticipando e/o duplicando una parte delle istruzioni • Esempio: #include <stdio.h> main() { int n; scanf (“%d”, &n); while (n <= 0) scanf (“%d“, &n); } 153
  • 154. Interruzione dei cicli • Il linguaggio C mette a disposizione due istruzioni per modificare il normale flusso di esecuzione di un ciclo: - break: • Termina il ciclo • L‟esecuzione continua dalla prima istruzione dopo la fine del ciclo - continue: • Termina l‟iterazione corrente • L‟esecuzione continua con la prossima iterazione del ciclo 154
  • 155. Interruzione dei cicli (Cont.) • Trasformano i cicli in blocchi non strutturati - Usare con cautela (e possibilmente non usare…) - Si può sempre evitare l‟uso di break/continue! • Usabili in ogni tipo di ciclo (while, for, do) 155
  • 156. break e continue • In termini di diagrammi di flusso (esempio: ciclo while): F F condizione condizione V V break continue blocco blocco 156
  • 157. break : Esempio • Acquisire una sequenza di numeri interi da tastiera; terminare l‟operazione quando si legge il valore 0. • Versione con break int valore; while (scanf("%d", &valore)) { if (valore == 0) { printf("Valore non consentiton"); break; /* esce dal ciclo */ } /* resto delle istruzioni del ciclo */ } 157
  • 158. break : Esempio (Cont.) • Versione senza break (strutturata) int valore, finito = 0; while (scanf("%d", &valore) && !finito) { if (valore == 0) { printf("Valore non consentiton"); finito = 1; } else { /* resto delle istruzioni del ciclo */ } } 158
  • 159. continue : Esempio • Acquisire una sequenza di numeri interi da tastiera; ignorare i numeri pari al valore 0. • Versione con continue int valore; while (scanf("%d", &valore)) { if (valore == 0) { printf("Valore non consentiton"); continue; /* va a leggere un nuovo valore */ } /* resto delle istruzioni del ciclo */ } 159
  • 160. continue : Esempio (Cont.) • Versione senza continue (strutturata) int valore; while (scanf("%d", &valore)) { if (valore == 0) { printf("Valore non consentiton"); } else { /* resto delle istruzioni del ciclo */ } } 160
  • 161. Settimana n.5 Obiettivi Contenuti • Vettori • Definizione di vettori • Dimensionamento statico dei vettori • Operazioni elementari: lettura, stampa, copia, confronto di vettori 161
  • 162. Variabili e vettori dato1 dato2 35 35 7 7 dato dato3 dato4 14 14 32 dato5 32 -9 -9 dato6 2 dato7 2 dato8 631 -18 631 dato9 -18 4 4 dato10 7 7 162
  • 163. Da evitare... int main(void) { int dato1, dato2, dato3, dato4, dato5 ; int dato6, dato7, dato8, dato9, dato10 ; . . . . . scanf("%d", &dato1) ; scanf("%d", &dato2) ; scanf("%d", &dato3) ; . . . scanf("%d", &dato10) ; printf("%dn", dato10) ; printf("%dn", dato9) ; printf("%dn", dato8) ; . . . printf("%dn", dato1) ; } 163
  • 164. ...così è meglio! int main(void) { int dato[10] ; . . . . . for( i=0; i<10; i++) scanf("%d", &dato[i]) ; for( i=9; i>=0; i--) printf("%dn", dato[i]) ; } 164
  • 165. Vettori • Insiemi di variabili dello stesso tipo aggregate in un‟unica entità - Identificate globalmente da un nome - Singole variabili (elementi) individuate da un indice, corrispondente alla loro posizione rispetto al primo elemento - L‟indice degli elementi parte da 0 - Gli elementi di un vettore sono memorizzati in celle di memoria contigue! a a a a0 a1 a2 a3 a4 165
  • 166. Dichiarazione di un vettore • Sintassi: <tipo> <nome vettore> [<dimensione>]; • Accesso ad un elemento: <nome vettore> [<posizione>] • Esempio: int v[10]; - Definisce un insieme di 10 variabili intere v[0],v[1],v[2],v[3],v[4],v[5],v[6],v[7],v[8],v[9] 166
  • 167. Definizione di vettori in C int dato[10] ; Tipo di dato Nome del Numero di base vettore elementi 167
  • 168. Inizializzazione di un vettore • E‟ possibile assegnare un valore iniziale ad un vettore (solo) al momento della sua dichiarazione • Equivalente ad assegnare OGNI elemento del vettore • Sintassi (vettore di N elementi): {<valore 0>, <valore 1>, ... ,<valore N-1>}; • Esempio: int lista[4] = {2, 0, -1, 5}; • NOTA: Se vengono specificati meno di N elementi, l‟inizializzazione assegna a partire dal primo valore. I successivi vengono posti a zero. - Esempio: int s[4] = {2, 0, -1}; /* s[0]=2, s[1]=0, s[2]=-1, s[3]=0 */ 168
  • 169. Vettori e indici • L‟indice che definisce la posizione di un elemento di un vettore DEVE essere intero! - Non necessariamente costante! • Può essere un‟espressione complessa (purché intera) • Esempi: double a[100]; /* a vettore di double */ double x; int i, j, k; … … … x = a[2*i+j-k]; /* è corretto! */ 169
  • 170. Uso di una cella di un vettore • L‟elemento di un vettore è utilizzabile come una qualsiasi variabile: - utilizzabile all‟interno di un‟espressione • tot = tot + dato[i] ; - utilizzabile in istruzioni di assegnazione • dato[0] = 0 ; - utilizzabile per stampare il valore • printf("%dn", dato[k]) ; - utilizzabile per leggere un valore • scanf("%dn", &dato[k]) ; 170
  • 171. Vettori e cicli • I cicli sono particolarmente utili per “scandire” un vettore • Utilizzo tipico: Applicazione iterativa di un‟operazione sugli elementi di un vettore • Schema: … int data[10]; for (i=0; i<10; i++) { // operazione su data[i] } … 171
  • 172. Direttiva #define • Sintassi: #define <costante> <valore> <costante>: Identificatore della costante simbolica • Convenzionalmente indicato tutto in maiuscolo <valore>: Un valore da assegnare alla costante • Utilizzo: - Definizione di costanti simboliche - Maggiore leggibilità - Maggiore flessibiltà • Il cambiamento del valore della costante si applica a tutto il file! 172
  • 173. Direttiva #define • Esempio: - #define PI 3.1415 - #define N 80 - ... - double z = PI * x; - int vect[N]; 173
  • 174. Costrutto #define #define N 10 Definizione della costante int main(void) { Uso della int dato[N] ; costante . . . } 174
  • 175. Modificatore const int main(void) Definizione { della const int N = 10 ; costante int dato[N] ; Uso della costante . . . } 175
  • 176. Sintassi • Stessa sintassi per dichiarare una variabile • Parola chiave const • Valore della costante specificato dal segno = • Definizione terminata da segno ; • Necessario specificare il tipo (es. int) • Il valore di N non si può più cambiare const int N = 10 ; 176
  • 177. Stampa vettore di interi printf("Vettore di %d interin", N) ; for( i=0; i<N; i++ ) { printf("Elemento %d: ", i+1) ; printf("%dn", v[i]) ; } 177
  • 178. Lettura vettore di interi printf("Lettura di %d interin", N) ; for( i=0; i<N; i++ ) { printf("Elemento %d: ", i+1) ; scanf("%d", &v[i]) ; } 178
  • 179. Copia di un vettore 35 12 35 35 7 2 7 7 14 73 14 14 32 -12 32 32 -9 0 -9 -9 2 0 Copia v in w 2 2 631 -17 631 631 -18 44 -18 -18 4 1 4 4 7 17 7 7 v w v w 179
  • 180. Copia di un vettore /* copia il contenuto di v[] in w[] */ for( i=0; i<N; i++ ) { w[i] = v[i] ; } 180
  • 181. Esercizio 1 • Leggere 10 valori interi da tastiera, memorizzarli in un vettore e calcolarne il minimo ed il massimo • Analisi: - Il calcolo del minimo e del massimo richiedono la scansione dell‟intero vettore - Il generico elemento viene confrontato con il minimo corrente ed il massimo corrente • Se minore del minimo, aggiorno il minimo • Se maggiore del massimo, aggiorno il massimo - Importante l‟inizializzazione del minimo/massimo corrente! 181
  • 182. Esercizio 1: Soluzione #include <stdio.h> main() { int v[10]; int i, max, min; for (i=0; i<10; i++) scanf(“%d”, &v[i]); /* uso il primo elemento per inizializzare min e max*/ max = v[0]; min = v[0]; for (i=1; i<10; i++) { if (v[i] > max) max = v[i]; if (v[i] < min) min = v[i]; } printf("Il massimo e': %3dn", max); printf("Il minimo e' : %3dn", min); } 182
  • 183. Esercizio 2 • Scrivere un programma che legga un valore decimale minore di 1000 e lo converta nella corrispondente codifica binaria • Analisi: - Usiamo l‟algoritmo di conversione binaria visto a lezione • Divisioni sucessive per 2 • Si memorizzano i resti nella posizione del vettore di peso corrispondente - La cifra meno significativa è l‟ultima posizione del vettore! - Essenziale determinare la dimensione massima del vettore • Per codificare un numero < 1000 servono 10 bit (210=1024) 183
  • 184. Esercizio 2: Soluzione #include <stdio.h> main() { int v[10] = {0}; int i=9; /* ultima posizione del vettore */ unsigned N; /* unsigned perchè positivo */ printf("Inserire un numero positivo (<1000): "); scanf("%d", &N); if (N > 1000) printf("Errore: il numero deve essere < 1000n"); else { while(N != 0) { v[i] = (N % 2); /* resto della divisione per 2! */ N = N/2; /* divido N per 2 */ i--; } for (i=0; i<10; i++) printf("%d", v[i]); printf("n"); } } 184
  • 185. Settimana n.6 Obiettivi Contenuti • Ricerche in Vettori • Ricerca di esistenza • Flag • Ricerca di universalità • Funzioni • Ricerca di duplicati • Problem solving su dati vettoriali • Definizione di Funzioni • Passaggio di parametri e valore di ritorno 185
  • 186. Ricerca di un elemento • Dato un valore numerico, verificare - se almeno uno degli elementi del vettore è uguale al valore numerico - in caso affermativo, dire dove si trova - in caso negativo, dire che non esiste • Si tratta di una classica istanza del problema di “ricerca di esistenza” 186
  • 187. Ricerca di un elemento: Esempio (1/3) int dato ; /* dato da ricercare */ int trovato ; /* flag per ricerca */ int pos ; /* posizione elemento */ ... printf("Elemento da ricercare? "); scanf("%d", &dato) ; 187
  • 188. Ricerca di un elemento: Esempio (2/3) trovato = 0 ; pos = -1 ; for( i=0 ; i<N ; i++ ) { if( v[i] == dato ) { trovato = 1 ; pos = i ; } } 188
  • 189. Ricerca di un elemento: Esempio (3/3) if( trovato==1 ) { printf("Elemento trovato " "alla posizione %dn", pos+1) ; } else { printf("Elemento non trovaton"); } 189
  • 190. Varianti • Altri tipi di ricerche - Contare quante volte è presente l‟elemento cercato - Cercare se esiste almeno un elemento maggiore (o minore) del valore specificato - Cercare se esiste un elemento approssimativamente uguale a quello specificato - ... 190
  • 191. Ricerca del massimo • Dato un vettore (di interi o reali), determinare - quale sia l‟elemento di valore massimo - quale sia la posizione in cui si trova tale elemento • Conviene applicare la stessa tecnica per l‟identificazione del massimo già vista in precedenza - Conviene inizializzare il max al valore del primo elemento 191
  • 192. Ricerca del massimo: Esempio (1/2) float max ; /* valore del massimo */ int posmax ; /* posizione del max */ ... max = r[0] ; posmax = 0 ; for( i=1 ; i<N ; i++ ) { if( r[i]>max ) { max = r[i] ; posmax = i ; } } 192
  • 193. Ricerca del massimo: Esempio (2/2) printf("Il max vale %f e si ", max) ; printf("trova in posiz. %dn", posmax) ; 193
  • 194. Ricerca di esistenza o universalità • L‟utilizzo dei flag è può essere utile quando si desiderino verificare delle proprietà su un certo insieme di dati - È vero che tutti i dati verificano la proprietà? - È vero che almeno un dato verifica la proprietà? - È vero che nessun dato verifica la proprietà? - È vero che almeno un dato non verifica la proprietà? 194
  • 195. Esempi • Verificare che tutti i dati inseriti dall‟utente siano positivi • Determinare se una sequenza di dati inseriti dall‟utente è crescente • Due numeri non sono primi tra loro se hanno almeno un divisore comune - esiste almeno un numero che sia divisore dei due numeri dati • Un poligono regolare ha tutti i lati di lunghezza uguale - ogni coppia di lati consecutivi ha uguale lunghezza 195
  • 196. Formalizzazione • È vero che tutti i dati verificano la proprietà? - x : P(x) • È vero che almeno un dato verifica la proprietà? - x : P(x) • È vero che nessun dato verifica la proprietà? - x : not P(x) • È vero che almeno un dato non verifica la proprietà? - x : not P(x) 196
  • 197. Realizzazione (1/2) • Esistenza: x : P(x) • Universalità: x : P(x) - Inizializzo flag F = 0 - Inizializzo flag F = 1 - Ciclo su tutte le x - Ciclo su tutte le x • Se P(x) è vera • Se P(x) è falsa - Pongo F = 1 - Pongo F = 0 - Se F = 1, l‟esistenza è - Se F = 1, l‟universalità è dimostrata dimostrata - Se F = 0, l‟esistenza è - Se F = 0, l‟universalità è negata negata 197
  • 198. Realizzazione (2/2) • Esistenza: x : not P(x) • Universalità: x : not P(x) - Inizializzo flag F = 0 - Inizializzo flag F = 1 - Ciclo su tutte le x - Ciclo su tutte le x • Se P(x) è falsa • Se P(x) è vera - Pongo F = 1 - Pongo F = 0 - Se F = 1, l‟esistenza è - Se F = 1, l‟universalità è dimostrata dimostrata - Se F = 0, l‟esistenza è - Se F = 0, l‟universalità è negata negata 198
  • 199. Esempio 1 • Verificare che tutti i dati inseriti dall‟utente siano positivi int positivi ; ... positivi = 1 ; i = 0 ; while( i<n ) { ... if( dato <= 0 ) positivi = 0 ; .... i = i + 1 ; } if( positivi == 1 ) printf("Tutti positivin"); 199
  • 200. Esempio 2 • Determinare se una sequenza di dati inseriti dall‟utente è crescente int crescente ; ... crescente = 1 ; precedente = INT_MIN ; i = 0 ; while( i<n ) { ... if( dato < precedente ) crescente = 0 ; precedente = dato ; .... i = i + 1 ; } 200
  • 201. Esempio 3 • Due numeri non sono primi tra loro se hanno almeno un divisore comune int A, B ; int noprimi ; ... noprimi = 0 ; i = 2 ; while( i<=A ) { ... if( (A%i==0) && (B%i==0) ) noprimi = 1 ; .... i = i + 1 ; } 201
  • 202. Esempio 4 • Un poligono regolare ha tutti i lati di lunghezza uguale int rego ; ... rego = 1 ; precedente = INT_MIN ; i = 0 ; while( i<n ) { ... if( lato != precedente ) rego = 0 ; precedente = lato ; .... i = i + 1 ; } 202
  • 203. Occupazione variabile • La principale limitazione dei vettori è la loro dimensione fissa, definita come costante al tempo di compilazione del programma • Molto spesso non si conosce l‟effettivo numero di elementi necessari fino a quando il programma non andrà in esecuzione • Occorre identificare delle tecniche che ci permettano di lavorare con vettori di dimensione fissa, ma occupazione variabile 203
  • 204. Tecnica adottata 0 N-1 N MAXN-1 MAXN 3 1 7 12 -3 1 21 43 -8 0 12 3 2 11 3 4 8 76 56 23 4 5 90 15 72 -4 -2 22 73 Elementi Elementi effettivamente inutilizzati utilizzati 204
  • 205. Esempio /* dimensione massima */ const int MAXN = 100 ; int v[MAXN] ; /* vettore di dim. max. */ int N ; /* occupazione effettiva del vettore */ ... N = 0 ; /* inizialmente “vuoto” */ 205
  • 206. Crescita del vettore • Un vettore ad occupazione variabile può facilmente crescere, aggiungendo elementi “in coda” v[N] = nuovo_elemento ; N++ ; 206
  • 207. Sottoprogrammi • Un programma realistico può consistere di migliaia di istruzioni • Sebbene fattibile, una soluzione “monolitica” del problema: - Non è molto produttiva: • Riuso del codice? • Comprensione del codice? - Non è intuitiva: • Tendenza ad “organizzare” in modo strutturato • Struttura gerarchica a partire dal problema complesso fino a sottoproblemi sempre più semplici • Approccio top-down 207
  • 208. Approccio top-down • Decomposizione del problema in sottoproblemi più semplici • Ripetibile su più livelli • Sottoproblemi “terminali” = Risolvibili in modo “semplice” 208
  • 209. Approccio top-down (Cont.) • Esempio: Pulizia di una casa Pulizia casa Pulizia Pulizia Pulizia bagno cucina camera Togli Togli Togli Lava Lucida Lava Lucida Lava Lucida polvere polvere polvere 209
  • 210. Approccio top-down (Cont.) • I linguaggi di programmazione permettono di suddividere le operazioni in modo simile tramite sottoprogrammi - Detti anche funzioni o procedure • La gerarchia delle operazioni si traduce in una gerarchia di sottoprogrammi • main() è una funzione! 210
  • 211. Funzioni e procedure • Procedure: - Sottoprogrammi che NON ritornano un risultato • Funzioni: - Sottoprogrammi che ritornano un risultato (di qualche tipo primitivo o non) • In generale, procedure e funzioni hanno dei parametri (o argomenti) - Vista funzionale: parametri f risultato 211
  • 212. Funzioni e procedure in C • Nel C K&R: - Esistono solo funzioni (tutto ritorna un valore) - Si può ignorare il valore ritornato dalle funzioni • Dal C89 (ANSI) in poi: - Funzioni il cui valore di ritorno deve essere ignorato (void) - Funzioni void  procedure 212
  • 213. Definizione di una funzione • Stabilisce un “nome” per un insieme di operazioni • Sintassi: <tipo risultato> <nome funzione> (<parametri formali >) { <istruzioni> } - Se la funzione non ha un risultato, <tipo risultato> deve essere void - Per ritornare il controllo alla funzione chiamante, nelle <istruzioni> deve comparire una istruzione • return <valore>; se non void • return; se void 213
  • 214. Definizione di una funzione (Cont.) • Tutte le funzioni sono definite allo stesso livello del main() - NON si può definire una funzione dentro un‟altra • main() è una funzione! - Tipo del valore di ritorno: int - Parametri: Vedremo più avanti! 214
  • 215. Prototipi • Così come per le variabili, è buona pratica dichiarare all‟inizio del programma le funzioni prima del loro uso (prototipi) • Sintassi: - Come per la definizione, ma si omette il contenuto (istruzioni) della funzione 215
  • 216. Prototipi: Esempio #include <stdio.h> int func1(int a); int func2(float b); ... main () { … } int func1(int a) { … } int func2(float b) { … } 216
  • 217. Funzioni e parametri • Parametri e risultato sono sempre associati ad un tipo • Esempio: float media(int a, int b) int a media() float int b • I tipi di parametri e risultato devono essere rispettati quando la funzione viene utilizzata! • Esempio: float x; int a,b; x = media(a, b); 217
  • 218. Utilizzo di una funzione • Deve rispettare l‟interfaccia della definizione • Utilizzata come una normale istruzione <variabile> = <nome funzione> (<parametri attuali>); • Può essere usata ovunque - Una funzione può anche invocare se stessa (funzione ricorsiva) 218
  • 219. Utilizzo di una funzione: Esempio #include <stdio.h> int modabs(int v1, int v2); //prototipo main() { int x,y,d; scanf(“%d %d”,&x,&y); d = modabs(x,y); // utilizzo printf(“%dn”,d); } int modabs (int v1, int v2) // definizione { int v; if (v1>=v2) { v = v1-v2; } else { v = v2-v1; } return v; } 219
  • 220. Parametri formali e attuali • E‟ importante distinguere tra: - Parametri formali: Specificati nella definizione di una funzione - Parametri attuali: Specificati durante il suo utilizzo • Esempio: - funzione Func • Definizione: double Func(int x,double y) - Parametri formali: (x,y) • Utilizzo: double z = Func(a*2, 1.34); - Parametri attuali: (Risultato di a*2, 1.34) 220
  • 221. Parametri formali e attuali (Cont.) • Vista funzionale: - Definizione: int x Func double double y - Utilizzo: a*2 => x Func double 1.34 => y 221
  • 222. Passaggio dei parametri • In C, il passaggio dei parametri avviene per valore - Significato: Il valore dei parametri attuali viene copiato in variabili locali della funzione • Implicazione: - I parametri attuali non vengono MAI modificati dalle istruzioni della funzione 222
  • 223. Passaggio dei parametri: Esempio #include <stdio.h> void swap(int a, int b); main() { int x,y; scanf(“%d %d”,&x,&y); printf(“%d %dn”,x,y); swap(x,y); /* x e y NON VENGONO MODIFICATI */ printf(“%d %dn”,x,y); } void swap(int a, int b) { int tmp; tmp = a; a = b; b = tmp; return; } 223
  • 224. Passaggio dei parametri (Cont.) • E‟ possibile modificare lo schema di passaggio per valore in modo che i parametri attuali vengano modificati dalle istruzioni della funzione • Passaggio per indirizzo (by reference) - Parametri attuali = indirizzi di variabili - Parametri formali = puntatori al tipo corrispondente dei parametri attuali - Concetto: • Passando gli indirizzi dei parametri formali posso modificarne il valore - La teoria dei puntatori verrà ripresa in dettaglio più avanti • Per il momento è sufficiente sapere che: - „&‟<variabile> fornisce l‟indirizzo di memoria di <variabile> - „*‟<puntatore> fornisce il dato contenuto nella variabile puntata da <puntatore> 224
  • 225. Passaggio dei parametri: Esempio #include <stdio.h> void swap(int *a, int *b); main() { int x,y; scanf(“%d %d”,&x,&y); printf(“%d %dn”,x,y); swap(&x,&y); Passo l‟indirizzo /* x e y SONO ORA MODIFICATI */ di x e y printf(“%d %dn”,x,y); } void swap(int *a, int *b) { int tmp; tmp = *a; *a = *b; Uso *a e *b *b = tmp; come “interi” return; } 225
  • 226. Passaggio dei parametri (Cont.) • Il passaggio dei parametri per indirizzo è indispensabile quando la funzione deve ritornare più di un risultato Parametri F Risultati 226
  • 227. Vettori e funzioni • Le funzioni possono avere come parametri dei vettori o matrici: - Parametri formali • Si indica il nome del vettore, con “[ ]” senza dimensione - Parametri attuali • Il nome del vettore SENZA “[ ]” • Il nome del vettore indica l‟indirizzo del primo elemento, quindi il vettore è passato per indirizzo! 227
  • 228. Vettori e funzioni (Cont.) • Conseguenza: - Gli elementi di un vettore passato come argomento vengono SEMPRE modificati! • ATTENZIONE: Dato che il vettore è passato per indirizzo, la funzione che riceve il vettore come argomento non ne conosce la lunghezza!!!! • Occorre quindi passare alla funzione anche la dimensione del vettore! 228
  • 229. Esercizio • Scrivere una funzione nonnull() che ritorni il numero di elementi non nulli di un vettore di interi passato come parametro • Soluzione: int nonnull(int v[], int dim) { All‟interno della funzione int i, n=0; bisogna sapere la dimensione for (i=0; i<dim; i++) { del vettore if (v[i] != 0) n++; } Se v[ ] fosse modificato dentro la funzione, il valore sarebbe return n; modificato anche nella funzione } chiamante 229
  • 230. Funzioni matematiche • Utilizzabili includendo in testa al programma #include <math.h> • NOTA: Le funzioni trigonometriche (sia dirette sia inverse) operano su angoli espressi in radianti 230
  • 231. math.h funzione definizione double sin (double x) sin (x) double cos (double x) cos (x) double tan (double x) tan (x) double asin (double x) asin (x) double acos (double x) acos (x) double atan (double x) atan (x) double atan2 (double y, double x) atan ( y / x ) double sinh (double x) sinh (x) double cosh (double x) cosh (x) double tanh (double x) tanh (x) 231
  • 232. math.h (Cont.) funzione definizione double pow (double x, double y) xY double sqrt (double x) radice quadrata double log (double x) logaritmo naturale double log10 (double x) logaritmo decimale double exp (double x) eX 232
  • 233. math.h (Cont.) funzione definizione double ceil (double x) ceil (x) double floor (double x) floor (x) double fabs (double x) valore assoluto double fmod (double x, double y) modulo restituisce la parte double modf (double x, double frazionaria di x e *ipart) memorizza la parte intera di x in ipart 233
  • 234. Funzioni matematiche: Esempio #include <stdio.h> #include <math.h> double log2(double x); main() { int nogg, nbit; printf(“Dammi il numero di oggetti: ”); scanf(“%d”, &nogg); nbit=ceil(log2((double)nogg)); printf(“Per rappresentare %d oggetti servono %d bitn”, nogg, nbit); } double log2(double x) { return log(x)/log((double)2); } 234
  • 235. Settimana n.7 Obiettivi Contenuti • Caratteri • Il tipo char • Vettori di caratteri • Input/output di caratteri • Stringhe • Operazioni su variabili char • Funzioni <ctype.h> • Stringhe come vettori di char • Il terminatore nullo • Stringhe come tipo gestito dalla libreria • Funzioni di I/O sulle stringhe 235
  • 237. Dualità caratteri - numeri • Ogni carattere è rappresentato dal suo codice ASCII y 7 W ! % 121 55 87 33 37 • Ogni stringa è rappresentata dai codici ASCII dei caratteri di cui è composta F u l v i o 0 6 A Z N 70 117 108 118 105 111 48 54 65 90 78 0 1 1 - 5 6 4 6 3 3 2 48 49 49 45 53 54 52 54 51 51 50 237
  • 238. I/O a caratteri • Acquisizione/stampa di un carattere alla volta • Istruzioni: - int getchar() • Legge un carattere da tastiera • Il carattere viene fornito come “risultato” di getchar (valore intero) • In caso di errore il risultato è la costante EOF (dichiarata in stdio.h) - int putchar(<carattere>) • Stampa <carattere> su schermo • <carattere>: Un dato di tipo char 238
  • 239. EOF • EOF = End-of-File • Rappresenta in realtà un valore fittizio corrispondente alla fine dell‟input • Indica che non ci sono più dati in input • EOF può essere prodotto in diversi modi: - Automaticamente, se si sta leggendo un file - Premendo CTRL+‟Z‟ in MS-DOS o VMS - Premendo CTRL+‟D‟ in Unix 239
  • 240. I/O a caratteri: Esempio #include <stdio.h> main() { int tasto; printf(“Premi un tasto...n”); tasto = getchar(); if (tasto != EOF) /* errore ? */ { printf(“Hai premuto %cn”, tasto); printf(“Codice ASCII = %dn”, tasto); } } 240
  • 241. scanf/printf e getchar/putchar • scanf e printf sono “costruite” a partire da getchar/putchar • scanf/printf sono utili quando è noto il formato (tipo) del dato che viene letto - Esempio: Serie di dati con formato fisso • getchar/putchar sono utili quando non è noto tale formato - Esempio: Un testo 241
  • 242. Funzioni di utilità • Classificazione caratteri (<ctype.h>) funzione definizione int isalnum (char c) Se c è lettera o cifra int isalpha (char c) Se c è lettera int isascii(char c) Se c è lettera o cifra int isdigit (char c) Se c è una cifra int islower(char c) Se c è minuscola int isupper (char c) Se c è maiuscola int isspace(char c) Se c è spazio,tab,n int iscntrl(char c) Se c è di controllo Se c è stampabile, non int isgraph(char c) spazio int isprint(char c) Se c è stampabile int ispunct(char c) Se c è di interpunzione int toupper(char c) Converte in maiuscolo int tolower(char c) Converte in minuscolo 242
  • 243. Vista d‟insieme A...F G...Z isupper !"#$%&'() *+,-./: a...f g...z ;<=>?@[] islower isalpha ^_`{|}~ ispunct 0...9 isdigit isxdigit isalnum isgraph Spazio isprint Caratteri di Tab controllo Newline isspace iscntrl 243
  • 244. Stringhe in C • Nel linguaggio C non è supportato esplicitamente alcun tipo di dato “stringa” • Le informazioni di tipo stringa vengono memorizzate ed elaborate ricorrendo a semplici vettori di caratteri char saluto[10] ; B u o n g i o r n o 244
  • 245. Stringhe (Cont.) • Definizione: Sequenze di caratteri terminate dal carattere „0‟ (NULL) • Tecnicamente: Vettori di caratteri terminati da un carattere aggiuntivo „0‟ (NULL) • Memorizzate come i vettori • La lunghezza della stringa può essere definita implicitamente mediante l‟assegnazione di una costante stringa, rappresentata da una sequenza di caratteri racchiusa tra doppi apici • Esempio: „c‟ „i‟ „a‟ „o‟ „!‟ „0‟ char s[] = “ciao!”; s[0] s[1] s[2] s[3] s[4] s[5] 245
  • 246. Stringhe (Cont.) • NOTA: La stringa vuota non è un vettore “vuoto”! - Esempio: char s[] = “”; „0‟ s[0] • Attenzione: „a‟ è diverso da “a” • Infatti „a‟ indica il carattere a, mentre “a” rappresenta la stringa a (quindi con „0‟ finale). • Graficamente: - “Ciao” ----> „C‟ „i‟ „a‟ „o‟ „0‟ - “a” ----> „a‟ „0‟ - „a‟ ----> „a‟ 246
  • 247. Formattazione di stringhe • Le operazioni di I/O formattato possono essere effettuate anche da/su stringhe • Funzioni int sscanf(char* <stringa>,char* <formato>,<espressioni>); - Restituisce EOF in caso di errore, altrimenti il numero di campi letti con successo int sprintf(char* <stringa>,char* <formato>,<variabili>)); - Restituisce il numero di caratteri scritti • Utili in casi molto particolari per costruire/analizzare stringhe con un formato fisso 247
  • 248. I/O di stringhe • Diamo per scontato di utilizzare la convenzione del terminatore nullo • Si possono utilizzare - Funzioni di lettura e scrittura carattere per carattere • Come nell‟esercizio precedente - Funzioni di lettura e scrittura di stringhe intere • scanf e printf • gets e puts 248
  • 249. Esempio const int MAX = 20 ; char nome[MAX+1] ; printf("Come ti chiami? ") ; scanf("%s", nome) ; 249
  • 250. Esempio const int MAX = 20 ; char nome[MAX+1] ; printf("Come ti chiami? ") ; gets(nome) ; 250
  • 251. Esempio printf("Buongiorno, ") ; printf("%s", nome) ; printf("!n") ; printf("Buongiorno, %s!n", nome) ; 251
  • 252. Esempio printf("Buongiorno, ") ; puts(nome) ; /* No!! printf("!n") ; */ 252
  • 253. Settimana n.8 Obiettivi Contenuti • Stringhe • Approfondimento printf • Matrici • Conversioni stringa-intero, stringa-reale e v/v • Vettori di Stringhe • Funzioni <string.h> • Matrice come estensione dei vettori (veloce) • Dualità matrici di caratteri = vettori di stringhe • Problem solving su dati testuali 253
  • 254. Manipolazione di stringhe • Data la loro natura di tipo “aggregato”, le stringhe non possono essere usate come variabili qualunque • Esempi di operazioni non lecite: char s1[20], s2[10], s3[50]; ... s1 = “abcdefg”; s2 = s3 = “hijklmno”; s1 + s2; NO! • A questo scopo esistono apposite funzioni per la manipolazione delle stringhe 254
  • 255. Funzioni di libreria per stringhe • Utilizzabili includendo in testa al programma #include <string.h> funzione definizione definizione char* strcat (char* s1, char* s2); concatenazione concatenazione s1+s2 s1+s2 char* strchr (char* s, int c); ricerca di c in s int strcmp (char* s1, char* s2); confronto confronto char* strcpy (char* s1, char* s2); s1 <= s2 s1 <= s2 int strlen (char* s); lunghezza di s lunghezza di s char* strncat (char* s1,char* s2,int n); concat. n car. max concat. n car. max char* strncpy (char* s1,char* s2,int n); copia n car. max copia n car. max char* strncmp(char* dest,char* src,int n); cfr. n car. max cfr. n car. max 255
  • 256. Funzioni di libreria per stringhe (Cont.) • NOTE: - Non è possibile usare vettori come valori di ritorno delle funzioni di libreria • Esempio: char s[20] ... s = strcat(stringa1, stringa2); /* NO! */ - Alcune funzioni possono essere usate “senza risultato” • Esempio: strcpy(<stringa destinazione>, <stringa origine>) strcat(<stringa destinazione>, <stringa origine>) - Il valore di ritorno coincide con la stringa destinazione 256
  • 257. Esercizio 1 • Realizzare un meccanismo di “cifratura” di un testo che consiste nell‟invertire le righe del testo stesso • Esempio: C’era una volta atlov anu are’C un re che ... ehc er nu 257
  • 258. Esercizio 1: Soluzione #include <stdio.h> main() { int i,j, len; char s[80], dest[80]; /* una riga */ while (gets(s) != NULL) { len = strlen(s); j = 0; for (i=len-1;i>=0;i--) { dest[j] = s[i]; j++; } dest[j]='0'; puts(dest); } } 258
  • 259. Esercizio 2 • Si scriva un programma che legga da tastiera due stringhe e cancelli dalla prima stringa i caratteri contenuti nella seconda stringa • Esempio: - str1: “Olimpico” - str2: “Oio” - risultato: “lmpc” 259
  • 260. Esercizio 2: Soluzione #include <stdio.h> #define MAXCAR 128 char *elimina(char s1[], char s2[]); main() { char str1[MAXCAR], str2[MAXCAR]; printf(“Dammi la stringa str1: ”); scanf(“%s”, str1); printf(“Dammi la stringa str2: ”); scanf(“%s”, str2); printf(“str1-str2= %sn”, elimina(str1,str2)); } 260
  • 261. Esercizio 2: Soluzione (Cont.) char *elimina(char s1[], char s2[]) { int i, j, k; for(i=j=0;str1[i]!= „0‟;i++) { for(k=0;(str2[k]!= „0‟) && (str1[i]!=str2[k]);k++); if(str2[k]== „0‟) str1[j++]=str1[i]; } str1[j]=„0‟; return str1; } 261
  • 262. I/O a righe • Acquisizione/stampa di una riga alla volta - Riga = Serie di caratteri terminata da „n‟ • Istruzioni: - char *gets(<stringa>) • Legge una riga da tastiera (fino al „n‟) • La riga viene fornita come stringa (<stringa>), senza il carattere „n‟ • In caso di errore, il risultato è la costante NULL (definita in stdio.h) - int puts(<stringa>) • Stampa <stringa> su schermo • Aggiunge sempre „n‟ alla stringa 262
  • 263. I/O a righe (Cont.) • L‟argomento di gets/puts è di tipo “puntatore” (discussione più avanti), definito come segue: char* • Significato: Il puntatore ad una stringa contiene l‟indirizzo di memoria in cui il primo carattere della stringa è memorizzato • Esempio: s - char* s; 263
  • 264. I/O a righe (Cont.) • NOTE: - puts/gets sono “costruite” a partire da getchar/putchar - Uso di gets richiede l‟allocazione dello spazio di memoria per la riga letta in input • Gestione dei puntatori che vedremo più avanti - puts(s) è identica a printf(“%sn”,s); • Usate meno di frequente delle altre istruzioni di I/O 264
  • 265. I/O a righe: Esempio • Programma che replica su video una riga di testo scritta dall‟utente #include <stdio.h> main() { char *s, *res; printf(“Scrivi qualcosan”); res = gets(s); if (res != NULL) /* errore ? */ { puts(“Hai inserito”); puts(s); } } 265
  • 266. Matrice bidimensionale colonne 0 1 2 ... M-1 0 1 2 3 4 5 1 2 4 6 8 10 righe 2 3 6 9 12 15 4 8 12 16 20 ... 5 10 15 20 25 N-1 6 12 18 24 30 pitagora 266
  • 267. Vettori multidimensionali • E‟ possibile estendere il concetto di variabile indicizzata a più dimensioni - Utilizzo tipico: Vettori bidimensionali per realizzare tabelle (matrici) • Implementazione: Vettore di vettori a[0][0] a[0][1] a[0][2] a[0][3] a[0][4] a[0] a a[1][0] a[1][1] a[1][2] a[1][3] a[1][4] a[1] a[2][0] a[2][1] a[2][2] a[2][3] a[2][4] a[2] int a[3][5]; 267
  • 268. Vettori multidimensionali (Cont.) • Sintassi: <tipo> <nome vettore> [<dim1>][<dim2>] … [<dimN>]; • Accesso ad un elemento: <nome vettore> [<pos1>] [<pos2>] … [<posN>] • Esempio: int v[3][2]; • Inizializzazione: - Inizializzazione per righe! • Esempio: int v[3][2] = {{8,1},{1,9},{0,3}}; // vettore 3x2 int w[3][2] = { 8,1, 1,9, 0,3 }; // equivalente 268
  • 269. Vettori multidimensionali e cicli • Per vettori a più dimensioni, la scansione va applicata a tutte le dimensioni - Cicli “annidati” • Esempio: Accesso agli elementi di una matrice 3x5 int x[3][5]; … for (i=0;i < 3; i++) { /* per ogni riga i */ for (j=0; j < 5; j++) { /* per ogni colonna j */ ... // operazione su x[i][j] } } 269
  • 270. Stampa per righe matrice di reali printf("Matrice: %d x %dn", N, M); for(i=0; i<N; i++) { /* Stampa la riga i-esima */ for(j=0; j<M; j++) { printf("%f ", mat[i][j]) ; } printf("n"); } 270
  • 271. Lettura per righe matrice di reali printf("Immetti matrice %d x %dn", N, M) ; for(i=0; i<N; i++) { printf("Riga %d:n", i+1) ; for(j=0; j<M; j++) { printf("Elemento (%d,%d): ", i+1, j+1) ; scanf("%f", &mat[i][j]) ; } } 271
  • 272. Somma per righe for(i=0 ; i<N ; i++) { somma = 0.0 ; for(j=0; j<M; j++) somma = somma + mat[i][j] ; sr[i] = somma ; } for(i=0; i<N; i++) printf("Somma riga %d = %fn", i+1, sr[i]) ; 272
  • 273. Esercizio 1 • Scrivere un programma che acquisisca da tastiera gli elementi di una matrice quadrata 5x5 e che stampi su video la matrice trasposta • Analisi: - Per il caricamento dei dati nella matrice, utilzziamo due cicli for annidati • Il più interno scandisce la matrice per colonne, utilizzando l‟indice j • Il più esterno scandisce la matrice per righe, utilizzando l‟indice i - Per la stampa della matrice trasposta, utilizziamo due cicli for annidati, ma con gli indici di riga (i) e colonna (j) scambiati rispetto al caso dell‟acquisizione dei dati 273
  • 274. Esercizio 1: Soluzione #include <stdio.h> main() { int matrice[5][5], i, j; printf("Inserire gli elementi per righe:n"); for (i=0; i<5; i++) for (j=0; j<5; j++) scanf("%d", &matrice[i][j]); printf("nn"); /* stampa della matrice trasposta */ for (j=0; j<5; j++) { for (i=0; i<5; i++) printf("%5d", matrice[i][j]); printf("n"); } } 274
  • 275. Esercizio 2 • Scrivere un programma che legga da tastiera una matrice quadrata di dimensioni massime 32x32 e stampi su video la matrice stessa con accanto a destra la somma di ciascuna riga ed in basso la somma di ciascuna colonna - Le dimensioni della matrice devono essere inserite da tastiera • Esempio: 4 3 1 2 10 1 7 2 2 12 3 3 5 0 11 8 13 8 4 275
  • 276. Esercizio 2 (Cont.) • Analisi: - Il caricamento dei valori nella matrice avviene con un doppio ciclo for annidato - Le somme delle varie righe sono memorizzate in un vettore vet_righe avente un numero di elementi pari al numero di righe della matrice - Le somme delle varie colonne sono memorizzate in un vettore vet_col avente un numero di elementi pari al numero di colonne della matrice - Il calcolo delle somme delle righe viene eseguito tramite un doppio ciclo for annidato che scandisce la matrice per righe - Il calcolo delle somme delle colonne viene eseguito tramite un doppio ciclo for annidato che scandisce la matrice per colonne - La stampa della matrice e del vettore vet_righe avviene con un doppio ciclo for annidato - La stampa del vettore col avviene con un singolo ciclo for 276
  • 277. Esercizio 2: Soluzione #include <stdio.h> #define MAXDIM 32 main() { int matrice[MAXDIM][MAXDIM], vet_righe[MAXDIM], vet_col[MAXDIM], nrighe, ncol, somma, i, j; printf("Inserire le dimensioni della matrice: "); scanf("%d %d", &nrighe, &ncol); /* caricamento elementi della matrice per righe */ printf("Inserire gli elementi per righe:n"); for (i=0; i<nrighe; i++) for (j=0; j<ncol; j++) scanf("%d", &matrice[i][j]); 277
  • 278. Esercizio 2: Soluzione (Cont.) /* calcolo della somma delle righe */ for (i=0; i<nrighe; i++) { somma = 0; for (j=0; j<ncol; j++) somma = somma + matrice[i][j]; vet_righe[i] = somma; } /* calcolo della somma delle colonne */ for (j=0; j<ncol; j++) { somma = 0; for (i=0; i<nrighe; i++) somma = somma + matrice[i][j]; vet_col[j] = somma; } 278
  • 279. Esercizio 2: Soluzione (Cont.) /* stampa matrice e vettore somma delle righe*/ printf("nn"); for (i=0; i<nrighe; i++) { for (j=0; j<ncol; j++) printf("%4d", matrice[i][j]); printf("%7dn", vet_righe[i]); } /* stampa vettore somma delle colonne */ printf("n"); for (j=0; j<ncol; j++) printf("%4d", vet_col[j]); printf("nn"); } 279
  • 280. Settimana n.9 Obiettivi Contenuti • Esercizi aggiuntivi su • Strutture dati complesse vettori di stringhe gestite come “vettori • Vettori “paralleli” paralleli” • Tipi di dato scalari • Il sistema dei tipi scalari in (completi) C (completo) • Argomenti sulla linea di • Attivazione di programmi comando da command line • Argc, argv 280
  • 281. Il sistema dei tipi C Tipo di dato Tipi Scalari Tipi Strutturati void Tipi interi Tipi reali Enumerazioni Vettori char float Strutture int double Union short / long long Puntatori signed/unsigned Funzioni 281
  • 282. I tipi interi in C Tipo Descrizione Esempi char Caratteri ASCII 'a' '7' '!' int Interi… +2 -18 0 +24221 short int … con meno bit long int … con più bit unsigned int Interi senza 0 1 423 segno… 23234 unsigned short int … con meno bit unsigned long int … con più bit 282
  • 283. Specifiche del C = sizeof(char) 1 ≤ < ≤ sizeof(short int) sizeof(int) sizeof(long int) = = = sizeof(unsigned sizeof( sizeof(unsigned short int) unsigned int) long int) ≤ ≤ 283
  • 284. Intervallo di rappresentazione Tipo Min Max char CHAR_MIN CHAR_MAX int INT_MIN INT_MAX short int SHRT_MIN SHRT_MAX long int LONG_MIN LONG_MAX unsigned int 0 UINT_MAX unsigned short int 0 USHRT_MAX unsigned long int 0 ULONG_MAX #include <limits.h> 284
  • 285. Compilatori a 32 bit Tipo N. Bit Min Max char 8 -128 127 int 32 -2147483648 2147483647 short int 16 -32768 32767 long int 32 -2147483648 2147483647 unsigned 32 0 4294967295 int unsigned 16 0 65536 short int unsigned 32 0 4294967295 long int 285
  • 286. I tipi reali in C Tipo Descrizione float Numeri reali in singola precisione double Numeri reali in doppia precisione long double Numeri reali in massima precisione  segno esponente     eeeeee A   1.mmmmm 2     mantissa 286
  • 287. Numero di bit Tipo Dimensione Mantissa Esponente float 32 bit 23 bit 8 bit double 64 bit 53 bit 10 bit long double  double  segno esp o n en te     eeeeee A   1.mmmmm 2     mantissa 287
  • 288. Intervallo di rappresentazione float 0 ±1.17549435E-38 ±3.40282347E+38 double 0 ±2.2250738585072014E-308 ±1.7976931348623157E+308 288
  • 289. Specificatori di formato Tipo scanf printf char %c %c %d int %d %d short int %hd %hd %d long int %ld %ld unsigned int %u %o %x %u %o %x unsigned short int %hu %hu unsigned long int %lu %lu float %f %f %g double %lf %f %g 289
  • 290. Funzioni di conversione char line[80] ; char line[80] ; int x ; float x ; gets(line) ; gets(line) ; x = atoi(line) ; x = atof(line) ; char line[80] ; char line[80] ; long int x ; double x ; gets(line) ; gets(line) ; x = atol(line) ; x = atof(line) ; 290
  • 291. Argomenti sulla linea di comando
  • 292. Il modello “console” Sistema Operativo Finestra di comando Argomenti Codice di uscita Programma utente int main() 292
  • 293. Argomenti sulla linea di comando • In C, è possibile passare informazioni ad un programma specificando degli argomenti sulla linea di comando - Esempio: C:> myprog <arg1> <arg2> ... <argN> • Comuni in molti comandi “interattivi” - Esempio: MS-DOS C:> copy file1.txt dest.txt • Automaticamente memorizzati negli argomenti del main() 293
  • 294. Argomenti del main() • Prototipo: main (int argc, char* argv[]) - argc: Numero di argomenti specificati • Esiste sempre almeno un argomento (il nome del programma) - argv: Vettore di stringhe • argv[0] = primo argomento • argv[i] = generico argomento • argv[argc-1] = ultimo argomento 294
  • 295. Esempi C:progr>quadrato Numero argomenti = 0 Numero argomenti = 1 C:progr>quadrato 5 Argomento 1 = “5” Numero argomenti = 2 C:progr>quadrato 5 K Argomento 1 = “5” Argomento 2 = “K” 295
  • 296. argc e argv • Struttura: - Esempio: c:> prog.exe 3 file.dat 3.2 argv[0] “prog.exe0” argv[1] “30” argv[2] “file.dat0” argc=4 argv[3] “3.20” NULL 296
  • 297. argc e argv (Cont.) • Ciclo per l‟elaborazione degli argomenti for (i=0; i<argc; i++) { /* elabora argv[i] come stringa */ } • NOTA: - Qualunque sia la natura dell‟argomento, è sempre una stringa - Necessario quindi uno strumento per “convertire” in modo efficiente stringhe in tipi numerici 297
  • 298. Conversione degli argomenti • Il C mette a disposizione tre funzioni per la conversione di una stringa in valori numerici int atoi(char *s); long atol(char *s); double atof(char *s); • Esempio: int x = atoi(“2”) ; // x=2 long y = atol(“23L”); // y=23 double z = atof(“2.35e-2”); // z=0.0235 • Definite in stdlib.h 298
  • 299. Conversione degli argomenti (Cont.) • NOTA: Si assume che la stringa rappresenti l‟equivalente di un valore numerico: - cifre, „+‟,‟-‟ per interi - cifre, „+‟,‟-‟,‟l‟,‟L‟ per long - cifre, „+‟,‟-‟,‟e‟,„E‟,‟.‟ per reali • In caso di conversione errata o non possibile le funzioni restituiscono il valore 0 - Necessario in certi casi controllare il valore della conversione! • NOTA: Importante controllare il valore di ogni argv[i]! 299
  • 300. Conversione degli argomenti (Cont.) • Esempio: Programma C che prevede due argomenti sulla linea di comando: - Primo argomento: Un intero - Secondo argomento: Una stringa • Schema: int x; char s[80]; x = atoi(argv[1]); strcpy(s,argv[2]); /* s=argv[2] è errato! */ ... 300
  • 301. Programmi e opzioni • Alcuni argomenti sulla linea di comando indicano tipicamente delle modalità di funzionamento “alternative” di un programma • Queste “opzioni” (dette flag o switch) sono convenzionalmente specificate come -<carattere> per distinguerle dagli argomenti veri e propri • Esempio C:> myprog -x -u file.txt opzioni argomento 301
  • 302. La funzione exit • Esiste inoltre la funzione di libreria exit, dichiarata in <stdlib.h>, che assolve alla stessa funzione - Interrompe l‟esecuzione del programma - Ritorna il valore specificato • Il vantaggio rispetto all‟istruzione return è che può essere usata all‟interno di qualsiasi funzione, non solo del main void exit(int value) ; 302
  • 303. Esercizio 1 • Scrivere un programma che legga sulla linea di comando due interi N e D, e stampi tutti i numeri minori o uguali ad N divisibili per D 303
  • 304. Esercizio 1: Soluzione #include <stdio.h> main(int argc, char* argv[]) { int N, D, i; if (argc != 3) { fprintf(stderr,”Numero argomenti non validon”); return 1; } if (argv[1] != NULL) N = atoi(argv[1]); if (argv[2] != NULL) D = atoi(argv[2]); for (i=1;i<=N;i++) { Altrimenti le operazioni if ((i % D) == 0) { successive operano su printf(”%dn”,i); stringhe = NULL } } } 304
  • 305. Esercizio 2 • Scrivere un programma m2m che legga da input un testo e converta tutte le lettere maiuscole in minuscole e viceversa, a seconda dei flag specificati sulla linea di comando -l, -L conversione in minuscolo -u, -U conversione in maiuscolo Un ulteriore flag -h permette di stampare un help • Utilizzo: m2m –l m2m -L m2m –u m2m -U m2m -h 305
  • 306. Esercizio 2: Soluzione #include <stdio.h> main(int argc, char* argv[]) { int lowercase = 0, uppercase = 0; for (i=1; i<argc; i++) { switch (argv[i][1]) { case „l‟: case „L‟: lowercase = 1; break; case „u‟: case „U‟: uppercase = 1; break; case „h‟: printf(“Uso: m2m [-luh]n”); } } ... } 306
  • 307. Esercizio 3 • Scrivere un frammento di codice che gestisca gli argomenti sulla linea di comando per un programma TEST.EXE il cui comando ha la seguente sintassi: TEST.EXE [-a][-b] <nome file> - I flag –a e –b sono opzionali (e possono essere in un ordine qualunque) - L‟ultimo argomento (<nome file>) è obbligatorio (ed è sempre l‟ultimo) - Esempi validi di invocazione: TEST.EXE <nome file> TEST.EXE –a <nome file> TEST.EXE –b <nome file> TEST.EXE –a -b <nome file> TEST.EXE –b -a <nome file> 307
  • 308. Esercizio 3: Soluzione main(int argc, char* argv[]) { int i, aflag=0, bflag=0; char filename[80]; if (argc >= 2) { /* almeno due argomenti */ /* copiamo in una stringa, verra‟ aperto dopo */ strcpy (filename, argv[argc-1]); /* processiamo gli altri (eventuali argomenti) */ for (i=1; i<= argc-1; i++) { if (argv[i][0] == '-') {/* e‟ un flag */ switch (argv[i][1]) { case 'a': aflag = 1; break; case 'b': bflag = 1; break; default: fprintf(stderr,"Opzione non corretta.n"); } } 308
  • 309. Esercizio 3: Soluzione (Cont.) } else { /* Non e‟ un flag. Esce dal programma */ fprintf(stderr,"Errore di sintassi.n"); return; } } } else { /* sintassi errata. Esce dal programma */ fprintf(stderr,"Errore di sintassi.n"); return; } } 309
  • 310. Settimana n.10 Obiettivi Contenuti • Strutture • Struct. Operatore “.” • Vettori di strutture • Definizione vettori di struct • Definizione di struct contenenti vettori (es. stringhe) 310
  • 312. Tipi aggregati • In C, è possibile definire dati composti da elementi eterogenei (detti record), aggregandoli in una singola variabile - Individuata dalla keyword struct • Sintassi (definizione di tipo): struct <identificatore> { campi }; I campi sono nel formato: <tipo> <nome campo>; 312
  • 313. Aggregato di dati eterogenei • Più informazioni eterogenee possono essere unite come parti (campi) di uno stesso dato dato (aggregato) studente cognome: Rossi nome: Mario matricola: 123456 media: 27.25 313
  • 314. struct • Una definizione di struct equivale ad una definizione di tipo • Successivamente, una struttura può essere usata come un tipo per dichiarare variabili • Esempio: struct complex { double re; double im; } ... struct complex num1, num2; 314
  • 315. struct: Esempi struct complex { double re; double im; } struct identity { char nome[30]; char cognome[30]; char codicefiscale[15]; int altezza; char statocivile; } 315
  • 316. Accesso ai campi di una struct • Una struttura permette di accedere ai singoli campi tramite l‟operatore „.‟, applicato a variabili del corrispondente tipo struct <variabile>.<campo> • Esempio: struct complex { double re; double im; } ... struct complex num1, num2; num1.re = 0.33; num1.im = -0.43943; num2.re = -0.133; num2.im = -0.49; 316
  • 317. Definizione di struct come tipo • E‟ possibile definire un nuovo tipo a partire da una struct tramite la direttiva typedef - Passabile come parametro - Indicizzabile in vettori • Sintassi: typedef <tipo> <nome nuovo tipo>; • Esempio: typedef struct complex { double re; double im; compl z1,z2; } compl; 317
  • 318. Definizione di struct come tipo (Cont.) • Passaggio di struct come argomenti int f1 (compl z1, compl z2) • struct come risultato di funzioni compl f2(.....) • Vettore di struct compl lista[10]; • Nota: La direttiva typedef è applicabile anche non alle strutture per definire nuovi tipi - Esempio: typedef unsigned char BIT8; 318
  • 319. Operazioni su struct • Confronto: - Non è possibile confrontare due variabili dello stesso tipo di struct usando il loro nome • Esempio: compl s1, s2  s1==s2 o s1!=s2 è un errore di sintassi - Il confronto deve avvenire confrontando i campi uno ad uno • Esempio: compl s1, s2 (s1.re == s2.re) && (s1.im == s2.im) • Inizializzazione: - Come per i vettori, tramite una lista di valori tra {} • Esempio: compl s1 = {0.1213, 2.655}; - L‟associazione è posizionale: In caso di valori mancanti, questi vengono inizializzati a: • 0, per valori “numerici” • NULL per puntatori 319
  • 320. Esercizio 1 • Data la seguente struct: struct stud { char nome[40]; unsigned int matricola; unsigned int voto; } - Si definisca un corrispondente tipo studente - Si scriva un main() che allochi un vettore di 10 elementi e che invochi la funzione descritta di seguito - Si scriva una funzione ContaInsufficienti() che riceva come argomento il vettore sopracitato e ritorni il numero di studenti che sono insufficienti 320
  • 321. Esercizio 1: Soluzione #include <stdio.h> #define NSTUD 10 typedef struct stud { char nome[40]; unsigned int matricola; unsigned int voto; }studente; int ContaInsufficienti(studente vett[], int dim); /* prototipo */ 321
  • 322. Esercizio 1: Soluzione (Cont.) main() { int i, NumIns; studente Lista[NSTUD]; /* assumiamo che il programma riempia con valori opportuni la lista */ NumIns = ContaInsufficienti(Lista, NSTUD); printf("Il numero di insufficienti e': %d.n", NumIns); } int ContaInsufficienti(studente s[], int numstud) { int i, n=0; for (i=0; i<numstud; i++) { if (s[i].voto < 18) n++; } return n; } 322
  • 323. Esercizio 2 • Data una struct che rappresenta un punto nel piano cartesiano a due dimensioni: struct point { double x; double y; }; ed il relativo tipo typedef struct point Point; scrivere le seguenti funzioni che operano su oggetti di tipo Point: - double DistanzaDaOrigine (Point p); - double Distanza (Point p1, Point p2); - int Quadrante (Point p); /* in quale quadrante */ - int Allineati(Point p1, Point p2, Point p3); /* se sono allineati */ - int Insterseca(Point p1, Point p2); /* se il segmento che ha per estremi p1 e p2 interseca un qualunque asse*/ 323
  • 324. Esercizio 2: Soluzione double DistanzaDaOrigine (Point p) { return sqrt(p.x*p.x + p.y*p.y); } double Distanza (Point p1, Point p2) { return sqrt((p1.x-p2.x)*(p1.x-p2.x) + (p1.y-p2.y)*(p1.y-p2.y)); } int Quadrante (Point p) { if (p.x >= 0 && p.y >= 0) return 1; if (p.x <= 0 && p.y >= 0) return 2; if (p.x <= 0 && p.y <= 0) return 3; if (p.x >= 0 && p.y <= 0) return 4; } 324
  • 325. Esercizio 2: Soluzione (Cont.) int Allineati (Point p1, Point p2, Point p3) { double r1, r2; /* verifichiamo che il rapporto tra y e x delle due coppie di punti sia identico */ r1 = (p2.y-p1.y)/(p2.x-p1.x); r2 = (p3.y-p2.y)/(p3.x-p2.x); if (r1 == r2) return 1; else return 0; } int Interseca(Point p1, Point p2) { /* verifichiamo se sono in quadranti diversi */ if (Quadrante(p1) == Quadrante(p2)) return 0; else return 1; } 325
  • 326. Settimana n.11 Obiettivi Contenuti • File di testo • Concetto di file e funzioni • Input/output robusto fopen/fclose • Funzioni fgets+sscanf • Approfondimenti su scanf (inclusi tutti i tipi scalari) • La funzione sscanf e lettura “robusta” da file • Elaborazione di file “on the fly” (senza acquisirli in memoria) 326
  • 327. Rango delle espressioni aritmetiche • In C, è possibile lavorare con operandi non dello stesso tipo • Le operazioni aritmetiche avvengono dopo aver promosso tutti gli operandi al tipo di rango più alto: _Bool char short unsigned short int unsigned int long unsigned long long long unsigned long long float double long double 327
  • 328. Operatori di cast • In alcuni casi, può essere necessario convertire esplicitamente un‟espressione in uno specifico tipo - Quando le regole di conversione automatica non si applicano - Esempio: int i; double d; l‟assegnazione i = d; fa perdere informazione • Sintassi: „(‟ <tipo> „)‟ <espressione>; - Significato: Forza <espressione> ad essere interpretata come se fosse di tipo <tipo> • Esempio: ... double f; f = (double) 10; 328
  • 329. Operatori di cast: Esempio #include <stdio.h> main() { int a, b; printf(“Dammi un numero intero (A): ”); scanf(“%d”,&a); printf(“Dammi un numero intero (B): ”); scanf(“%d”,&b); if(b==0) printf(“Errore: divisione per zero!!n”); else printf(“A / B = %fn”, ((float)a)/b); } 329
  • 330. Files
  • 331. Vista d‟insieme dei formati di file File File binario File ASCII Formato Formato Testo Testo Linguaggio “proprietario” “standard” puro formattato formale .doc .pdf .txt .html .c .psd .zip .csv .xml .xls .jpeg .rtf .java 331
  • 332. File sequenziali • Il modo più comune per realizzare I/O da file consiste nell‟utilizzo del cosiddetto accesso bufferizzato - Informazioni prelevate dal file attraverso una memoria interna al sistema (detta buffer) • Vantaggi: - Livello di astrazione più elevato - Possibilità di I/O formattato • I/O non bufferizzato: - Accesso diretto a livello binario un carattere per volta 332
  • 333. File sequenziali (Cont.) • Il C vede i file come un flusso (stream) sequenziale di byte - Nessuna struttura particolare: La strutturazione del contenuto è a carico del programmatore - Carattere terminatore alla fine del file: EOF Byte 0 1 2 …. N-1 … EOF • NOTA: L‟accesso sequenziale implica l‟impossibilità di: - Leggere all‟indietro - Saltare ad uno specifico punto del file 333
  • 334. File sequenziali (Cont.) • Accesso tramite una variabile di tipo FILE* • Definita in stdio.h • Dichiarazione: FILE* <file>; FILE* contiene un insieme di variabili che permettono l‟accesso per “tipi” • Al momento dell‟attivazione di un programma vengono automaticamente attivati tre file: - stdin - stdout - stderr 334
  • 335. File sequenziali (Cont.) • La struttura dati FILE contiene vari campi: - short level; /* Fill/empty level of buffer */ - unsigned flags; /* File status flags */ - char fd; /* File descriptor */ - unsigned char hold; /* Ungetc char if no buffer */ - short bsize; /* Buffer size */ - unsigned char *buffer; /* Data transfer buffer */ - unsigned char *curp; /* Current active pointer */ - unsigned istemp; /* Temporary file indicator */ - short token; /* Used for validity checking */ 335
  • 336. File sequenziali (Cont.) • stdin è automaticamente associato allo standard input (tastiera) • stdout e stderr sono automaticamente associati allo standard output (video) • stdin,stdout,stderr sono direttamente utilizzabili nelle istruzioni per l‟accesso a file - In altre parole, sono delle variabili predefinite di tipo FILE* 336
  • 337. File: Operazioni • L‟uso di un file passa attraverso tre fasi fondamentali - Apertura del file - Accesso al file - Chiusura del file • Prima di aprire un file occorre dichiararlo! 337
  • 338. Stati di un file Directory Apertura del file Stream Nome file Posizione attuale Lettura / Scrittura Testo / Binario File aperto File chiuso Risiede su disco, Risiede su disco, il programma ha il programma non accesso al suo ha accesso al suo contenuto contenuto attraverso lo stream associato Chiusura del file 338
  • 339. Apertura di un file • Per accedere ad un file è necessario aprirlo: - Apertura: Connessione di un file fisico (su disco) ad un file logico (interno al programma) • Funzione: FILE* fopen(char* <nomefile>, char* <modo>); <nomefile>: Nome del file fisico 339
  • 340. Apertura di un file (Cont.) - <modo>: Tipo di accesso al file • “r”: sola lettura • “w”: sola scrittura (cancella il file se esiste) • “a”: append (aggiunge in coda ad un file) • “r+”: lettura/scrittura su file esistente • “w+”: lettura/scrittura su nuovo file • “a+”: lettura/scrittura in coda o su nuovo file - Ritorna: • Il puntatore al file in caso di successo • NULL in caso di errore 340
  • 341. Chiusura di un file • Quando l‟utilizzo del file fisico è terminato, è consigliabile chiudere il file: - Chiusura: Cancellazione della connessione di un file fisico (su disco) ad un file logico (interno al programma) • Funzione: int fclose(FILE* <file>); <file>: File aperto in precedenza con fopen() - Ritorna: • 0 se l‟operazione si chiude correttamente • EOF in caso di errore 341
  • 342. Apertura e chiusura di un file: Esempio FILE *fp; /* variabile di tipo file */ ... /* apro file „testo.dat‟ in lettura * fp = fopen(“testo.dat”,“r”); if (fp == NULL) printf(“Errore nell‟aperturan”); else { /* qui posso accedere a „testo.dat‟ usando fp */ } ... fclose(fp); 342
  • 343. Lettura di un file Apertura del file Leggi riga / Leggi carattere File aperto in File aperto in lettura lettura Posizione iniziale Posizione intermedia (primo carattere) (n-esimo carattere) File aperto in Condizione end-of-file lettura Leggi riga / Posizione finale Leggi carattere Chiusura del file (ultimo carattere) 343
  • 344. Scrittura di un file Apertura del file Scrivi riga / Scrivi carattere File aperto in Scrivi riga / Scrivi carattere scrittura Posizione iniziale (primo carattere) File aperto in scrittura La posizione intermedia Posizione intermedia diviene posizione finale (n-esimo carattere) Chiusura del file 344
  • 345. Aggiunta ad un file Apertura del file Scrivi riga / Scrivi carattere File aperto in Scrivi riga / Scrivi carattere aggiunta Posizione finale File aperto in (ultimo carattere) aggiunta Posizione intermedia La posizione intermedia (n-esimo carattere diviene posizione finale dopo l‟ultimo) Chiusura del file 345
  • 346. Lettura a caratteri • Lettura: - int getc (FILE* <file>); - int fgetc (FILE* <file>); • Legge un carattere alla volta dal file • Restituisce il carattere letto o EOF in caso di fine file o errore • NOTA: getchar() equivale a getc(stdin) 346
  • 347. Scrittura a caratteri • Scrittura: - int putc (int c, FILE* <file>); - int fputc (int c, FILE* <file>); • Scrive un carattere alla volta nel file • Restituisce il carattere scritto o EOF in caso di errore • NOTA: putchar(…) equivale a putc(…,stdout) 347
  • 348. Lettura a righe • Lettura: char* fgets(char* <s>,int <n>,FILE* <file>); - Legge una stringa dal file fermandosi al più dopo n-1 caratteri - L‟eventuale „n‟ NON viene eliminato (diverso da gets !) - Restituisce il puntatore alla stringa letta o NULL in caso di fine file o errore • NOTA: gets(…) “equivale” a fgets(…,stdin) 348
  • 349. Scrittura a righe • Scrittura: int fputs(char* <s>, FILE* <file>); - Scrive la stringa <s> nel senza aggiungere „n‟ (diverso da puts !) - Restituisce l‟ultimo carattere scritto, oppure EOF in caso di errore • NOTA: puts(…) “equivale” a fputs(…,stdout) 349
  • 350. Lettura formattata • Lettura: int fscanf(FILE* <file>,char* <formato>,...); - Come scanf(), con un parametro addizionale che rappresenta un file - Restituisce il numero di campi convertiti, oppure EOF in caso di fine file • NOTA: scanf(…) “equivale” a fscanf(stdin,…) 350
  • 351. Scrittura formattata • Scrittura: int fprintf(FILE* <file>,char* <formato>,...); - Come printf(), con un parametro addizionale che rappresenta un file - Restituisce il numero di byte scritti, oppure EOF in caso di errore • NOTA: printf(…) “equivale” a fprintf(stdout,…) 351
  • 352. Altre funzioni • FILE* freopen(char* <nomefile>,char* <modo>); - Come fopen, ma si applica ad un file già esistente - Restituisce il puntatore al file oppure NULL • int fflush(FILE* <file>); - “Cancella” il contenuto di un file - Restituisce 0 se termina correttamente oppure EOF • int feof(FILE* <file>); - Restituisce falso (0) se il puntatore NON è posizionato alla fine del file - Restituisce vero (!0) se il puntatore è posizionato alla fine del file 352
  • 353. Posizionamento in un file • Ad ogni file è associato un buffer ed un “puntatore” all‟interno di questo buffer • La posizione del puntatore può essere manipolata con alcune funzioni • Più utile: void rewind (FILE* <file>) - Posiziona il puntatore all‟inizio del file - Utile per “ripartire” dall‟inizio nella scansione di un file 353
  • 354. Schema generale di lettura da file leggi un dato dal file; finchè (non è finito il file) { elabora il dato; leggi un dato dal file; } • La condizione “non è finito il file” può essere realizzata in vari modi: - Usando i valori restituiti dalle funzioni di input (consigliato) - Usando la funzione feof() 354
  • 355. Esempio 1 • Lettura di un file formattato (esempio: Un intero per riga) - Uso dei valori restituiti dalle funzioni di input (fscanf) res = fscanf (fp, “%d”, &val); while (res != EOF) { elabora val; res = fscanf (fp, “%d”, &val); } 355
  • 356. Esempio 1 (Cont.) • Versione “compatta” senza memorizzare il risultato di fscanf() - Usiamo fscanf() direttamente nella condizione di fine input while (fscanf (fp,“%d”,&val) != EOF) { elabora val; } 356
  • 357. Esempio 2 • Lettura di un file formattato (esempio: Un intero per riga) - Uso di feof() fscanf (fp, “%d”, &val); while (!feof(fp)) { elabora val; fscanf (fp, “%d”, &val); } 357
  • 358. Esempio 3 • Lettura di un file non formattato - Uso dei valori restituiti dalle funzioni di input (getc) c = getc(fp); while (c != EOF) { elabora c; Versione 1 c = getc(fp); } while ((c=getc(fp))!= EOF) { elabora c; Versione 2 } 358
  • 359. Esempio 4 • Lettura di un file non formattato - Uso dei valori restituiti dalle funzioni di input (fgets) s = fgets(s,80,fp); while (s != NULL) { Versione 1 elabora s; s = fgets(s,80,fp); } while ((s = fgets(s,80,fp))!= NULL) { elabora s; Versione 2 } 359
  • 360. Esercizio • Leggere un file “estremi.dat” contenente coppie di numeri interi (x,y), una per riga e scrivere un secondo file “diff.dat” che contenga le differenze x-y, una per riga • Esempio: File 1 File 2 23 32 -9 2 11 -9 19 6 13 23 5 18 3 2 1 … … … 360
  • 361. Esercizio: Soluzione #include <stdio.h> main() { FILE *fpin, *fpout; int x,y; /* apertura del primo file */ if ((fpin = fopen(“estremi.dat”,”r”)) == NULL) { fprintf(stderr,”Errore nell‟aperturan”); return 1; } 361
  • 362. Esercizio: Soluzione (Cont.) /* apertura del secondo file */ if ((fpout = fopen(“diff.dat”,”w”)) == NULL) { fprintf(stderr,”Errore nell‟aperturan”); return 1; } /* input */ while (fscanf(fpin,”%d %d”,&x,&y) != EOF) { /* ora ho a disposizione x e y */ fprintf(fpout,”%dn”,x-y); } fclose (fpin); fclose (fpout); } 362
  • 363. Avvertenza • In generale, è errato tentare di memorizzare il contenuto di un file in un vettore - La dimensione (numero di righe o di dati) di un file non è quasi mai nota a priori - Se la dimensione è nota, tipicamente è molto grande! 363
  • 364. Formattazione dell‟output • L‟output (su schermo o su file) viene formattato solitamente mediante la funzione printf (o fprintf) • Ogni dato viene stampato attraverso un opportuno specificatore di formato (codici %) • Ciascuno di questi codici dispone di ulteriori opzioni per meglio controllare la formattazione - Stampa incolonnata - Numero di cifre decimali - Spazi di riempimento - ... 364
  • 365. Specificatori di formato Tipo printf char %c %d int %d short int %hd %d long int %ld unsigned int %u %o %x unsigned short int %hu unsigned long int %lu float %f %e %g double %f %e %g char [] %s 365
  • 366. Forma completa degli specificatori (1) - precision + . width * % format # * 0 366
  • 367. Forma completa degli specificatori (2) - precision + . width * % format # * 0 Specificatore di % obbligatorio formato Modificatori obbligatorio opzionali 367
  • 368. Forma completa degli specificatori (3) - precision + . width * % format # * 0 Specificatori già noti 368
  • 369. Forma completa degli specificatori (4) - precision + . width * % format # * 0 Lunghezza totale: numero minimo di caratteri stampati 369
  • 370. Esempi Istruzione Risultato printf("%d", 13) ; 13 printf("%1d", 13) ; 13 printf("%3d", 13) ; ␣13 printf("%f", 13.14) ; 13.140000 printf("%6f", 13.14) ; 13.140000 printf("%12f", 13.14) ; ␣␣␣13.140000 printf("%6s", "ciao") ; ␣␣ciao 370
  • 371. Forma completa degli specificatori - precision + . width * % format # * Minimo numero di caratteri %d totali (eventualmente 0 aggiunge 0 a sinistra) Numero massimo di cifre Precisione %f dopo la virgola (dipende...) Massimo numero di caratteri %s (stringhe più lunghe vengono troncate) 371
  • 372. Esempi (1/2) Istruzione Risultato printf("%.1d", 13) ; 13 printf("%.4d", 13) ; 0013 printf("%6.4d", 13) ; ␣␣0013 printf("%4.6d", 13) ; 000013 printf("%.2s", "ciao") ; ci printf("%.6s", "ciao") ; ciao printf("%6.3s", "ciao") ; ␣␣␣cia 372
  • 373. Esempi (2/2) Istruzione Risultato printf("%.2f", 13.14) ; 13.14 printf("%.4f", 13.14) ; 13.1400 printf("%6.4f", 13.14) ; 13.1400 printf("%9.4f", 13.14) ; ␣␣13.1400 373
  • 374. Forma completa degli specificatori - precision + . width * % format # * - Allinea a sinistra anziché a destra Aggiungi il segno anche davanti ai 0 + numeri positivi Aggiungi spazio davanti ai numeri _ positivi Riempimento e 0 Aggiungi 0 iniziali fino a width allineamento # Formato alternativo (dipende...) 374
  • 375. Esempi (1/2) Istruzione Risultato printf("%6d", 13) ; ␣␣␣␣13 printf("%-6d", 13) ; 13␣␣␣␣ printf("%06d", 13) ; 000013 printf("%6s", "ciao") ; ␣␣ciao printf("%-6s", "ciao") ; ciao␣␣ 375
  • 376. Esempi (2/2) Istruzione Risultato printf("%d", 13) ; 13 printf("%d", -13) ; -13 printf("%+d", 13) ; +13 printf("%+d", -13) ; -13 printf("% d", 13) ; ␣13 printf("% d", -13) ; -13 376
  • 377. Approfondimenti su scanf • Tipologie di caratteri nella stringa di formato • Modificatori degli specificatori di formato • Valore di ritorno • Specificatore %[] 377
  • 378. Stringa di formato (1/2) • Caratteri stampabili: - scanf si aspetta che tali caratteri compaiano esattamente nell‟input - Se no, interrompe la lettura • Spaziatura (“whitespace”): - Spazio, tab, a capo - scanf “salta” ogni (eventuale) sequenza di caratteri di spaziatura - Si ferma al primo carattere non di spaziatura (o End-of-File) 378
  • 379. Stringa di formato (2/2) • Specificatori di formato (%-codice): - Se il codice non è %c, innanzitutto scanf “salta” ogni eventuale sequenza di caratteri di spaziatura - scanf legge i caratteri successivi e cerca di convertirli secondo il formato specificato - La lettura si interrompe al primo carattere che non può essere interpretato come parte del campo 379
  • 380. Specificatori di formato Tipo scanf char %c int %d short int %hd long int %ld unsigned int %u %o %x unsigned short int %hu unsigned long int %lu float %f double %lf char [] %s %[...] 380
  • 381. Forma completa degli specificatori * width % format Specificatore di % obbligatorio Modificatori formato opzionali obbligatorio 381
  • 382. Forma completa degli specificatori * width % format Specificatori già noti % obbligatorio 382
  • 383. Forma completa degli specificatori * width % format Numero massimo di caratteri letti per questa conversione 383
  • 384. Esempi Istruzione Input Risultato scanf("%d", &x) ; 134xyz x = 134 scanf("%2d", &x) ; 134xyz x = 13 scanf("%s", v) ; 134xyz v = "134xyz" scanf("%2s", v) ; 134xyz v = "13" 384
  • 385. Forma completa degli specificatori * width % format Leggi questo campo, ma non memorizzarlo in alcuna variabile 385
  • 386. Esempi Istruzione Input Risultato scanf("%d %s", &x, v) ; 10 Pippo x = 10 v = "Pippo" scanf("%s", v) ; 10 Pippo x immutato v = "10" scanf("%*d %s", v) ; 10 Pippo x immutato v = "Pippo" 386
  • 387. Valore di ritorno • La funzione scanf ritorna un valore intero: - Numero di elementi (%) effettivamente letti • Non conta quelli “saltati” con %* • Non conta quelli non letti perché l‟input non conteneva i caratteri desiderati • Non conta quelli non letti perché l‟input è finito troppo presto - End-of-File per fscanf - Fine stringa per sscanf - EOF se l‟input era già in condizione End-of-File all‟inizio della lettura 387
  • 388. Lettura di stringhe • La lettura di stringhe avviene solitamente con lo specificatore di formato %s - Salta tutti i caratteri di spaziatura - Acquisisci tutti i caratteri seguenti, fermandosi al primo carattere di spaziatura (senza leggerlo) • Qualora l‟input dei separatori diversi da spazio, è possibile istruire scanf su quali siano i caratteri leciti, mediante lo specificatore %[pattern] 388
  • 389. Struttura di un pattern ^ - carattere % [ carattere ] 389
  • 390. Esempi Pattern Effetto %[r] Legge solo sequenze di 'r' %[abcABC] Legge sequenze composte da a, b, c, A, B, C, in qualsiasi ordine e di qualsiasi lunghezza %[a-cA-C] Idem come sopra %[a-zA-Z] Sequenze di lettere alfabetiche %[0-9] Sequenze di cifre numeriche %[a-zA-Z0-9] Sequenze alfanumeriche %[^x] Qualunque sequenza che non contiene 'x' %[^n] Legge fino a file riga %[^,;.!? ] Si ferma alla punteggiatura o spazio 390
  • 391. Settimana n.12 Obiettivi Contenuti • Uso più avanzato dei File • Elaborazione di file acquisendone il contenuto in una serie di vettori paralleli o in un vettore di struct • Lettura/scrittura di più file aperti contemporaneamente • Programmi che operano come “filtri” su file • Cenno alla allocazione dinamica di un vettore 391
  • 392. Allocazione dinamica della memoria
  • 393. Allocazione statica • Il C permette di allocare esclusivamente variabili in un numero predefinito in fase di definizione (allocazione statica della memoria): - Variabili scalari: Una variabile alla volta - Vettori: N variabili alla volta (con N valore costante) 393
  • 394. Allocazione statica: Esempio #define MAX 1000 vett è dimensionato in eccesso, in modo da soddisfare in ogni caso le struct scheda { esigenze del programma, anche se int codice; questo usa un numero minore di elementi. Quindi in ogni caso vett char nome[20]; sarà composto da 1000 elementi da char cognome[20]; 42 byte ciascuno, occupando cioè 42.000 byte }; struct scheda vett[MAX]; 394
  • 395. Memoria dinamica • Questa limitazione può essere superata allocando esplicitamente la memoria (allocazione dinamica della memoria): - Su richiesta: • Il programma è in grado di determinare, ogni volta che è lanciato, di quanta memoria ha bisogno - Per quantità definite al tempo di esecuzione: • Il programma usa ad ogni istante soltanto la memoria di cui ha bisogno, provvedendo periodicamente ad allocare la quantità di memoria da usare e a liberare (deallocare) quella non più utilizzata • In tal modo si permette ad eventuali altri processi che lavorano in parallelo sullo stesso sistema di meglio utilizzare la memoria disponibile 395
  • 396. Memoria dinamica (Cont.) • L‟allocazione dinamica assegna memoria ad una variabile in un‟area apposita, fisicamente separata da quella in cui vengono posizionate le variabili dichiarate staticamente • Concettualmente: - Mappa di memoria di Istruzioni e dati un programma allocati staticamente Memoria Dati allocati Memoria dinamicamente dinamica 396
  • 397. Memoria dinamica: malloc • La memoria viene allocata dinamicamente tramite la funzione malloc() • Sintassi: void* malloc(<dimensione>) <dimensione>: Numero (intero) di byte da allocare - Valore di ritorno: Puntatore a cui viene assegnata la memoria allocata • In caso di errore (esempio, memoria non disponibile), ritorna NULL • NOTA: Dato che viene ritornato un puntatore void*, è obbligatorio forzare il risultato al tipo del puntatore desiderato 397
  • 398. Memoria dinamica: malloc (Cont.) • Esempio: char *p; p = (char*)malloc(10); // Alloca 10 caratteri a p • L‟allocazione dinamica permette di superare la limitazione del caso statico • Esempio: int n; char p[n]; // Errore!! int n; char *p = (char*) malloc (n); // OK!!! 398
  • 399. malloc: Esempio int *punt; Richiede l‟allocazione di una int n; zona di memoria di n byte. … punt = (int *)malloc(n); Trasforma il puntatore generico if (punt == NULL) ritornato da malloc in un puntatore a int. { printf (“Errore di allocazionen”); exit(); } Verifica che l‟allocazione sia avvenuta regolarmente. … 399
  • 400. Settimana n.13 Obiettivi Contenuti • Preparazione all‟esame • Svolgimento temi d‟esame 400
  • 401. Settimana n.14 Obiettivi Contenuti • Preparazione all‟esame • Svolgimento temi d‟esame 401