Lezione VII                        FRAMES     NOFRAMES

 

Concetti di programmazione

 

Iniziamo la lezione introducendo la  struttura  generale di un programma in  linguaggio C :

 

< istruzioni per il preprocessore >

[ < definizione delle funzioni > ]

< dichiarazione di tipi e variabili >

main ()

 {

    < dichiarazione di tipi e variabili >

    [ < chiamata delle funzioni > ]

    < istruzioni direttamente eseguibili >

}

 

dove  main ()  e’ la funzione principale, ossia la funzione che deve essere sempre

 presente in un programma C e che viene eseguita sempre per prima . Le istruzioni direttamente eseguibili sono una lista di istruzioni (che verranno tradotte nel programma 

in LM ). Sugli altri concetti di preprocessore, di funzione si tornera’ piu’ in la' nel corso.

 

Il C ammette:

 

*   dichiarazioni per associare  locazioni  di memoria centrale ( indirizzi ) disponibili 

con  nomi ;

 

*   istruzioni  di lettura da Tastiera ( UL = Tastiera ) , scrittura sul video ( US = Video ), somma  del contenuto di due locazioni in MC (memoria centrale) ed inserendo il risultato

in una terza locazione.

 

Problema

Dati due numeri , calcolare e stampare la somma fra essi.

Analisi

Sicuramente abbiamo bisogno di due locazioni di memoria , una per il  primo  numero 

e l’ altra per il  secondo  numero; inoltre ci servira’ una locazione per memorizzare la  somma  fra i due numeri.

Sintesi

Come si puo’  intuire associamo la locazione :

per il primo numero al simbolo      primo

per il secondo numero al simbolo  secondo

per il numero somma al simbolo    somma

Algoritmo

1)    leggere un numero da input  e memorizzarlo nella cella di memoria associata al 

simbolo primo

2)    leggere un numero da input  e memorizzarlo nella cella  di memoria associata al 

simbolo secondo

3)    eseguire la addizione fra primo e secondo 
somma < -----  primo + secondo
mettere il risultato nella cella di memoria associata al simbolo  somma

4)    stampare somma.

L’ algoritmo presentato non puo’ essere tradotto in linguaggio macchina per 2 diversi 

motivi

a)    perche’ non abbiamo deciso gli indirizzi IND

b)    perche’ il passo 3) dell'algoritmo non e’ esprimibile con una istruzione macchina.

 

Trascurando l’operazione di addizione SUM il programma in LM corrispondente, una 

volta decisi gli indirizzi e’ :

associazione indirizzi ai simboli

primo         < --- >  IND1  =  01010

secondo     < --- >  IND2  =  01011

somma      < --- >   IND3  =  01100

 

Programma in linguaggio macchina

 

Read  da input in 01010

Read  da input in 01011

Load  da 01010 in R1

Load  da 01011 in R2

SUM

Store  R1 in 01100

Print  in output 01100

 

Il compilatore il linker ed il loader si occupano della traduzione di un programma da un linguaggio ad alto livello come puo’ essere il C nel corrispondente programma in 

linguaggio macchina in MC pronto per l’ esecuzione.

 

L’esecuzione di un programma coincide con l‘esecuzione di una sequenza di istruzioni (flusso di esecuzione).

Per descrivere l’algoritmo come sequenza di passi si usano delle forme grafiche in cui 

il flusso di esecuzione e’ rappresentato dal simbolo freccia ---- > .

 

Introduciamo delle convenzioni grafiche per esprimere un programma in termini del suo flusso di esecuzione ( programma espresso attraverso i diagrammi di flusso ):

 

 

 

 Fig. 7.1  

 

 

 

Forma grafica per descrivere il programma , di somma fra due numeri,  in termini del 

suo flusso di esecuzione che va dall’alto verso il basso conosciuto meglio come 

diagramma di flusso :

Fig. 7.2

 

 

 


 

Consideriamo il seguente diagramma in Fig. 7.3 che esprime, in forma grafica,  un programma che :

Legge D

Incrementa D di uno

Stampa D  ( il nuovo valore di D )

 poi ripete

Legge D

Incrementa D

Stampa D

