Linguaggio C – base Tipi di dati MCD(n1, n2) = MCD(n1-n2, n2) se n1>n2 la seconda proprietà...

Post on 25-Jul-2020

10 views 0 download

Transcript of Linguaggio C – base Tipi di dati MCD(n1, n2) = MCD(n1-n2, n2) se n1>n2 la seconda proprietà...

Esercitazione n. 3Esercitazione n. 3

Linguaggio C – baseLinguaggio C – baseTipi di datiTipi di dati

Queste slide sono distribuite con licenza Creative Commons Attribuzione-Non commerciale-Condividi allo stesso modo 2.5 Italia

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 2

Linguaggio C: Ripasso...

Fare riferimento alle dispense del docente...

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 3

C/1: Resto divisione tra interi – Codice sorgente/1

/* Il programma calcola il resto di una divisione fra numeri interi.

Input: dividendo e divisore Output: valore del resto */

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 4

C/1: Resto divisione tra interi – Codice sorgente/2

#include <stdio.h>

main(){ int dividendo, divisore, resto;

printf ("Dividendo: "); scanf ("%d", &dividendo); printf ("Divisore: "); scanf ("%d", &divisore);

resto = dividendo - (dividendo / divisore) * divisore;

/* il simbolo '/', nel caso di divisione tra variabili di tipo 'int', rappresenta la divisione INTERA (per cui, per esempio, se 'dividendo' contiene il valore 9, e 'divisore' il valore 2, il risultato della divisione intera è 4. Vedremo che nel caso di variabili 'float' il simbolo '/' rappresenta la divisione tra reali. */

printf ("Resto: %d\n", resto);}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 5

C/1: Resto divisione tra interi – Codice eseguibile

Come si rende eseguibile un programma C a partire dal codice sorgente?

1. Stesura del codice sorgente2. Compilazione3. Esecuzione

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 6

C/2: Verifica terna pitagorica – Codice sorgente/1

/* Verifica se una terna di numeri è pitagorica (o, meglio, se i tre numeri in input corrispondono ai cateti e all'ipotenusa di un triangolo rettangolo).

Input: valori dei cateti e dell'ipotenusa Output: messaggio che indica se la terna è pitagorica o no */

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 7

C/2: Verifica terna pitagorica – Codice sorgente/2

#include <stdio.h>

main(){ int c1, c2, ip;

printf ("Misura del primo cateto: "); scanf ("%d", &c1); printf ("Misura del secondo cateto: "); scanf ("%d", &c2);

printf ("Misura dell'ipotenusa: "); scanf ("%d", &ip);

if (c1*c1+c2*c2 == ip*ip) { printf ("Il triangolo è rettangolo\n"); } else { printf ("I valori inseriti non corrispondono a un triangolo rettangolo\n"); }}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 8

C/3: Verifica equidistanza – Codice sorgente/1

/* Date le coordinate x e y di 3 punti, verificare se i punti 2 e 3 sono equidistanti dal punto 1 (quindi se i punti 2 e 3 si trovano su una circonferenza con centro nel punto 1). La verifica viene fatta controllando se i quadrati delle distanze 1-2 e 1-3 sono uguali.

Input: coordinate x ed y dei 3 punti Output: messaggio che indica se i punti sono equidistanti oppure no */

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 9

C/3: Verifica equidistanza – Codice sorgente/2

#include <stdio.h>

