Total Hack Cheat
Benvenuto/a su Total hack Cheat....
non aspettate altro tempo Registratevi!!

Parte 1 (2) Guida linguaggio C

Vedere l'argomento precedente Vedere l'argomento seguente Andare in basso

Parte 1 (2) Guida linguaggio C

Messaggio Da RaYoZ il Gio Mag 20, 2010 12:43 pm

La scelta.

La scelta permette di valutare un' espressione logica e di eseguire un' istruzione o un' altra in base al risultato ottenuto e quindi di rompere la sequenzialita' di un flusso.
Si rappresenta con un rombo con un punto di ingresso e due d'uscita associati alle condizioni di vero o di falso.
In notazione A :

se condizione A allora istruzione1 altrimenti istruzione2
oppure

se condizione A allora istruzione

Nella costruzione delle espressioni da valutare vengono utilizzati anche, oltre agli operatori relazionali, gli operatori di AND , OR e NOT logico intesi come congiunzione, disgiunzione e negazione.
In C si utilizzano '&&' per rappresentare AND e '||' per OR.
Attenzione a non confonderli con '&' e '|' che hanno sempre il valore di AND e OR ma intesi come operazioni sui bit.
Per il NOT viene invece utilizzato il '!'.
Ad esempio in C '!=' ha significato di 'non uguale'.
Una condizione :

se non espressione allora .....

o anche :

se !espressione allora .....

in C :

if (!espressione) { ..... }



Un altro esempio :

se espressione1 || espressione2 allora .... /*se espr1 o espr2*/
/*sono veri ......*/

in C:

if (espressione1 || espressione2) { ..... }

Nella costruzione delle espressioni portate attenzione ai diversi significati degli operatori '=' e '=='.
Il primo rappresenta un' assegnazione mentre il secondo un confronto.
Ad esempio :

/* Errata in C */ if (a = b) { ..... }

tenderebbe ad assegnare b ad a.
Prestate attenzione in quanto il compilatore non vi segnalerebbe nessun errore in quanto avverrebbe un assegnazione ma non il controllo di a == b.
L'espressione corretta :

if (a == b) { ..... }

Esistono scelte a piu' rami che non considerano solo i casi associati allo stato di vero o di falso.
In notazione A questa condizione viene chiamata 'nel caso che'.
Un esempio :

nel caso che:

cond.1 : istruzione
cond.2 : istruzione
...... . ..........

cond.n : istruzione


Supponiamo di voler codificare un programma che dati degli input valuti quante volte sono premuti i caratteri m,n e o :


inizio
var b :char;var m,n,o :interi;
n <- m <- o <- 0;
finche' b != EOF ripetere | leggi b;
| nel caso che :
| caso b == 'n':n <- n+1;
| caso b == 'm':m <- m+1;
| caso b == 'o'Surprised <- o+1;
| scrivi n,m,o;
fine


Il relativo diagramma di flusso sarebbe :


+------------+
| leggi b |-------------------+
+------------+ |
| |
/ \
si/ \no
=EOF?
\ /

\ /
+---------+
| END | +-------------------------+
+---------+ |==n |==m |==o |def

+-------------------------+

+------+
|n=n+1 +------+
+------+ m=m+1 +------+
+------+ o=o+1
+------+
+---------+---------+---------------+
|
+------------+
|scrivi n,m,o |
+------------+




(NOTA)


Sui diagrammi di flusso esistono varie correnti. Alcuni a livello didattico li consigliano mentre altri sono piu' propensi allo sviluppo dell'analisi mediante uno pseudo linguaggio tipo la notazione algebrica.
Sinceramente io sono piu' propenso al secondo caso. A livello di nota si puo' anche dire che un analisi di questo tipo e' adatta a problematiche abbastanza semplici.
L'ingegneria del software ha sviluppato negli ultimi anni metodologie d'analisi per problemi molto complessi che contemplano lo sviluppo mediante varie fasi.
In genere se il problema risulta essere particolarmente difficile da rapportare al sistema su cui dovra' girare si utilizza un metodo definito a raffinazioni successive in cui le prime fasi vengono proiettate su una "macchina virtuale" che possiede poche delle caratteristiche della macchina reale. Mediante fasi successive si esegue il passaggio tra questa e la
macchina reale.
In ogni caso per coloro interessati al problema dell' ingegneria del software consiglio il volume edito dalla Franco Angeli intitolato "Ingegneria del software e metodologie d'analisi".