e cosi’ via fino all’infinito

 

Fig 7.3

 

 

Seguendo il flusso , nel tratto di destra in rosso, avremo che:

Legge D

Ripete all’ infinito

Incrementa D

Stampa D

In entrambi i casi i   programmi sono NON TERMINANTI

Esempio di comportamento del programma percorrendo il flusso di sinistra :

 

Tab.  7.1

Input

7

4

3

.

Output

8

5

4

.

 

Esempio di comportamento del programma quando si percorre il flusso di destra :

 

Tab. 7.2

Input

7

 

 

 

Output

8

9

10

.

 

Il flusso di esecuzione puo’  essere deviato per seguire strade alternative. Questo viene realizzato con un TEST , il quale coincide con la verifica di una condizione logica, che

puo’ valere SI oppure NO. Se la CONDIZIONE e’ vera ( SI ) il flusso di esecuzione 

prosegue in una direzione altrimenti, nel caso in cui la condizione vale  falso ( NO ) 

si prosegue nell’altra direzione. 

Indichiamo per brevita’ la CONDIZIONE LOGICA con COND.

 

Fig. 7.4

 

 

 

 

 

 

 

 

 

 


                     

 

 

 

Progettiamo adesso un programma,  con i diagrammi di flusso ,che dati due numeri 

interi stampi il maggiore fra i due. Nel TEST indichiamo il simbolo PRIMO con PR. ed il simbolo SECONDO con SEC.  .

 

Fig. 7.5

 

 

                                                           

Il diagramma e’ abbastanza esplicativo del programma che in italiano potremmo cosi’ tradurre:

     1)   AVVIO

     2)   Lettura del  PRIMO numero

     3)   Lettura del SECONDO numero

     4)  Se il PRIMO numero e’ minore del SECONDO numero allora:

     5)   Stampa SECONDO numero

     6)   Altrimenti Stampa PRIMO numero

     7)     FINE

Questo programma sia che lo esprimiamo come diagramma che come algoritmo e’ traducibile in qualsiasi linguaggio di programmazione. 

Ad esempio in linguaggio Pascal avremo il seguente programma  (traducibile automaticamente in un programma eseguibile maggiore.exe; notate che e’ anche 

automatica la scelta degli indirizzi) :

 

program  maggiore;

var  PRIMO, SECONDO;

  begin

     read ( PRIMO );

     read ( SECONDO );

     if ( PRIMO < SECONDO )

       then

       write ( SECONDO )

       else

       write ( PRIMO );

  end  ;

end.

 

Nel linguaggio C lo stesso programma potremmo cosi’ tradurre, anticipando che l’istruzione    if - then - else del Pascal diventa

if - else in C, che ha la seguente sintassi:

if (< espressione> )<istruzione1> else <istruzione2> .

Ossia se risulta vera l’espressione fra parentesi tonde “ CONDIZIONE LOGICA VERA” 

allora viene eseguita l’istruzione1 altrimenti “ CONDIZIONE LOGICA FALSA”, viene 

eseguita l’istruzione2. Inoltre l’ istruzione di lettura nel C e’ scanf(…) e l’istruzione di 

stampa e’ printf(..) ; o meglio scanf(..) e printf(..) sono delle funzioni di libreria del C 

( contenute nel file stdio.h  “ standard di input output ” ) che usiamo come se fossero 

delle semplici istruzioni.

 

#<include stdio.h>

void main(void)

 {

  int  PRIMO, SECONDO;

  scanf (“\n%d”,&PRIMO);

  scanf (“\n%d”,&SECONDO);

   if ( PRIMO<SECONDO)

   printf (“\n %d”, SECONDO);

   else

   printf (“\n %d”, PRIMO);

 } 

 

Traduzione in linguaggio macchina LM del programma rappresentato in Fig. 7.5

 

Supponiamo di avere come istruzione di salto condizionato una JUMP tale che:

Salta in A se R1 < 0  ( con codice operativo 1111 ) ;

 

traduciamo il programma in codice simbolico e poi in LM vero e proprio (solo zeri e uni);

 

associamo ai simboli PRIMO l’indirizzo IND1 e SECONDO l’indirizzo IND2