main(){ float x1, y1, x2, y2, x3, y3; float distq12, distq13;

printf ("Coordinata x del punto 1: "); scanf ("%f", &x1); printf ("Coordinata y del punto 1: "); scanf ("%f", &y1);

printf ("Coordinata x del punto 2: "); scanf ("%f", &x2); printf ("Coordinata y del punto 2: "); scanf ("%f", &y2);

printf ("Coordinata x del punto 3: "); scanf ("%f", &x3); printf ("Coordinata y del punto 3: "); scanf ("%f", &y3);

c'è l'esigenza di gestire numeri reali

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 10

C/3: Verifica equidistanza – Codice sorgente/3

distq12 = (x1-x2)*(x1-x2)+(y1-y2)*(y1-y2); distq13 = (x1-x3)*(x1-x3)+(y1-y3)*(y1-y3);

if (distq12 == distq13){ printf ("I punti 2 e 3 sono equidistanti da 1\n"); } else { printf ("I punti 2 e 3 NON sono equidistanti da 1\n"); }

/* In realtà con il problema che i float sono comunque approssimazioni finite dei numeri reali, è meglio usare, nella condizione dell'if, una verifica di appartenenza a un intervallo, invece che l'uguaglianza semplice. Una condizione migliore quindi è

if (distq12-distq13<TOL && distq12-distq13>-TOL)

dove TOL sarà una costante definita all'inizio del file come, per esempio

#define TOL 0.0001 */}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 11

C/4: Calcolo circonferenza – Codice sorgente/1

/* Dato il raggio di una circonferenza, calcolare il valore di circonferenza ed area.

Input: raggio Output: circonferenza ed area*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 12

C/4: Calcolo circonferenza – Codice sorgente/2#include <stdio.h>

main(){ const double pi = 3.141592;

/* La costante potrebbe anche essere dichiarata con una define: #define PI 3.141592 però le due cose sono diverse. Da una parte ho una cella di memoria (pi) che contiene un valore, che però è costante, per cui se tento di fare pi = 4; a runtime (NON ALLA COMPILAZIONE) ho un errore. Dall'altra invece viene semplicemente effettuata, IN FASE DI COMPILAZIONE, una sostituzione tra l'identificatore PI ed il valore 3.141592. PI NON corrisponde a una cella di memoria, per cui se tento di fare PI = 4 ho un errore IN FASE DI COMPILAZIONE.

(Nota: il fatto che abbia chiamato la cella di memoria costante con lettere minuscole (pi) ed invece l'identificatore usato nella define con lettere maiuscole è PURA CONVENZIONE, potevo fare l'inverso, o chiamarli entrambi alla stessa modo.) */

c'è l'esigenza di gestire numeri realiin doppia precisione

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 13

C/4: Calcolo circonferenza – Codice sorgente/3

double raggio, area, circonf;

printf ("Raggio della circonferenza: "); scanf ("%lf", &raggio);

circonf = 2*pi*raggio; area = pi*raggio*raggio;

printf ("Circonferenza: %lf\nArea: %lf\n", circonf, area);

}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 14

C/5: Calcolo potenza – Codice sorgente/1

/* Data una base ed un esponente, calcolare base elevato ad esponente. Sia la base che l'esponente sono valori interi.

Input: base, esponente (deve essere >0) Output: base elevato ad esponente*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 15

C/5: Calcolo potenza – Codice sorgente/2

#include <stdio.h>

main(){ int base, esp, i, ris;

printf ("Base: "); scanf ("%d", &base);

printf ("Esponente (>0): "); scanf ("%d", &esp);

if (esp < 0) { printf ("Errore: l'esponente deve essere > 0\n"); } else {

ris = 1; i = 0;

while (i < esp) { ris = ris * base; i = i+1; } printf ("Risultato base^esponente = %d\n", ris); }}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 16

C/5.1: Calcolo potenza (con for) – Codice sorgente/1

/* data una base ed un esponente, calcolare base elevato ad esponente. Sia la base che l'esponente sono valori interi.

Utilizzare la struttura di controllo “for”

Input: base, esponente (deve essere >0) Output: base elevato ad esponente*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 17

C/5.1: Calcolo potenza (con for) – Codice sorgente/2

/* A livello sintattico, il costrutto for è costituito da:

- la parola chiave for seguita da - un coppia di () comprendente tre espressioni separate dal carattere “;” (valore iniziale della variabile di conteggio, espressione booleana sulla variabile di conteggio, incremento della variabile di conteggio). Queste sono seguite da - una qualsiasi istruzione oppure una sequenza di istruzioni racchiuse tra {}*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 18

C/5.1: Calcolo potenza (con for) – Codice sorgente/3

#include <stdio.h>

main(){ int base, esp, i, ris;

printf ("Base: "); scanf ("%d", &base);

printf ("Esponente (>0): "); scanf ("%d", &esp);

if (esp < 0){ printf ("Errore: l'esponente deve essere > 0\n"); } else {

ris = 1;

/* Con l'uso del ciclo for invece del ciclo while */

