Per inizializzare un array di caratteri, oltre ad utilizzare una funzione che genera caratteri di valore arbitrario, è possibile utilizzare la funzione getchar() ed il modo in cui essa gestisce il buffer di input standard (ovvero stdin).
In particolare, visto che il buffer di input può essere riempito un numero arbitrario di caratteri, noi possiamo utilizzare tali caratteri per inizializzare tutti gli elementi di un array (facendo naturalmente attenzione a non superare, all'atto dell'inizializzazione, le dimensioni dell'array). Per memorizzarne il valore, infatti, sarà sufficiente effettuare chiamate alla funzione getchar() fino a quando non si trovi il carattere dal codice ASCII pari a 10 (LF)
Il programma dovrà contenere:
(1) una parte in cui l'input dell'utente venga memorizzato in modo corretto (proveniendo dalla tastiera, il canale attraverso il quale i caratteri giungono al programma è lo standard input, stdin)
(2) una parte in cui tale input venga visualizzato
(3) una parte in cui l'input venga analizzato e, dopo l'analisi, visualizzato sul monitor
// inizio codice
#include <stdio.h>
#define MAX 40
int main()
{char messaggio[MAX];
char temp;
int i = 0;
printf("\nInserisci un messaggio formato da non piu' di %d elementi",MAX);
printf("\nLa lunghezza del messaggio non deve superare l'ultimo asterisco \n");
for(i=0;i<MAX; i++)
printf('*');
printf('\n');
i = 0; // questo contatore mi serve per controllare che il numero di caratteri non superi il limite MAX
while(1)
{temp=getchar();
if(temp == 10) break; // per terminare quando incontro il LF
if(i == MAX) break; // per terminare nel caso il messaggio superi la dimensione dell'array
messaggio[i] = temp; // inserisco il carattere nell'array
i++;}
// nel caso il messaggio sia composto da un numero di caratteri inferiore alla dimensione dell'array
if( i != MAX )
{for( i ; i < MAX ; i++ )
messaggio[i] = ' ' ; // inizializzo l'elemento dell'array con il carattere spazio
}
/* A questo punto il messaggio inserito dall'utente è stato memorizzato. Per visualizzarne il contenuto possiamo effettuare un ciclo e stampare una prima volta il messaggio originale ed una seconda volta il messaggio invertendo l'altezza delle lettere. */
putchar('\n');
putchar('\n');
// stampo il messaggio originale
for(i = 0; i < MAX ; i++)
{putchar(messaggio[i]);}
// stampo il messaggio invertendo l'altezza delle lettere
putchar('\n');
putchar('\n');
for(i = 0; i < MAX ; i++)
{
if((messaggio[i] >= 'a') && (messaggio[i] <= 'z')) // minuscola
putchar( messaggio[i] - 32 );
else if((messaggio[i] >= 'A') && (messaggio[i] <= 'Z')) // maiuscola
putchar( messaggio[i] + 32 );
else
putchar(messaggio[i]);
}
return 0;}
// fine codice
L'output sarà di questo tipo:
Inserisci un messaggio formato da non piu' di 40 elementi
La lunghezza del messaggio non deve superare l'ultimo asterisco
***************************************
Prova di Inserimento Messaggio !
Prova di Inserimento Messaggio !
pROVA DI iNSERIMENTO mESSAGGIO !
|
Come possiamo implementare la medesima procedura in modo tale che la dimensione dell'array, che deve essere stabilita in fase di compilazione, possa essere modificata SENZA modificare il file sorgente ?
Ricorriamo al preprocessore e, sfruttando il fatto che la MACRO può essere definita direttamente dalla linea di comando, scegliamo di volta in volta, al momento della compilazione, la lunghezza massima del vettore. In futuro, grazie ai puntatori, vedremo come ottenere lo stesso risultato in fase di esecuzione.
A questo scopo è sufficiente eliminare la direttiva #define dal codice
// inizio codice
#include <stdio.h>
#define MAX 40
int main()
{char messaggio[MAX];
char temp;
...
// fine codice
ed utilizzare il seguente comando per effettuare la compilazione:
gcc -Wall -o messaggio -DMAX=50 miofile.c
inserire l'opzione -DMAX=50 nella mascherina in cui è stata inserita l'opzione -Wall
Quale metodo usava Cesare per comunicare con i suoi generali in modo tale da non far comprendere il messaggio ad eventuali nemici che fossero venuti in possesso delle lettere che egli spediva loro ?
Innanzitutto scriveva il messaggio "originale" e poi sostituiva ogni lettera con quella che, nell'alfabeto, si trova 3 posizioni più avanti (in realtà il numero, ovvero lo shift in avanti, non era sempre pari a 3). In questo modo alla a faceva corrispondere la d, alla m la lettera p e via così. Questo metodo, però, non è molto sicuro in quanto le frequenze con cui le lettere si presentano all'interno delle parole di uso quotidiano permettono di ricavare delle informazioni sul valore dello shift.
Costruiamo una funzione simile, garantendoci però la possibilità di scegliere in modo arbitrario il numero di posizioni da saltare per passare da una lettera all'altra. Tale funzione verrà utilizzata anche in seguito; la inseriremo quindi nel file myfun.h assieme alle altre.
// inizio codice
/*
la variabile originale rappresenta il carattere da cifrare mentre shift rappresenta il numero di posizioni da saltare per passare dal carattere originale a quello cifrato
Nell'implementare la funzione devo fare alcune ipotesi:
a) non verranno inseriti caratteri di controllo
b) i caratteri, una volta cifrati, non dovranno venir trasformati in caratteri di controllo
*/
int cifratura(int,int);
// perché le variabili sono state dichiarate di tipo int se la funzione gestisce solo char ?
int cifratura(int originale,int shift)
{originale = 32 + (originale + shift) % (255 - 32 + 1);
return originale ;}
// fine codice
A cosa serve l'operatore modulo ? A far diventare la sequenza (ovvero la tabella di codici ASCII)
!"#$ ... ABCD ... 123 ... defg ... {|}~ ... ·¹²■
un oggetto simile ad un anello
Ora possiamo riprendere il programma di prima e
cercare di effettuare la cifratura dei caratteri inseriti dall'utente.
NOTA: per scegliere lo shift ci affidiamo al fatto che la funzione rand(), una volta fissato il primo elemento della serie di numeri casuali grazie ad srand(), fornisce sempre la medesima sequenza di numeri. Pertanto ci possiamo permettere di variare lo shift ad ogni cifratura, tanto la sequenza degli shift è fissata e può essere riprodotta in un secondo momento per decodificare il codice.
// la macro
MAX deve essere definita al momento della compilazione del codice
#include <stdio.h>
#include <stdlib.h>
#include "myfun.h"
int main()
{char messaggio[
MAX];
char cifrato[MAX]; // il vettore che conterrà il messaggio cifrato
int shift = 0;
char chiave;
char temp;
int i = 0;
printf("\nInserisci un messaggio formato da non piu' di %d elementi",
MAX);
printf("\nLa lunghezza del messaggio non deve superare l'ultimo asterisco \n");
for(i=0;i<
MAX; i++)
printf('*');
printf('\n');
i = 0;
while(1)
{temp=getchar();
if(
temp == 10)
break;
if(
i == MAX)
break;
messaggio[i] = temp;
i++;}
if( i !=
MAX )
{for( i ; i <
MAX ; i++ )
messaggio[i] = ' ' ;
}
/* A questo punto il messaggio inserito dall'utente è stato memorizzato. Per visualizzarne il contenuto possiamo effettuare un ciclo e stampare una prima volta il messaggio originale ed una seconda volta il messaggio invertendo l'altezza delle lettere. */
putchar("\n");
putchar("\n");
// stampo il
messaggio originale
for(i = 0; i <
MAX ; i++)
{putchar(messaggio[i]);}
// stampo il messaggio invertendo l'altezza delle lettere
putchar("\n");
putchar("\n");
for(i = 0; i <
MAX ; i++)
{
if(
(messaggio[i] >= 'a') && (messaggio[i] <= 'z')) // minuscola
putchar( messaggio[i] - 32 );
else if(
(messaggio[i] >= 'A') && (messaggio[i] <= 'Z')) // maiuscola
putchar( messaggio[i] + 32 );
else
putchar(messaggio[i]);
}
chiave = 200;
srand( chiave ); // inizializzo il generatore di numeri casuali
for( i = 0 ; i <
MAX ; i++)
{
shift = rand() % 20 ; // prevedo shift non superiori alle 20 unità
cifrato[i] = cifratura(messaggio[i],
shift);
// ora stampo il messaggio cifrato e la chiave per decodificarlo
printf("\n%c\n",chiave);
for( i = 0; i < MAX ; i++)
{printf("%c",cifrato[i]); }
return 0;}
// fine codice