Riprendendo il discorso relativo all'esempio precedente in linguaggio C risultera':


#define EOF -1 /* Definisce EOF = -1 */
main() /* Dichiarazione funzione*/

{

int n,m,o; /* Dichiara n,m,o interi */
char c; /* Dichiara c carattere */
o = n = m = 0; /* Assegna 0 a o,n,m */

while ((c = getchar()) != EOF) /* Ripeti c != -1 */
{

switch(c) { /* Passa c ai case per il controllo */
case 'm':m += 1;break; /* Se 'm' m = m+1 */
case 'n':n += 1;break; /* Se 'n' n = n+1 */
case 'o'Surprised += 1;break; /* Se 'o' 0 = o+1 */
default:break; /* Se no esci */
}

printf("%d m, %d n e %d o",m,n,o);
}

exit(0); /* Se EOF esci */
}



Alcune note che compariranno nei seguenti capitoli non sono solo relative a sintassi particolari della notazione algebrica, ma bensi derivanti da forme del C.
L'abitudine all'uso di queste facilitera' non solo l' apprendimento della sintassi C ma facilitera' la stesura degli algoritmi in notazione A.
Si sara' notato l'uso dell'espressione n += 1.
In C, ma puo' essere utilizzato vantaggiosamente anche in analisi, questa ha il significato di :

n = n + 1

La sintassi di questa e' :

espres1 oper= espres2

che e' equivalente a :

espres1 = (espres1) oper (espres2)

quindi

x *= y + 1

sarebbe

x = x * ( y + 1 )

L'espressione n = m = o = 0 esegue un assegnamento da destra a
sinistra, quindi sarebbe come scrivere n = ( m = ( o = 0 ) ).

** Esempio

Allo scopo di provare a mettere in pratica quello fino a qui detto, codificheremo in notazione A un programma che dati degli input conti quanti caratteri, spazi, ritorni a capo e cifre sono stati inseriti visualizzando i risultati quando questi sono finiti.
E' molto simile all' esempio precedente.

procedura CONTA

var car :char;
var ncar,nnum,ncr,nbia:intero;
nmum <- ncar <- ncr <- nbia <- 0;

inizio CONTA
inizio loop

ripeti fino a che car != EOF | leggi car
| nel caso che:
| caso '0':
| caso '1':
| caso '2':
| caso '3':
| caso '4':
| caso '5':
| caso '6':
| caso '7':
| caso '8':
| caso '9':
| nnum += 1;
| caso ' ':
| nbia += 1;
| caso \n :
| ncr += 1;
| caso default:
| ncar += 1;
fine loop

scrivi nnum,nbia,ncr,ncar;

fine CONTA


** Esempio

Codifichiamo ora in notazione A un programma che debba contare le
linee, le parole e i caratteri in input.
Non utilizzare come nell'esempio precedente 'nel caso che' ma creare dei nodi decisionali mediante i soli 'if'.

var SI,NO :booleano;
SI <- 1;NO <- 0;

inizio CONTA2
var c,nlinee,nparole,ncaratteri,inparola:intero;
inparola <- NO;
nlinee <- nparole <- ncaratteri <- 0;

ripeti fino a
inizio loop;
che c != EOF | leggi c; ncaratteri += 1;
| se c == '\n' nlinee += 1;
| se c == ' ' || == '\n' || == 't'
| esegui inparola <- NO;
| se no
| se inparola == NO
| esegui
| inizio
| inparola <- SI;
| nparole += 1;
| fine
fine loop

scrivi nlinee, ncaratteri, nparole;

fine CONTA



L'iterazione.

Spesso esiste la necessita' di ripetere un' istruzione o un gruppo di istruzioni per un numero di volte non necessariamente noto prima dell'esecuzione.Questo e' il concetto di iterazione.
Esistono due forme di iterazione :

finche' condizione C ripetere istruzione E
e
ripetere istruzione E fino a condizione C

Nel primo caso la condizione viene testata inizialmente prima di
eseguire l'istruzione E .
Nel secondo caso prima viene eseguita l'istruzione E e poi testata la condizione.



In C sarebbe :

while (condizione) { ..... }
e
do { ..... } while (condizione)

Un altro tipo di iterazione e' quella 'per' (for).
Si tratta di una ripetizione gestita da un contatore.