for (i=0; i<esp ; i=i+1){ ris = ris * base; }

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 19

C/5.1: Calcolo potenza (con for) – Codice sorgente/4

/* Altri modi per scrivere i=i+1: i+=1 i++ (il valore viene prima utilizzato e poi incrementato) ++i (il valore viene prima incrementato e poi utilizzato) Quindi attenzione perchè i++ e ++i NON SONO la stessa cosa! In questo caso avrebbero lo stesso effetto, ma in altri no! Per esempio, potrei scrivere la condizione del while (e quindi lo statement di mezzo del for) come

i++<esp

questo è corretto, mentre la scrittura

++i<esp

non lo è, crea confusione! Notate come scrivere

while(i++<esp){ ris*=base; }

sia in effetti molto più compatto di quanto scritto prima, ma, in compenso, sia già meno leggibile.

Altro modo per scrivere ris = ris * base: ris*=base

Notare come il C può essere compatto (e quindi illeggibile!) */

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 20

C/5.1: Calcolo potenza (con for) – Codice sorgente/5

/* Forma classica per scrivere quel ciclo for: for (i=0 ; i<esp ; i++){ ... }

Domanda: cosa fa il ciclo while (); ??????

E il ciclo for (;;); ?????? */

printf ("Risultato base^esponente = %d\n", ris); }}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 21

C/6: Calcolo MCD con Euclide – Codice sorgente/1

/* Il programma calcola il massimo comun divisore tra due numeri n1 e n2, usando l'algoritmo di Euclide.

Il principio di funzionamento dell'algoritmo è il seguente: MCD(n1, n2) = n1 (o n2) se n1 = n2 MCD(n1, n2) = MCD(n1-n2, n2) se n1>n2

la seconda proprietà discende da ciò: 1) se n1 > n2 e k è un divisore comune a n1 ed n2, allora k è anche un divisore di n1-n2. Infatti esistono degli interi positivi d ed r per cui n1=k*d e n2=k*r. Dunque n1-n2=k(d-r) con d-r>0 2) si può dimostrare che se k è divisore comune a n1-n2 e n2, k è anche divisore di n1 3) dunque tutti i divisori comuni di n1 e n2 coincidono con i divisori comuni di n1-n2 e n2; quindi anche i massimi divisori comuni tra le due coppie di numeri coincidono

Input: numeri di cui calcolare il MCD Output: MCD dei numeri*/

Nota: risolvere in autonomia

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 22

C/6: Calcolo MCD con Euclide – Codice sorgente/2

#include <stdio.h>

main(){ unsigned int n1, n2;

printf ("Inserire il primo numero positivo: "); scanf ("%u", &n1);

printf ("Inserire il secondo numero positivo: "); scanf ("%u", &n2);

while (n1 != n2){ if (n1>n2){ n1 = n1 - n2; } else { n2 = n2 - n1; } }

printf ("Il massimo comun divisore e': %u\n", n1);}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 23

C/7: Calcolo massimo di una sequenza – Codice sorgente/1

/* Data una sequenza di interi positivi, terminata dal valore 0, calcolare il massimo della sequenza.

Input: sequenza di interi positivi Output: massimo della sequenza*/

Nota: risolvere in autonomia

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 24

C/7: Calcolo massimo di una sequenza – Codice sorgente/2

#include <stdio.h>