PRIMO < ---- > IND1 ;  SECONDO < ----- > IND2 ; 

introduciamo due etichette ETIC1 ed ETIC2  per contrassegnare due righe di codice

del programma ( gli indirizzi di memoria ).

 

programma in LM simbolico :

 

              Read  da I in IND1

              Read  da I in IND2

              Load  da IND1 in R1

              Load  da IND2 in R2

              Sub    ( una istruzione che dovrebbe eseguire la R1 < --- R1 - R2 )

              Salta  in ETIC1 ( se R1 < 0 )

              Write  IND1

              Salta  in  ETIC2  ( incondizionatamente )

ETIC1:  Write  IND2

ETIC2:  STOP

 

In sostanza se R1 < 0  l’esecuzione del programma prosegue dall’indirizzo di memoria avente etichetta  ETIC1 ( stampa del contenuto di IND2 ) altrimenti prosegue con la 

istruzione successiva ossia viene stampato nel nostro caso  il contenuto di IND1 e

 poi si salta in ETIC2 dove ci si ferma  .

 

Adesso associando a  IND1 il valore 11001  e  ad   IND2 il valore 11010  

introducendo il codice operativo della istruzione  Sub  che e’ pari a   0101 

conoscendo quello dell’istruzione di   Salta  in ETIC1 ( se R1 < 0 ) che e’ pari a  1111 

e supponendo che il programma sia caricato in memoria all’indirizzo  1010  in base 2, 

si puo’ scrivere il vero e proprio programma in linguaggio macchina,  poiche’  gli altri 

codici operativi dovrebbero essere noti,dalla tab. 3.2 della lezione 3.

  nota: abbiamo deciso arbitrariamente di usare tali codici operativi.

 

Programma in LM, che calcola il maggiore fra due numeri letti da Input:

 

                 Tab. 7.3

  Indirizzo     Cella

Codice operativo

Indirizzo operando

10

01010

1000

11001

11

01011

1000

11010

12

01100

0000

11001

13

01101

0001

11010

14

01110

0101

-------

15

01111

1111

10010

16

10000

1001

11001

17

10001

0111

11010

18

10010

1001

11010

19

10011

0110

-------

…….

……

……

25

11001

PRIMO

26

11010

SECONDO

 

 

Esercizio

 

Dati 3 numeri interi, stampare il massimo fra essi.

Scrivere il programma : in forma di algoritmica, di diagramma di flusso e 

corrispondente traduzione in linguaggio C.

 

Algoritmo

1)    Leggere  primo  ,  secondo  e  terzo  numero

2)    Se  primo  >  secondo

3)    Allora stampare il max tra primo e terzo

4)    Altrimenti stampare il max tra secondo e terzo

5)    Fine

 

Diagramma di flusso

 

Nel diagramma trascuriamo la lettura di primo , secondo , e terzo ; indichiamo per

comodita’ i tre simboli rispettivamente con  P , S , T .

 

 

Fig. 7.6

 

 

Programma espresso in linguaggio  C :

 

#include<stdio.h>

void main(void)

{        /* BEGIN */

  int P, S, T;            /*  commento: dichiarazione dei simboli ( variabili)  */

  scanf (“\n %d”,&P);    /*  lettura del primo numero intero da input       */

  scanf (“\n %d”,&S);    /*  lettura del secondo numero intero da input   */

  scanf (“\n %d”,&T);    /*  lettura del terzo numero intero da input        */    

     if ( P > S )

      {

         if ( P > T)

          printf (“\n Il numero max e’ =  %d ” , P );  /* stampa il primo numero */

        else

         printf ( “\n Il numero max e’ = %d ” , T  );  /* stampa il terzo numero */

      }

    else  /* le istruzioni successive vengono eseguite se P e’ minore od uguale ad S */

      if ( S > T )

      printf (“\n Il numero max e’ = %d ” , S );  /* stampa il secondo numero*/

     else

     printf (“\n Il numero max e’ = %d ” , T );  /* stampa il terzo numero */

/* STOP */

 }

 

 

 

Esercizio   (svolgere da soli)

 

Scrivere in linguaggio C un programma che stampi il Massimo fra 4 numeri