Ripetere istruzioni per var_1 che varia da NUM1 a NUM2 con passo
INCREMENTO o DECREMENTO.

La codifica in C sarebbe :

int inc;
for (inc = 1; inc != 30; inc += 1)

oppure

for (inc = 1;inc != 30;inc++)

Negli esempi precedenti abbiamo utilizzato n += 1 per rappresentare l'espressione n = n + 1.
Questo non era necessario in quanto il C permette l'utilizzo di n++ per indicare la stessa espressione.
Allo stesso modo l'operatore di decremento e' '--'.
Bisogna prestare attenzione al posizionamento degli operatori per evitare casi come il seguente.

Intendendo eseguire

var a,b :interi; int a,b;
b <- 1; b = 1;
a <- b ;b <- b+1; a = b++;
scrivi a; printf("%d",a);

il risultato sarebbe la stampa del numero 1, quello assegnato inizialmente a b.
Se si fosse scritto invece :

var a,b: interi; int a,b;
b <- 1; b = 1;
b <- b + 1;a <- b; a = ++b;
scrivi a; printf("%d",a);


si sarebbe ottenuto la visualizzazione del numero 2. Questo avviene semplicemente perche' la variabile b subisce l'incremento prima dell'assegnazione ad a.
Mi sono dimenticato di dire che la forma var += x e' valida per
qualsiasi operatore ammesso dal linguaggio C.
Ad esempio var &= 3 sarebbe come dire var = var & 3.


Sempre allo scopo di rapportare la sintassi C alla notazione A accennero' al concetto di puntatori anche se verra' dato ampio spazio a questi nella parte relativa al linguaggio vero e proprio.
Possiamo dire che un puntatore e' una variabile che contiene l'indirizzo di un'altra.
L'operatore unario & restituisce l'indirizzo di un oggetto.

punt_x = &x;

assegnera' a punt_x l'indirizzo di x.
In questo caso potremo dire che punt_x punta al valore di x.

y = *punt_x;

sarebbe come scrivere

y = x;




Analisi discendente e ascendente.

Tra il problema da risolvere e un programma il collegamento e' un
algoritmo espresso ad esempio in notazione algebrica.
La fase piu' difficile della programmazione non e' la traduzione di questo in un qualsiasi linguaggio ma la sua concezione.Questa fase viene definita come analisi. Molte tecniche analitiche sono state indirizzate al problem
solving, ma essenzialmente possiamo parlare di analisi con metodo
ascendente e analisi con metodo discendente.
Uno parte dai livelli piu' bassi per arrivare a quelli piu' alti dei problemi da risolvere, mentre l'altro parte dal livello piu' alto (problema da risolvere) per arrivare a quelli piu' bassi.
Il primo metodo permette di scoprire una strategia generale qualora questa non sia chiara dall'inizio.
Difatti la strategia bottom-up costruisce l'algoritmo risolutivo individuando inizialmente un insieme di passi o funzionalita' elementari e successivamente componendo tali funzionalita' in frammenti piu' grossi fino all' individuazione dell'intero algoritmo.
Questa tecnica e' tipicamente molto utile ogni volta che in virtu' della complessita' del problema, si voglia cominciare a fissare qualche aspetto dell'algoritmo .
Il secondo invece risulta piu' valido nel caso si abbia un' idea chiara fin dall'inizio della strategia da seguire.
La strategia top-down propone di decomporre iterativamente il problema in sottoproblemi proseguendo nella decomposizione fino a quando ogni singolo sottoproblema e' cosi' semplice che puo' essere espresso in notazione A o in qualsiasi linguaggio programmativo.



Questa tecnica permette di concentrarsi con gli aspetti del progetto che sono significativi in quel momento rimandando a passi successivi gli aspetti di maggior dettaglio.
Teoricamente e' possibile fare queste due distinzioni anche se poi praticamente esistono situazioni in cui le tecniche si mescolano.

Difatti spesso e volentieri l'ottimale risulta essere un ibrido delle due tecniche.

RaYoZ
Admin
Admin

Messaggi : 1040
Punti : 2245
Data d'iscrizione : 03.04.10
Età : 22
Località : immerso nei pensieri

Tornare in alto Andare in basso

Vedere l'argomento precedente Vedere l'argomento seguente Tornare in alto

- Argomenti simili

 
Permesso di questo forum:
Non puoi rispondere agli argomenti in questo forum