main(){ unsigned int curr, max = 0;

printf ("Inserire il prossimo numero positivo (0 per terminare): "); scanf ("%u", &curr);

while (curr != 0) { if (curr > max){ max = curr; }

printf ("Inserire il prossimo numero positivo (0 per terminare): "); scanf ("%u", &curr);

}

printf ("Il numero massimo inserito e': %u\n", max); }

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 25

C/7.1: Calcolo massimo di una sequenza (do ... while) – Codice sorgente/1

/* Data una sequenza di interi positivi, terminata dal valore 0, calcolare il massimo della sequenza.

Utilizzare la struttura di controllo “do ... while”

Input: sequenza di interi positivi Output: massimo della sequenza*/

Nota: risolvere in autonomia

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 26

C/7.1: Calcolo massimo di una sequenza (do ... while) – Codice sorgente/2

/* La sintassi della struttura di controllo do ... while è la seguente:

- la parola chiave do, seguita da - una qualsiasi istruzione oppure una sequenza di istruzioni racchiuse tra {}, seguita da - la parola chiave while seguita dall'espressione di verifica della condizione di uscita dal ciclo, racchiusa tra ()

Nota: a differenza di while e for, il ciclo interno viene eseguito almeno una volta*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 27

C/7.1: Calcolo massimo di una sequenza (do ... while) – Codice sorgente/3

#include <stdio.h>

main(){ unsigned int curr, max = 0;

/* Questa è una versione più compatta del programma precedente. Poiché il ciclo di lettura DEVE essere eseguito almeno una volta, si può usare, invece del ciclo 'while' classico, la versione

seguente: do ... while */

do {

printf ("Inserire il prossimo numero positivo (0 per terminare): "); scanf ("%u", &curr);

if (curr > max){ max = curr; }

} while (curr != 0);

printf ("Il numero massimo inserito e': %u\n", max); }

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 28

C/7.2: Calcolo massimo di una sequenza (anche numeri negativi) – Codice sorgente/1

/* Data una sequenza di interi (anche negativi), terminata dal valore 0, calcola il massimo della sequenza.

Input: sequenza di interi (anche negativi) Output: massimo della sequenza*/

Nota: risolvere in autonomia

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 29

C/7.2: Calcolo massimo di una sequenza (anche numeri negativi) – Codice sorgente/2

#include <stdio.h>#include <limits.h>

main(){ int curr, max = INT_MIN;

/* In questo caso si sfrutta il fatto che gli int abbiano un limite inferiore per inizializzare la variabile 'max', quindi si possono utilizzare gli interi invece degli unsigned. Notare che se il primo numero che viene inserito è lo 0 allora viene stampato il valore di INT_MIN. */

printf ("Inserire il prossimo numero (0 per terminare): "); scanf ("%d", &curr);

while (curr != 0) { if (curr > max) { max = curr; }

printf ("Inserire il prossimo numero (0 per terminare): "); scanf ("%d", &curr); } printf ("Il numero massimo inserito è: %d\n", max); }

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 30

C (e altri linguaggi): Sicurezza /1

Se occorre costruire una recinzione di 100 metri con paletti di sostegno distanziati di 10 metri, quanti paletti sono necessari?

10?

11!

Tipico errore “off-by-one”

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 31

C (e altri linguaggi): Sicurezza /2

Nel marzo del 2002 il cosiddetto “OpenSSH Channel Code Off by One Privilege Escalation” mette in serio pericolo i server connessi in rete che utilizzano OpenSSH (dalla versione 2.0 alla versione 3.0.2) permettendo a qualsiasi utente remoto di essere autenticato come amministratore.

Il codice includeva la seguente istruzione:

if (id < 0 || id > channels_alloc)

che avrebbe dovuto essere:

if (id < 0 || id >= channels_alloc)

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 32

Tipi di dati del linguaggio C: Ripasso...

Sono già stati utilizzati alcuni tipi di dati del linguaggio C

➢ int (unsigned int): per rappresentare numeri interi➢ float: per rappresentare numeri reali➢ double: per rappresentare numeri reali in precisione

doppia