interi dati in Input.

(Invio Soluzione: tramite e-mail agli iscritti alla mailing list, solo dopo invio vostra soluzione)

 

Bozza di algoritmo da seguire

1)    Leggere i 4 numeri interi da input e memorizzarli  ( Servono 4 variabili P, S ,T, Q)

2)    Se P > S

a)    stampare il massimo tra P, T e Q .

b)    altrimenti stampare il massimo tra  S, T e Q

 

*   e’ un esercizio un po’ piu’ lungo di quello visto

*   sfruttare l’ esercizio precedente come sottocaso

 

raffinamento :

          a’)   se P > T allora stampare il massimo tra P e Q

          b’)   altrimenti stampare il massimo tra  T e Q

          b’’)  fatelo voi

          a”)  fatelo voi

          b’’)  fatelo voi .

 

 

Il concetto di variabile

 

Una variabile e’ una astrazione della cella (locazione) di memoria, ossia formalmente e’ :

 

un  simbolo , cioe’ un identificatore ( nome ) associato ad un indirizzo fisico della 

memoria, che denota un valore contenuto nella locazione stessa;

(locazioni di memoria che possono essere di 1 byte, 2 byte, 4 byte ..).

 

Se chiamiamo L-Valore l’ indirizzo fisico della memoria e chiamiamo R-VALORE il

valore della variabile contenuto nella locazione di memoria, avremo che l’ R-VALORE

puo’ cambiare nel corso dell’ esecuzione di un programma mentre L-VALORE e’ 

fissato e certamente non cambia durante l’esecuzione.

Cerchiamo di chiarire meglio quanto detto.

Esempio

La dichiarazione di variabile intera seguente:

int   somma ;

avvisa “il sistema di programmazione” che sara’ necessario

-        Riservare una locazione di memoria (in L-VALORE)

-        Capace di contenere un numero intero di ( 16 , 32 ,… bit )

-        Associata al nome  somma

 e che nel programma sara’ possibile

-        Accedere al valore in essa contenuto (R-VALORE), scrivendo  somma

-        Memorizzare un valore (intero) in essa usando il nome  somma .

  Tab. 7.4

Identificatore

Indirizzo

somma

00110111

 

L’indirizzo della tabella 7.4 e’ L-VALORE che e’ invariante per il simbolo somma

 

Tab. 7.5  variabile somma di valore attualmente 1968 memorizzata nella cella di 

memoria di L-VALORE = 00110111

 

Indirizzo

R-VALORE

………….

        …..

………….

        .….

00110111

      1968

…………

       ……

………….

       ……

 

E’ diverso scrivere

int   somma;

float  somma;

Abbiamo dato la dichiarazione di due variabili aventi lo stesso nome, ma nel primo

caso la cella verra’ usata per operazioni in aritmetica intera, mentre nel secondo caso 

per operazioni in aritmetica reale o meglio floating point;

in sostanza con la frase definizione di una variabile, si intende che si introduce una 

variabile, identificata da un simbolo (nome) e contemporaneamente ne specifichiamo 

il tipo ( intero ,reale..).

 

esempio

int a, b, c, somma; /* dichiarazione di 4 variabili di tipo intero */

float d, e, re; /* dichiarazione di 3 variabili di tipo float (dati reali)*/

char car;      /* dichiarazione di una variabile car di tipo carattere */

 

Cenni su istruzioni della parte esecutiva

 

Sono di tre tipi, istruzioni di:

 

-        LETTURA/SCRITTURA :

     scanf(“%d”,&somma); scanf(“\n%d”,&somma);

     printf(“%d”, somma); printf(“\n%d”,somma);   

%d indica che somma e’ un intero;  \n indica prossima linea.

-        ASSEGNAZIONE

operatore   =

Somma = 30;  /* assegna alla variabile somma il valore intero 30 */

-        CONTROLLO

a)    istruzione composta :

gruppi di istruzioni da eseguire in sequenza in un medesimo contesto contenute fra le parentesi graffe { istr1; istr2;…  } 

b)    istruzione condizionale  :   if-else

 

c)     istruzione iterativa: for( ); while (); do - while()


 

Test 7