Introduciamo un nuovo tipo di dato semplice:

➢ char: per rappresentare i caratteri alfanumerici (lettere, numeri e una serie di simboli)

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 33

Nota: il codice ASCII

032 0x20 056 0x38 8 080 0x50 P 104 0x68 h 033 0x21 ! 057 0x39 9 081 0x51 Q 105 0x69 i 034 0x22 " 058 0x3a : 082 0x52 R 106 0x6a j 035 0x23 # 059 0x3b ; 083 0x53 S 107 0x6b k 036 0x24 $ 060 0x3c < 084 0x54 T 108 0x6c l 037 0x25 % 061 0x3d = 085 0x55 U 109 0x6d m 038 0x26 & 062 0x3e > 086 0x56 V 110 0x6e n 039 0x27 ' 063 0x3f ? 087 0x57 W 111 0x6f o 040 0x28 ( 064 0x40 @ 088 0x58 X 112 0x70 p 041 0x29 ) 065 0x41 A 089 0x59 Y 113 0x71 q 042 0x2a * 066 0x42 B 090 0x5a Z 114 0x72 r 043 0x2b + 067 0x43 C 091 0x5b [ 115 0x73 s 044 0x2c , 068 0x44 D 092 0x5c \ 116 0x74 t 045 0x2d - 069 0x45 E 093 0x5d ] 117 0x75 u 046 0x2e . 070 0x46 F 094 0x5e ^ 118 0x76 v 047 0x2f / 071 0x47 G 095 0x5f _ 119 0x77 w 048 0x30 0 072 0x48 H 096 0x60 ` 120 0x78 x 049 0x31 1 073 0x49 I 097 0x61 a 121 0x79 y 050 0x32 2 074 0x4a J 098 0x62 b 122 0x7a z 051 0x33 3 075 0x4b K 099 0x63 c 123 0x7b { 052 0x34 4 076 0x4c L 100 0x64 d 124 0x7c | 053 0x35 5 077 0x4d M 101 0x65 e 125 0x7d } 054 0x36 6 078 0x4e N 102 0x66 f 126 0x7e ~ 055 0x37 7 079 0x4f O 103 0x67 g

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 34

C/8: crittografia - Problema

Si vuole realizzare un programma che dato un carattere in ingresso, lo trasforma in un altro carattere, che si trova OFFSET posizioni più avanti nell'alfabeto (per esempio con OFFSET = 4, il carattere 'a' diventa 'e').

E' il cifrario di Cesare

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 35

C/8: crittografia – Codice sorgente/1

/* Dato un carattere in ingresso, lo trasforma in un altro carattere, che si trova OFFSET posizioni più avanti nell'alfabeto (per esempio con OFFSET = 4, il carattere 'a' diventa 'e'). L'alfabeto considerato è:

ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Per esempio, con OFFSET = 4, la lettera 'X' diventa 'b'.

La complessità del programma sta nel fatto che nella codifica ASCII le sequenze 'A'..'Z' e 'a'..'z' (viene prima la sequenza di caratteri maiuscoli) non sono consecutive, ma tra loro c'è un altro insieme di caratteri, per cui occorre spezzare il programma in 2 “if”.

Input: un carattere da convertire Output: il carattere convertito*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 36

C/8: crittografia – Codice sorgente/2

#include <stdio.h>#define OFFSET 4

main(){ char curr, new;

printf ("Inserisci il carattere alfabetico da convertire: "); scanf ("%c", &curr);

if (curr >= 'A' && curr <= 'Z') { new = curr + OFFSET; if (new > 'Z') { new = 'a' + (new - 'Z'-1); } printf ("Il nuovo carattere dopo la conversione è: %c\n", new); } else if (curr >= 'a' && curr <= 'z') { new = curr + OFFSET; if (new > 'z') { new = 'A' + (new - 'z'-1); } printf ("Il nuovo carattere dopo la conversione è: %c\n", new); } else { printf ("Non è stato immesso un carattere valido\n"); }}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 37

C/8.1: crittografia (do ... while) - Problema

Si vuole realizzare una variante al programma precedente in grado di continuare l'esecuzione dell'algoritmo finché vengono inseriti caratteri (la conversione viene comunque fatta un carattere alla volta).

L'uscita dal programma è prevista nel caso venga inserito un carattere al di fuori dell'alfabeto dei caratteri consentiti per la conversione.

Utilizzare la struttura di controllo “do ... while”.

Nota: esercizio da svolgere in aula

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 38

C/8.1: crittografia (do ... while) – Codice sorgente/1/* Dato un carattere in ingresso, lo trasforma in un altro carattere, che si trova OFFSET posizioni più avanti nell'alfabeto (per esempio con OFFSET = 4, il carattere 'a' diventa 'e').

A differenza del precedente, questa versione del programma si basa su un ciclo “do..while”, per cui è possibile inserire (uno alla volta) più caratteri da convertire. Per uscire dal ciclo è sufficiente digitare un carattere non alfabetico (per esempio '1', o '%', o anche lo spazio).

L'alfabeto considerato e': ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz

Per esempio, con OFFSET = 4, la lettera 'X' diventa 'b'.

La complessità del programma sta nel fatto che nella codifica ASCII le sequenze 'A'..'Z' e 'a'..'z' (viene prima la sequenza di caratteri maiuscoli) non sono consecutive, ma tra loro c'è un altro insieme di caratteri, per cui occorre spezzare il programma in 2 “if”.

Input: un sequenza di caratteri da convertire Output: i caratteri convertiti*/

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 39

C/8.1: crittografia (do ... while) – Codice sorgente/2

#include <stdio.h>

#define OFFSET 4

main(){ char curr, new;

do { printf ("Inserisci il carattere alfabetico da convertire: "); scanf ("%c%*c", &curr);

/* Perché il programma funzioni correttamente è cruciale il codice '%*c' nella stringa della scanf. La combinazione "%c%*c" obbliga la scanf a leggere 2 caratteri in input, di cui però solo il primo viene memorizzato (in questo caso nella variabile 'curr'), mentre il secondo (il carattere di 'a capo') viene eliminato. */

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 40

C/8.1: crittografia (do ... while) – Codice sorgente/3

if (curr >= 'A' && curr <= 'Z') { new = curr + OFFSET; if (new > 'Z') {

new = 'a' + (new - 'Z'-1); } printf ("Il nuovo carattere dopo la conversione è: %c\n", new); } else if (curr >= 'a' && curr <= 'z') { new = curr + OFFSET; if (new > 'z') {

new = 'A' + (new - 'z'-1); } printf ("Il nuovo carattere dopo la conversione è: %c\n", new); } } while ((curr >= 'A' && curr <= 'Z') || (curr >= 'a' && curr <= 'z'));

}

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 41

C – linguaggi in generale: considerazioni

La codifica dei caratteri riveste un ruolo fondamentale nelle applicazioni dell'informatica, soprattutto ora che Internet collega buona parte dei PC presenti nel mondo!

Es: http://www.cremona.polimi.it/%7etode/http://www.cremona.polimi.it/~tode/

Approfondimento: codifica UNICODE

Esercitazioni di Fondamenti di Informatica – Politecnico di Milano sede di Cremona – A.A. 2010/2011 – Carlo Todeschini – tode@cremona.polimi.it 42

C – linguaggi in generale: buona formattazione?

#include <ncurses.h>/*****************************************************/ int m[256 ] [ 256 ],a ,b ;;; ;;; WINDOW*w; char*l="" "\176qxl" "q" "q" "k" "w\xm" "x" "t" "j" "v" "u" "n" ,Q[ ]= "Z" "pt!ftd`" "qdc!`eu" "dq!$c!nnwf"/** *** */"t\040\t";c(int u , int v){ v?m [u] [v- 1] |=2,m[u][v-1] & 48?W][v-1 ] & 15]]):0:0;u?m[u -1][v]|=1 ,m[ u- 1][ v]& 48? W-1 ][v ]&15] ]):0:0;v< 255 ?m[ u][v+1]|=8,m[u][v+1]& 48? W][ v+1]&15]]):0 :0; u < 255 ?m[ u+1 ][v ]|=4,m[u+1][ v]&48?W+1][v]&15]]):0:0;W][ v]& 15] ]);}cu(char*q){ return *q ?cu (q+ 1)& 1?q [0] ++:q[0 ]-- :1; }d( int u , int/**/v, int/**/x, int y){ intY=y -v, X=x -u; int S,s ;Y< 0?Y =-Y ,s,s=- 1:( s=1);X<0?X=-X,S =-1 :(S= 1); Y<<= 1;X<<=1; if(X>Y){int f=Y -(X >>1 );; while(u!= x){f>= 0?v+=s,f-=X:0;u +=S ;f+= Y;m[u][v]|=32;mvwaddch(w,v ,u, m[u ][ v]& 64? 60: 46) ;if (m[ u][v]&16){c(u,v);; ;;; ;;; return;}} }else{int f=X -(Y>>1);; while (v !=y ){f >=0 ?u +=S, f-= Y:0 ;v +=s ;f+=X;m[u][v]|= 32;mvwaddch(w,v ,u,m[u][v]&64?60:46);if(m[u ][ v]& 16) {c( u,v ); ; return;;;}}}}Z( int/**/a, int b){ }e( int/**/y,int/**/ x){int i ; for (i= a;i <=a+S;i++)d(y,x,i,b),d(y,x,i,b+L);for(i=b;i<=b+L;i++)d(y,x,a,i),d(y,x,a+ S,i ); ;;; ;;; ;;; ;;; ; mvwaddch(w,x,y,64); ;;; ;;; ;;; prefresh( w,b,a,0,0 ,L- 1,S-1);} main( int V , char *C[ ] ){FILE*f= fopen(V==1?"arachnid.c"/**/ :C[ 1],"r");int/**/x,y,c,v=0 ;;; initscr (); Z(Z (raw () ,Z( curs_set(0),Z(1 ,noecho()))),keypad( stdscr,TRUE));w =newpad ( 300, 300 ) ; for (x= 255 ; x >=0 ;x-- ) for (y= 255 ;y>=0;y-- )m[ x][ y]= 0;x=y=0;refresh( );while ( (c= fgetc (f) )+1) {if(0||c==10|| x== 256){x=0;y++;if(y==256 )break;;} else{m[x][y]=(c =='~' ?64 : c ==32 ?0: 16) ;;x ++; }}for(x=0 ;x< 256;x++)m [x][0]=16 ,m[ x][ 255]=16;for(y=0;y< 256 ; y ++) m[0 ][y ] = 16,m[255][y] =16 ;a=b=c=0; x=y =1; do{v++;mvwaddch (w, y,x ,m[x][ y]& 32? m[x ][y ] & 16? 0| acs_map[l[m[x][y]&15]]:46 : 32);c==0163&&!(m[x][y+1]&16)?y++: 0;c == 119 &&! (m[ x][ y- 1]& 16) ?y--:0;;c ==97 &&!(m[x-1][y]&16)?x--:0;c==100&&!(m[x+1 ][ y]& 16) ? x ++:0 ;if( c== 3- 1+1 ){endwin( );; return(0) ;}x -a<5?a>S- 5?a-=S-5:(a=0):0;x -a> S-5?a<255 -S* 2?a +=S-5:(a=256-S):0; y-b<5?b>L-5?b-=L-5:(b =0) :0; y-b>L-5?b<255-L *2?b+= L-5 :(b =256-L) :0;e(x,y);if(m[x][y]&64)break;}while((c=getch())!=-1);endwin();cu(Q);printf(Q,v);}

Che cosa è?

arachnidhttp://www.de.ioccc.org/years.html#2004

The International Obfuscated C Code Contest